fix: Remove unsafe ClearDirtyIssues() method (bd-b6xo)

Remove ClearDirtyIssues() which had a race condition that could lose
dirty issues if export failed partway through. All callers now use
ClearDirtyIssuesByID() which only clears specific exported issues.

- Remove from Storage interface
- Remove from SQLite and Memory implementations
- Update 6 test call sites to use ClearDirtyIssuesByID()

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-17 19:10:13 -08:00
parent a7bfb3a6cf
commit 5869adadf2
7 changed files with 12 additions and 34 deletions

View File

@@ -95,19 +95,6 @@ func (s *SQLiteStorage) GetDirtyIssueHash(ctx context.Context, issueID string) (
return hash.String, nil
}
// ClearDirtyIssues removes all entries from the dirty_issues table
// This should be called after a successful JSONL export
//
// WARNING: This has a race condition (bd-52). Use ClearDirtyIssuesByID instead
// to only clear specific issues that were actually exported.
func (s *SQLiteStorage) ClearDirtyIssues(ctx context.Context) error {
_, err := s.db.ExecContext(ctx, `DELETE FROM dirty_issues`)
if err != nil {
return fmt.Errorf("failed to clear dirty issues: %w", err)
}
return nil
}
// ClearDirtyIssuesByID removes specific issue IDs from the dirty_issues table
// This avoids race conditions by only clearing issues that were actually exported
func (s *SQLiteStorage) ClearDirtyIssuesByID(ctx context.Context, issueIDs []string) error {

View File

@@ -39,9 +39,9 @@ func TestMarkIssueDirty(t *testing.T) {
}
// Clear dirty issues
err = store.ClearDirtyIssues(ctx)
err = store.ClearDirtyIssuesByID(ctx, []string{issue.ID})
if err != nil {
t.Fatalf("ClearDirtyIssues failed: %v", err)
t.Fatalf("ClearDirtyIssuesByID failed: %v", err)
}
// Verify cleared
@@ -92,9 +92,9 @@ func TestMarkIssuesDirty(t *testing.T) {
}
// Clear all dirty issues
err := store.ClearDirtyIssues(ctx)
err := store.ClearDirtyIssuesByID(ctx, issueIDs)
if err != nil {
t.Fatalf("ClearDirtyIssues failed: %v", err)
t.Fatalf("ClearDirtyIssuesByID failed: %v", err)
}
// Mark multiple issues dirty at once

View File

@@ -212,9 +212,9 @@ func TestAddCommentMarksDirty(t *testing.T) {
}
// Clear dirty issues
err = store.ClearDirtyIssues(ctx)
err = store.ClearDirtyIssuesByID(ctx, []string{issue.ID})
if err != nil {
t.Fatalf("ClearDirtyIssues failed: %v", err)
t.Fatalf("ClearDirtyIssuesByID failed: %v", err)
}
// Add comment - should mark issue dirty

View File

@@ -351,9 +351,9 @@ func TestLabelMarksDirty(t *testing.T) {
}
// Clear dirty issues
err = store.ClearDirtyIssues(ctx)
err = store.ClearDirtyIssuesByID(ctx, []string{issue.ID})
if err != nil {
t.Fatalf("ClearDirtyIssues failed: %v", err)
t.Fatalf("ClearDirtyIssuesByID failed: %v", err)
}
// Add label - should mark issue dirty
@@ -372,9 +372,9 @@ func TestLabelMarksDirty(t *testing.T) {
}
// Clear dirty again
err = store.ClearDirtyIssues(ctx)
err = store.ClearDirtyIssuesByID(ctx, []string{issue.ID})
if err != nil {
t.Fatalf("ClearDirtyIssues failed: %v", err)
t.Fatalf("ClearDirtyIssuesByID failed: %v", err)
}
// Remove label - should mark issue dirty