fix(search): make equal-score ranking deterministic#46
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5f73f2972d
ℹ️ 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".
| b.score | ||
| .partial_cmp(&a.score) | ||
| .unwrap_or(std::cmp::Ordering::Equal) | ||
| .then_with(|| a.file_path.cmp(&b.file_path)) |
There was a problem hiding this comment.
Preserve pass-one order for tied rerank scores
When the reranker assigns the same score to multiple candidates, including the existing unwrap_or(0.0) path when scoring fails, this tie-break turns the rerank lane into an alphabetical ranking. Because the rerank lane is fused with a nonzero weight, equal reranker scores can now promote alphabetically earlier files over candidates that were ranked higher by pass 1; the deterministic tie-break here should preserve the existing fused_pass1 candidate order instead of using file_path.
Useful? React with 👍 / 👎.
| b.score | ||
| .partial_cmp(&a.score) | ||
| .unwrap_or(std::cmp::Ordering::Equal) | ||
| .then_with(|| a.file_path.cmp(&b.file_path)) |
There was a problem hiding this comment.
Preserve base relevance for equal temporal scores
For temporal queries where several candidates fall inside the requested date range, temporal_score gives them identical scores, so this tie-break makes the temporal lane rank those equally timed notes alphabetically. Since the temporal lane has a high RRF weight, that can push alphabetically earlier paths above more relevant base results even though the temporal signal did not distinguish them; tie scores should keep the base_fused order to preserve the existing relevance signal deterministically.
Useful? React with 👍 / 👎.
Refs #44 and #34.
What changed
chunks(file_id)indexing and anidtie-break for best-chunk selection.Why
Several result collections originate in
HashMaps. Equal-score entries therefore inherited randomized map iteration order, which could change ranks, confidence, and graph-expansion truncation across otherwise identical searches. The graph lane also repeatedly looked up chunks byfile_idwithout an index.Impact
Searches with score ties now produce stable ordering, and graph best-chunk lookups avoid full chunk-table scans. Non-tied ranking semantics are unchanged.
Validation
cargo fmt --checkcargo clippy -- -D warningscargo test --lib— 468 passedcargo test --test golden_search— passed