Fix bd-l0r: Skip export after ZFC import to preserve JSONL source of truth
## Problem When bd sync detected stale DB (>50% divergence), it would import JSONL to fix the DB, but then immediately export the DB back to JSONL. This caused the stale DB to overwrite the JSONL after a git pull, undoing cleanup work. Example scenario: 1. Clone has 688 stale issues in DB (628 closed) 2. git pull brings JSONL with 62 issues (cleanup applied) 3. bd sync detects 1009.7% divergence and imports JSONL (DB → 62 issues) ✓ 4. bd sync exports DB to JSONL (JSONL still 62 issues) ✓ 5. But this marks JSONL as "changed" and commits/pushes it ✗ ## Solution After ZFC (JSONL First Consistency) import, set skipExport flag to prevent the export step. JSONL is the source of truth after import - DB should sync to match, not export back. ## Changes - cmd/bd/sync.go: Add skipExport flag, set it after ZFC import - cmd/bd/sync.go: Wrap export logic in `if !skipExport` block - CHANGELOG.md: Update ZFC entry with accurate description - cmd/bd/sync_test.go: Add TestZFCSkipsExportAfterImport Fixes #bd-l0r 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -124,11 +124,13 @@ Use --merge to merge the sync branch back to main branch.`,
|
||||
}
|
||||
|
||||
// Step 1: Export pending changes (but check for stale DB first)
|
||||
skipExport := false // Track if we should skip export due to ZFC import
|
||||
if dryRun {
|
||||
fmt.Println("→ [DRY RUN] Would export pending changes to JSONL")
|
||||
} else {
|
||||
// ZFC safety check (bd-l0r): if DB significantly diverges from JSONL,
|
||||
// force import first to sync with JSONL source of truth
|
||||
// After import, skip export to prevent overwriting JSONL (JSONL is source of truth)
|
||||
if err := ensureStoreActive(); err == nil && store != nil {
|
||||
dbCount, err := countDBIssuesFast(ctx, store)
|
||||
if err == nil {
|
||||
@@ -142,32 +144,37 @@ Use --merge to merge the sync branch back to main branch.`,
|
||||
fmt.Fprintf(os.Stderr, "Error importing (ZFC): %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
// Skip export after ZFC import - JSONL is source of truth
|
||||
skipExport = true
|
||||
fmt.Println("→ Skipping export (JSONL is source of truth after ZFC import)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pre-export integrity checks
|
||||
if err := ensureStoreActive(); err == nil && store != nil {
|
||||
if err := validatePreExport(ctx, store, jsonlPath); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Pre-export validation failed: %v\n", err)
|
||||
os.Exit(1)
|
||||
if !skipExport {
|
||||
// Pre-export integrity checks
|
||||
if err := ensureStoreActive(); err == nil && store != nil {
|
||||
if err := validatePreExport(ctx, store, jsonlPath); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Pre-export validation failed: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := checkDuplicateIDs(ctx, store); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Database corruption detected: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if orphaned, err := checkOrphanedDeps(ctx, store); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Warning: orphaned dependency check failed: %v\n", err)
|
||||
} else if len(orphaned) > 0 {
|
||||
fmt.Fprintf(os.Stderr, "Warning: found %d orphaned dependencies: %v\n", len(orphaned), orphaned)
|
||||
}
|
||||
}
|
||||
if err := checkDuplicateIDs(ctx, store); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Database corruption detected: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if orphaned, err := checkOrphanedDeps(ctx, store); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Warning: orphaned dependency check failed: %v\n", err)
|
||||
} else if len(orphaned) > 0 {
|
||||
fmt.Fprintf(os.Stderr, "Warning: found %d orphaned dependencies: %v\n", len(orphaned), orphaned)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("→ Exporting pending changes to JSONL...")
|
||||
if err := exportToJSONL(ctx, jsonlPath); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error exporting: %v\n", err)
|
||||
os.Exit(1)
|
||||
fmt.Println("→ Exporting pending changes to JSONL...")
|
||||
if err := exportToJSONL(ctx, jsonlPath); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error exporting: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Capture left snapshot (pre-pull state) for 3-way merge
|
||||
|
||||
Reference in New Issue
Block a user