Skip to content

feat: add optional vector fusion for recall - #26

Open
faj-design5260 wants to merge 5 commits into
mainfrom
feat/optional-index-pr
Open

faj-design5260 wants to merge 5 commits into
mainfrom
feat/optional-index-pr

Conversation

@faj-design5260

@faj-design5260 faj-design5260 commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Problem

BM25 is fast for lexical matches, but some relevant memories miss the top-k candidate set when query and stored wording diverge.

Design

  • Keep FTS5/BM25 as the default retrieval path.
  • Optionally build a local vector index and fuse BM25 and vector chunk rankings with RRF.
  • Keep Markdown files as the source of truth and SQLite indexes rebuildable.
  • Preserve BM25 behavior with vector retrieval disabled, and use BM25 results when an enabled vector index has no candidates. Missing optional embedding dependencies produce an explicit error.
  • Apply the existing lifecycle, scope, as-of, weight, recency, and raw-evidence rules.

The branch was rebased onto 34d12a2f and reduced to the optional index, fusion, config/lifecycle, tests, and documentation. Answer replay harness changes were removed from this PR.

Retrieval evaluation

Fixed 120-query acceptance set across 200 source sessions:

Arm Recall@5 Median retrieval latency P95 retrieval latency
BM25 79.0% 5.1ms 9.3ms
BM25 + Vector 86.6% 139.2ms 170.8ms

Optional vector fusion improved Recall@5 by 7.6 percentage points with a substantial latency cost. This establishes a retrieval-coverage/latency trade-off on this fixed set.

Provenance: the local experiment artifact experiments/runs/optional-index-acceptance-20260909/ contains the manifest, selected questions, frozen store/truth hashes, runner, per-query outputs, summary, and identical repeated ON rankings. The manifest pins source SHA-256 821a2034d219ab45846873dd14c14f12cfe7776e73527a483f9dac095d38620c, seed 20260909, configurations, two embedding threads, and evaluated revision e3480b4b. The final candidate changes only recall fingerprint handling, vector config validation, and BM25 fallback when the vector candidate list is empty; populated-index RRF, filtering, top-k, vector indexing, and benchmark runner remain the evaluated implementation. The 120-query run was therefore not repeated for formality.

Answer-level evaluation

  • Fixed-context replay, first 24 cases: BM25 17/24; BM25 + Vector 18/24.
  • Fixed-context replay, expanded 36 cases: BM25 28/36; BM25 + Vector 27/36. Both additional Vector regressions lacked relevant Raw evidence in that arm's retrieval results.
  • Agentic 24-case replay: both arms 21/24, while 23/24 cases did not actually read Memory.

These experiments do not establish an answer-quality improvement attributable to the vector index. Larger answer replays are outside this PR's merge claim.

Claim and limitations

This PR establishes an optional retrieval-coverage/latency trade-off. It does not claim an end-to-end answer accuracy improvement or universal superiority. The benefit is measured on the fixed retrieval set only, and enabled retrieval has substantially higher latency.

Compatibility and validation

  • Vector remains opt-in; BM25 remains available.
  • Files remain the source of truth; index deletion and rebuild preserve recall and Memory content.
  • Tests cover config/fingerprint, BM25 compatibility, missing dependency, empty vector fallback, incremental indexing, delete/supersede, RRF fusion, scope/as-of, and rebuild.
  • uv run pytest -q: 410 passed.
  • CI coverage command: 410 passed, 90.94% coverage (85% required).
  • uv run ruff check .: passed.
  • uv run mypy: passed, 68 source files.

faj-design5260 and others added 5 commits September 18, 2026 21:07
The fingerprint hashed every index knob, so adding vector_enabled and
vector_model changed the default fingerprint even though retrieval with
the vector index off is byte-for-byte what main does. Every experiment
after the merge would then read as a different R than every experiment
before it, which is exactly the drift the Invariant 9 guard exists to
catch, fired on nothing.

A disabled backend shapes nothing, so its knobs leave the hash while it
is off and enter it the moment it is on. The default fingerprint is
again 4883d0333e25b7c6, the same value main produces.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@faj-design5260 faj-design5260 changed the title feat: add optional vector recall index feat: add optional vector fusion for recall Sep 18, 2026
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.

2 participants