fix(search): activate dormant vector+graph+BM25 fusion on jrag search#445
Merged
Conversation
PR #443 added BM25 as a 3rd RRF list in _graph_expand_merge, but search_v2 never passed graph_expand=True to run_search — so the vector+graph+BM25 fusion was dormant for every user-facing search (jrag search, MCP search). Tests + eval stayed green only because they invoke run_search(graph_expand=True) directly, never through search_v2. The design spec's "Current" diagram claimed graph-expand was already on the live path; it wasn't (false since #409). - search_v2 (mcp_v2.py): pass graph_expand=(table == "java") at both run_search call sites — the primary path and the hybrid->vector FTS-missing retry. run_search already guards fusion to the java single-table path and degrades silently when the graph/FTS index is unavailable, so table=all/sql/yaml and airgapped installs are unaffected. search_payload routes through search_v2, so this covers jrag search + the MCP search tool. - tests: two contract tests through search_v2 (the wiring gap's blind spot). Negative control: forcing graph_expand=False makes them FAIL, proving the guard is non-vacuous and catches the dormancy. - docs: correct the design spec's false "Current" diagram with a post-merge note so the next implementer doesn't inherit the premise. ARCHITECTURE.md / DESIGN.md claims ("BM25 first-class on primary path") were false before and are now true — no edit needed. Full suite: 1535 passed, 38 skipped, 0 failed. Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
PR #443 added BM25 as a first-class third RRF list in
_graph_expand_mergeand shipped it with a measured win (MRR 0.30→0.62, recall@1 0.22→0.49 on identifier queries). But the fusion never ran on any user-facing search path —jrag searchand the MCPsearchtool were still pure vector.Root cause
search_v2never passedgraph_expand=Truetorun_search. The 3-list fusion lives in_graph_expand_merge, which is gated behindif graph_expand and key == "java"(search_lancedb.py:1080).search_v2'sgraphparam is the graph object (for lexical fallback), not an expand toggle — and it has nograph_expandparam at all. Git history confirmsmcp_v2.pyhas zero commits that referencegraph_expand; it's been dormant since #409 introduced_graph_expand_merge.Tests + the eval stayed green only because they invoke
run_search(graph_expand=True)directly, never throughsearch_v2— that was the blind spot. The design spec's "Current" data-flow diagram assertedsearch_v2 → run_search → graph-expandwas already happening; it wasn't.Fix
search_v2(mcp_v2.py:1052, 1079): passgraph_expand=(table == "java")at bothrun_searchcall sites (the primary path and the hybrid→vector-only FTS-missing retry).run_searchalready guards fusion to the java single-table path and degrades silently when the graph/FTS index is unavailable, sotable=all/sql/yamland airgapped installs are unaffected.search_payloadroutes throughsearch_v2, so this coversjrag search+ MCPsearchin one place.tests/mcp/test_mcp_v2.py): two contract tests throughsearch_v2—test_search_v2_enables_graph_expand_on_javaand..._through_hybrid_fts_fallback. Negative control: forcinggraph_expand=Falsemakes them FAIL, proving they catch the dormancy (this is the guard that was missing).2026-07-12-hybrid-bm25-rrf-design.md): added a post-merge correction note under the false "Current" diagram.ARCHITECTURE.md/DESIGN.mdclaims ("BM25 first-class on the primary path") were false before and are now true — no edit needed.Evidence
graph_expanddisabled, PASSES with the fixNote for reviewers / operators
This makes #443's feature actually run (~+25-30ms/query on the java path, per the eval). Identifier-style queries (
OperatorMessageProcessor,DistributionChunkService) are exactly BM25's strength and should improve. If you're diagnosing a ranking regression that appeared around #443's release, reindex clean first — a stale index (or the cocoindex 1.0.7→1.0.16 bump) is the more likely culprit than the fusion, which was dormant until this PR.🤖 Generated with Claude Code