Fix bd-khnb: Prevent auto-import from resurrecting deleted issues
Replace mtime-based staleness detection with content-based (SHA256 hash) to prevent git operations from resurrecting deleted issues. **Problem:** Auto-import used file modification time to detect if JSONL was "newer" than database. Git operations (checkout, merge, pull) restore old files with recent mtimes, causing auto-import to load stale data over current database state, resurrecting deleted issues. **Solution:** - Added computeJSONLHash() to compute SHA256 of JSONL content - Added hasJSONLChanged() with two-tier check: 1. Fast-path: Check mtime first (99% of checks are instant) 2. Slow-path: Compute hash only if mtime changed (catches git operations) - Store metadata: last_import_hash, last_import_mtime, last_import_time - Updated auto-import in daemon_sync.go to use content-based check - Updated validatePreExport to use content-based check (bd-xwo) - Graceful degradation: metadata failures are non-fatal warnings **Changes:** - cmd/bd/integrity.go: Add computeJSONLHash(), hasJSONLChanged() - cmd/bd/integrity_test.go: Add comprehensive tests for new functions - cmd/bd/import.go: Update metadata after import - cmd/bd/sync.go: Use hasJSONLChanged() instead of isJSONLNewer() - cmd/bd/daemon_sync.go: Use hasJSONLChanged() in auto-import **Testing:** - Unit tests pass (TestHasJSONLChanged with 7 scenarios) - Integration test passes (test_bd_khnb_fix.sh) - Verified git resurrection scenario prevented Fixes: bd-khnb Related: bd-3bg, bd-xwo, bd-39o, bd-56p, bd-m8t, bd-rfj, bd-t5o 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -307,6 +307,34 @@ NOTE: Import requires direct database access and does not work with daemon mode.
|
||||
flushToJSONL()
|
||||
}
|
||||
|
||||
// Update last_import_hash metadata to enable content-based staleness detection (bd-khnb fix)
|
||||
// This prevents git operations from resurrecting deleted issues by comparing content instead of mtime
|
||||
if input != "" {
|
||||
if currentHash, err := computeJSONLHash(input); err == nil {
|
||||
if err := store.SetMetadata(ctx, "last_import_hash", currentHash); err != nil {
|
||||
// Non-fatal warning: Metadata update failures are intentionally non-fatal to prevent blocking
|
||||
// successful imports. System degrades gracefully to mtime-based staleness detection if metadata
|
||||
// is unavailable. This ensures import operations always succeed even if metadata storage fails.
|
||||
debug.Logf("Warning: failed to update last_import_hash: %v", err)
|
||||
}
|
||||
importTime := time.Now().Format(time.RFC3339)
|
||||
if err := store.SetMetadata(ctx, "last_import_time", importTime); err != nil {
|
||||
// Non-fatal warning (see above comment about graceful degradation)
|
||||
debug.Logf("Warning: failed to update last_import_time: %v", err)
|
||||
}
|
||||
// Store mtime for fast-path optimization in hasJSONLChanged (bd-3bg)
|
||||
if jsonlInfo, statErr := os.Stat(input); statErr == nil {
|
||||
mtimeStr := fmt.Sprintf("%d", jsonlInfo.ModTime().Unix())
|
||||
if err := store.SetMetadata(ctx, "last_import_mtime", mtimeStr); err != nil {
|
||||
// Non-fatal warning (see above comment about graceful degradation)
|
||||
debug.Logf("Warning: failed to update last_import_mtime: %v", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug.Logf("Warning: failed to read JSONL for hash update: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Update database mtime to reflect it's now in sync with JSONL
|
||||
// This is CRITICAL even when import found 0 changes, because:
|
||||
// 1. Import validates DB and JSONL are in sync (no content divergence)
|
||||
|
||||
Reference in New Issue
Block a user