fix(bd-f2f): Add hash-based staleness detection to prevent stale DB from corrupting JSONL

The existing ZFC checks only compared issue counts, missing the case where
counts match but content differs (e.g., status=open vs status=closed).

Added Case 3 (bd-f2f) hash-based staleness detection:
- Before export, check if JSONL content hash differs from stored hash
- If hash mismatch detected, import JSONL first to get remote changes
- Then proceed with export to write merged state

This prevents the corruption scenario where:
1. Stale DB has old status values (e.g., status=closed)
2. Remote JSONL has correct values (e.g., status=open)
3. Export would overwrite correct JSONL with stale DB values
4. Git 3-way merge would propagate the corruption

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-11-29 19:25:14 -08:00
parent d5b9b7d284
commit 7b1573c4d4
2 changed files with 125 additions and 0 deletions

View File

@@ -223,6 +223,33 @@ Use --merge to merge the sync branch back to main branch.`,
}
}
}
// Case 3 (bd-f2f): JSONL content differs from DB (hash mismatch)
// This catches the case where counts match but STATUS/content differs.
// A stale DB exporting wrong status values over correct JSONL values
// causes corruption that the 3-way merge propagates.
//
// Example: Remote has status=open, stale DB has status=closed (count=5 both)
// Without this check: export writes status=closed → git merge keeps it → corruption
// With this check: detect hash mismatch → import first → get correct status
//
// Note: Auto-import in autoflush.go also checks for hash changes during store
// initialization, so this check may be redundant in most cases. However, it
// provides defense-in-depth for cases where auto-import is disabled or bypassed.
if !skipExport {
repoKey := getRepoKeyForPath(jsonlPath)
if hasJSONLChanged(ctx, store, jsonlPath, repoKey) {
fmt.Println("→ JSONL content differs from last sync (bd-f2f)")
fmt.Println("→ Importing JSONL first to prevent stale DB from overwriting changes...")
if err := importFromJSONL(ctx, jsonlPath, renameOnImport, noGitHistory); err != nil {
fmt.Fprintf(os.Stderr, "Error importing (bd-f2f hash mismatch): %v\n", err)
os.Exit(1)
}
// Don't skip export - we still want to export any remaining local dirty issues
// The import updated DB with JSONL content, and export will write merged state
fmt.Println("→ Import complete, continuing with export of merged state")
}
}
}
if !skipExport {