Properly enforce ZFC: always import JSONL before export in sync

- Removed arbitrary 50% divergence check
- bd sync now unconditionally imports JSONL first (source of truth)
- Simpler, more correct: JSONL -> DB -> JSONL flow
This commit is contained in:
Steve Yegge
2025-11-23 22:38:13 -08:00
parent 1ba068fabd
commit 2e4171a5f8
2 changed files with 9 additions and 36 deletions

View File

@@ -8,7 +8,6 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"math"
"os"
"path/filepath"
"sort"
@@ -190,27 +189,8 @@ func validatePreExport(ctx context.Context, store storage.Storage, jsonlPath str
return fmt.Errorf("refusing to export empty DB over %d issues in JSONL (would cause data loss)", jsonlCount)
}
// Critical: refuse to export stale DB over fresh JSONL (bd-l0r)
// When DB has significantly more issues than JSONL, JSONL is the source of truth.
// Force import before allowing export to prevent stale DB from contaminating JSONL.
if jsonlCount > 0 {
divergencePercent := math.Abs(float64(dbCount-jsonlCount)) / float64(jsonlCount) * 100
if divergencePercent > 50 {
fmt.Fprintf(os.Stderr, "WARNING: DB has %d issues, JSONL has %d (%.1f%% divergence)\n",
dbCount, jsonlCount, divergencePercent)
// If DB is much larger than JSONL, refuse export - force import first
// JSONL is always the source of truth (ZFC: JSONL First Consistency)
if dbCount > jsonlCount {
return fmt.Errorf("refusing to export: DB has %d more issues than JSONL (%.1f%% divergence). "+
"JSONL is the source of truth - import it first with 'bd import' or 'bd sync --import-only'",
dbCount-jsonlCount, divergencePercent)
}
// If JSONL is much larger than DB, just warn (could be legitimate new issues)
fmt.Fprintf(os.Stderr, "This suggests sync failure - investigate before proceeding\n")
}
}
// Note: ZFC (JSONL First Consistency - bd-l0r) is now enforced in sync.go
// by always importing before export. This validation is kept for direct bd export calls.
return nil
}

View File

@@ -123,23 +123,16 @@ Use --merge to merge the sync branch back to main branch.`,
os.Exit(1)
}
// Step 1: Export pending changes
// Step 1: Import JSONL first (ZFC: JSONL First Consistency - bd-l0r)
// JSONL is always the source of truth. Import before export to ensure DB is synced.
if dryRun {
fmt.Println("→ [DRY RUN] Would import from JSONL (ZFC)")
fmt.Println("→ [DRY RUN] Would export pending changes to JSONL")
} else {
// Smart conflict resolution: if JSONL content changed, auto-import first
// Use content-based check (not mtime) to avoid git resurrection bug (bd-khnb)
if err := ensureStoreActive(); err == nil && store != nil {
// Use getRepoKeyForPath for multi-repo support (bd-ar2.10, bd-ar2.11)
repoKey := getRepoKeyForPath(jsonlPath)
if hasJSONLChanged(ctx, store, jsonlPath, repoKey) {
fmt.Println("→ JSONL content changed, importing first...")
if err := importFromJSONL(ctx, jsonlPath, renameOnImport); err != nil {
fmt.Fprintf(os.Stderr, "Error auto-importing: %v\n", err)
os.Exit(1)
}
fmt.Println("✓ Auto-import complete")
}
fmt.Println("→ Importing from JSONL (ZFC)...")
if err := importFromJSONL(ctx, jsonlPath, renameOnImport); err != nil {
fmt.Fprintf(os.Stderr, "Error importing (ZFC): %v\n", err)
os.Exit(1)
}
// Pre-export integrity checks