{{ message }}
Repository navigation
fix(core): retrieve once per reranked search request - #1616
Merged
Merged
Conversation
A vector or hybrid request whose page reached past the fixed reranked prefix ran a second retrieval (query embedding, vector query, and a second FTS pass for hybrid) only to rebuild that prefix. The prefix is now read from the request's own candidate window at the fixed window's chunk-position bound, so every page reranks the same rows with the same passages from one retrieval, on the project route and the scoped QUERY /v2/search/ route alike. - CandidateWindow records each chunk's adapter position and can rank its rows as a window of a given bound sees them. - Fusion moves into a pure fuse() shared by the full fusion and the fixed prefix; equal fused scores order by key. - Hybrid tail rows order by first FTS rank or best-chunk vector position, counted before chunks collapse into rows. - SQLite FTS breaks score ties by id, as Postgres already did. - stable_pool_refetched is removed from the search trace. Fixes #1557 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig Signed-off-by: phernandez <paul@basicmachines.co>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b7de49a03c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
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.

Why
Fixes #1557. With reranking enabled, a vector or hybrid request whose page reached past the fixed reranked prefix ran retrieval twice: once for the expanded window, and again at the fixed window's size to rebuild the prefix (a second query embedding and vector query, plus a second FTS pass for hybrid). This replaces closed #1560 on top of the scope-parameterized
SearchReaderfrom the #1558 stack, so the fix covers the project route and the scopedQUERY /v2/search/route.What changed
CandidateWindowrecords each chunk's position in the adapter ranking.ranked_rows(position_bound)returns the rows, scores, and passages a window of that bound would produce. A larger window only appends chunks, so this reproduces the fixed window from the request's own window.SemanticSearch._prefix_rowsreads the fixed prefix at_rerank_candidate_limitchunks. With structured filters, the fixed window widens until it admits enough rows, so the bound extends to cover the leading admitted rows. Passages past the bound stay out of the prefix.fts_results[:K]with the vector prefix rows. Fusion is now a purefuse()used by both the full fusion and the prefix. Equal fused scores are ordered by key._rerank_and_paginatenow takes the prefix and the tail from its caller instead ofstable_rows.vector_onlyandhybridlose thecandidate_limit,apply_rerank, andemit_observability_logparameters, which only existed for the recursive refetch.search_index.id ASC, as Postgres already did. A smaller FTS window is then always a prefix of a larger one.stable_pool_refetchedis removed from the internal search trace. It was not exposed in the inspect schema.Salvaged from #1560
SearchReader. Also kept: the hybrid collapse tail-order test and the fixed-prefix-passages test, both ported toSemanticSearch._run_vector_query. The call-count assertions updated from[18, 8]/[90, 80]to[18]/[90], including thetest-int/semanticones.candidate_rank/fixedk=4096adapter change and its tests (dropped adapter slots, pending-manifest slots, unordered-stream threshold). This design counts positions in the hydrated stream, so it does not need adapter ranks. A fixedk=4096cost about 6x on shallow sqlite-vec queries in a local microbenchmark (1.8 ms to 10.5 ms at 10k vectors).tests/semantic_search_helpers.pyand the tyextra-pathschange. The new test imports helpers fromtests.repository.test_rerank_pipeline, like other suites do.Known limit
sqlite-vec picks arbitrarily among exactly equal distances at its
kcutoff. Windows of different sizes can therefore disagree on which identical vectors they hold. This already affects every sqlite-vec window boundary on main (tail pages, non-reranked pagination). This change extends it to the prefix boundary in the rare case where exact-duplicate passages sit there. The test corpus gives each passage its own distance. If we want tie determinism, the option is the fixed-kquery from #1560, scoped to reranked requests. Postgres passes the same suite with tied vectors.Testing
main: 2 embeddings per deep reranked request, and a misordered collapse tail. They pass on this branch.just fast-check: passed.tests/repository tests/api/v2 tests/services tests/mcp: 3600 passed.test-int(not semantic/benchmark): 607 passed.BASIC_MEMORY_TEST_POSTGRES=1): stable-pagination, rerank pipeline, trace, fusion, reader, vector pagination/filter/threshold, pgvector index, and search router suites: 174 passed.🤖 Generated with Claude Code
https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig