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:
Steve Yegge
2025-11-20 21:49:52 -05:00
parent 57253f93a3
commit 0020eb490c
5 changed files with 480 additions and 42 deletions

View File

@@ -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)