* fix(sync): infiniteGameExp + foxhoundinc 5-bug wave (#1422, #1433, #1434, #1309, #1436)
Five real production bugs from infiniteGameExp (PostgreSQL onboarding) and
foxhoundinc (dream-cycle reproduction), each silent-failure shape where gbrain
told the user the operation succeeded when it didn't.
* #1422 — `gbrain dream` swallowed connectEngine errors. Bind the caught
error and surface `[dream] WARNING: could not connect to DB (...)` on
stderr before falling through to filesystem-only phases. runDream(null)
no-DB fallback preserved.
* #1433 — `gbrain sync` deleted previously-indexed log.md / schema.md /
index.md / README.md pages on every re-sync. Refactor isSyncable
through private classifySync helper; expose unsyncableReason (companion
returning the same tagged reason) and SYNC_SKIP_FILES named export.
Cleanup loop guards on reason === 'metafile' before deleting.
* #1434 — `gbrain sync` without --source on single-vault brains routed
to source_id='default' (zero pages) and silently failed. Add resolver
tier 5.5 'sole_non_default' AFTER brain_default (explicit user intent
wins). Wire runSync + runImport to call resolveSourceWithTier
unconditionally so the tier actually fires. Stderr nudge on tier hit;
suppress with GBRAIN_NO_SOLE_NON_DEFAULT_NUDGE=1.
* #1309 — overlapping ingest roots created duplicate pages. New
BrainEngine.findDuplicatePage?(sourceId, {hash, frontmatterId}) with
identity-based posture: SKIP when frontmatter.id matches (true
external duplicate), WARN-ALWAYS on content_hash collision with
different/missing fm.id, FAIL CLOSED on lookup error. Migration v95
adds partial index pages_dedup_idx (Postgres CONCURRENTLY, PGLite
plain CREATE).
* #1436 — MCP fuzzy get_page returned slug candidates from sources
outside caller's scope. resolveSlugs signature extended with
{sourceId?, sourceIds?} matching the sourceScopeOpts helper output;
operations.ts threads it through. Both engines preserve unscoped
back-compat for internal CLI callers.
Plus a stable tiebreaker on searchVector ORDER BY (score DESC, page_id
ASC, chunk_id ASC) in both engines. Caught while wiring the index above
— basis-vector eval fixtures with tied scores depend on planner row
order, which any new index on pages could flip. Pins eval-replay-gate
ranking determinism against future index changes.
Per codex review of the original plan: caught 6 load-bearing gaps that
the engineering review missed (runSync bypass, #1436 misclassified as
fixed, dedup fail-open, content-hash-alone too aggressive, soft-delete
filter missing, tier-ordering contradiction). All folded in pre-merge.
Tests: 65 new wave cases across 7 new files + 1 extended; all green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: bump version and changelog (v0.41.13.0)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>