Skip to content

fix(brain): load vector index from disk on the search path - #546

Merged
ajianaz merged 1 commit into
developfrom
fix/545-brain-vector-signal-fresh-process
Aug 31, 2026
Merged

fix(brain): load vector index from disk on the search path#546
ajianaz merged 1 commit into
developfrom
fix/545-brain-vector-signal-fresh-process

Conversation

@ajianaz

@ajianaz ajianaz commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

What

The search path (cora brain CLI and MCP brain_search) never loaded the vector index from disk. VECTOR_CACHE was only populated by embed_project (the cora index path), so every fresh search process saw an empty cache, vector_search returned nothing, and results silently degraded to FTS + graph signals only. Pre-existing on develop (default usearch backend) and on the vecq branch — verified with the same sandboxed e2e run (signals=fts only).

Fix: vector_search now lazy-loads the on-disk index once per process via ensure_vector_cache (double-checked read/write locking; concurrent double load is idempotent). Load failures degrade gracefully with a warn log and FTS fallback. Also guard dimension mismatch (embedding provider switched since the index was built) — previously a guaranteed panic inside the backend.

Why

Without this, the vector signal — a third of the RRF fusion — was dead in every process that did not run the embed itself. brain_search quality silently regressed to FTS-only, and the vecq backend merged in #543 had no observable benefit on the search path.

Testing

  • New regression tests (tests/brain_search_process.rs): fresh-process cora brain must emit the vector signal with the default usearch backend; brain.vector_store: vecq must produce a .vecq file. Both use isolated CODECORA_HOME sandboxes. 2/2 pass.
  • Full suite: 939/939 (915 unit + 2 new + 16 + 6).
  • E2E with the real binary (sandboxed CODECORA_HOME): cora index → fresh-process cora brain alpha now prints signals=fts,vector (and surfaces beta via vector-only) where develop printed signals=fts alone.

Note: the vecq backend still degrades to FTS-only in fresh search processes — upstream vecq#32 (no key serialization on reload) — tracked separately; the load path is backend-aware and will pick vecq up once upstream lands key serialization.

Closes #545

VECTOR_CACHE was only populated by embed_project (i.e. 'cora index'),
so a fresh search process — 'cora brain' CLI or MCP brain_search —
always saw an empty cache and the vector signal never fired; results
silently degraded to FTS + graph only. Verified on develop and on the
vecq PR branch with the same sandboxed e2e run.

vector_search now lazy-loads the on-disk index once per process via
ensure_vector_cache (double-checked read/write locking; a concurrent
double load is idempotent). Load failures degrade gracefully with a
warn log. Also guard dimension mismatch (embedding provider switched
since the index was built) — previously a panic inside the backend.

Note: the vecq backend still degrades to FTS-only in fresh search
processes — that is the documented upstream limitation (vecq#32, no
key serialization), tracked separately.

Regression tests (tests/brain_search_process.rs): fresh-process brain
search must emit the vector signal (default usearch backend), and
brain.vector_store: vecq must produce a .vecq file — both run with
isolated CODECORA_HOME sandboxes.
@ajianaz
ajianaz merged commit 01be21f into develop Aug 31, 2026
15 checks passed
@ajianaz
ajianaz deleted the fix/545-brain-vector-signal-fresh-process branch August 31, 2026 04:01
ajianaz added a commit that referenced this pull request Aug 31, 2026
…rain.vector_bits knob (#548)

Upgrade the opt-in vecq store to vecq-core 0.3.0 and close #547.

- Keyed persistence (upstream vecq#32 closed, format v1.3+): symbol-id
  keys survive reload. load_or_create_vecq now deserializes for real and
  keeps a healthy keyed index; legacy keyless files, corrupt files, and
  dim mismatches rebuild dirty so the next  re-embeds. A dim
  guard is mandatory: add_keyed panics on wrong-dim vectors.
- brain.vector_bits config (residual|4|5|6, lenient, default residual):
  residual is best recall@10 at 4-bit scan speed in a recall study on
  cora's own embeddings (ahead of plain 5-bit at 1k/5k/13k scales).
  A width change rebuilds the index once so the config takes effect;
  vecq_file_needs_rebuild is width-aware.
- BrainConfig gets a manual Default (derived Default produced empty
  strings, inconsistent with the serde defaults).
- Cross-project heal: the vector index is one shared file; a rebuild
  (width/dims/legacy/corrupt) now clears embed fingerprints for ALL
  projects, not just the active one, and the usearch dims-mismatch
  deletion path joins the same heal (pre-existing fingerprint leak).

Tests: keyed roundtrip, legacy keyless rebuild, corrupt rebuild,
dim-mismatch rebuild, width-switch rebuild, roundtrip across all four
widths, lenient parsing, config merge. 947 pass incl. the fresh-process
integration tests from #546.

Closes #547

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

brain search: vector signal never fires in a fresh process (VECTOR_CACHE never loaded from disk)

1 participant