fix(knowledge): expose honest search score provenance - #2317
Conversation
Keep genuine lexical misses empty instead of ranking newest corpus rows. Track lexical and ANN score sources, expose candidate and score provenance, and retire stale absolute score bands across the public contract docs.
|
The behaviour change is scoped correctly and the provenance is derived rather than asserted, which are the two things most likely to be wrong in a change of this shape. One test gap is worth closing before merge; one stale comment is worth fixing on the way past. The set difference is the right oneBefore this diff, The new path keeps the raw probe, but only to distinguish "matched then filtered to empty" from "matched nothing" ( That is the correct scope, and the two conditions that would have made a partial fix are both handled: a raw match whose rows are all ineligible does not take the miss path, and a timeout does not either. One correction to the framingThe wire contract is five-valued, not four: Filtered-to-empty and matched-nothing are distinguishable through Provenance is computed, not inferred from contextLexical hits carry lexical provenance at construction ( Additivity holds: existing result keys and [Medium] No end-to-end coverage of the fused-plus-reranked case
A regression in the caller-visible projection, in the fused-source merge, or in the rerank flag would pass the current suite. Suggested shape: one handler-level test with an id contributed by both legs and a successful fake embedding rerank, asserting
[Low] Two comments still describe the removed fallback
One ordering noteThe implementation fetches ANN before lexical ( |
|
Approving the change. Not merging yet — CI has never run on this PR, and I am not The fix is the right oneThe defect being removed is real and it is the interesting kind. On a genuine FTS miss the Deleting that fallback while keeping the raw-FTS existence probe is the right shape — it Retiring the score bands is overdue and correctly justifiedRetiring the
TestsThree tests, one per behavioural claim, and the important one is not vacuous — I checked, I ran the suite locally at this head: Treat that as supporting evidence, not as a substitute for CI: my local toolchain is Why this is not mergedNo CI has run on this PR at all. The only workflow run on the branch is the auto-merge This is not a filter: the CI trigger is a bare I am flipping this out of draft to fire a Merge waits on a green wall. |
|
Correcting my previous note: marking this ready did not get CI to run, and neither did This branch conflicts with The branch is 9 commits behind Resolving that conflict and pushing will also fix the CI situation as a side effect, since So the sequence is: merge |
|
This is blocked on a merge conflict, and it explains the missing CI too. Details below so the The conflictOne file:
Correct resolution is to keep both: the status line becomes The risk worth naming: resolving this by taking this branch's side of the hunk is The other two hunks on this branch (the Why there is no CI
One thing to expect on that first run: the secret scan was repository-wide until recently and is |
Both required contexts are absent, and re-triggering will not produce them
Only the That is the whole cause. GitHub cannot compute a merge commit while the branch conflicts with Worth stating what this is not, because the obvious reading is wrong: a conflicted state alone The practical consequence: re-running, reopening, or re-marking ready cannot help, since all of The conflict is one file:
|
No CI is running on this branch, and the empty check list is the symptomThis branch conflicts with The consequence is worth stating plainly, because it reads the wrong way round: neither required The direction of the error is safe — a required check that is missing blocks the merge, so Resolving the conflict and pushing is what produces a check surface. Nothing else will; in |
ohdearquant
left a comment
There was a problem hiding this comment.
Automated review. Posted by this repository's automated pull-request review pipeline; this is not a human read and does not gate the merge by itself.
Verdict on head 8e4ab94: REQUEST-CHANGES, 1 blocking finding. Finding details are delivered to the review's recipients rather than posted here. Do not merge this head while blocking findings are outstanding; a pipeline comment on a newer head supersedes this one.
ohdearquant
left a comment
There was a problem hiding this comment.
Automated review. Posted by this repository's automated pull-request review pipeline; this is not a human read and does not gate the merge by itself.
Verdict on head 21dcc88: REQUEST-CHANGES, 1 blocking finding. Finding details are delivered to the review's recipients rather than posted here. Do not merge this head while blocking findings are outstanding; a pipeline comment on a newer head supersedes this one.
…-out in search A query whose every token falls below the minimum scoreable term length (e.g. "AI") reached FTS only as the raw phrase, which the trigram tokenizer cannot match below three characters. Removing the recency-fallback lexical path left such short exact names undiscoverable without ANN. search_core now probes the unique (namespace, slug) index as an indexed exact-name fallback when no query term is scoreable, and reports a distinct exact_name lexical candidate state so callers can tell it apart from an ordinary FTS match. The lexical candidate stage also bounds the number of distinct scoreable terms that each issue their own FTS MATCH statement. Without this bound, a query with many distinct terms turned one request into a proportionally unbounded number of index probes and retained-row memory, checked only by the request read deadline. A query at or under the bound sees identical candidate generation and ranking to the unbounded behavior; a query over the bound now reports terms_truncated in candidate_provenance. Also documents the upsert_atoms source_uri/source_type patch fields that were missing from the API reference, and adds a deterministic-embedder test covering the embedding_rerank=true provenance path, which previously had no coverage.
ohdearquant
left a comment
There was a problem hiding this comment.
Automated review. Posted by this repository's automated pull-request review pipeline; this is not a human read and does not gate the merge by itself.
Verdict on head c4c1c11: REQUEST-CHANGES, 2 blocking findings. Finding details are delivered to the review's recipients rather than posted here. Do not merge this head while blocking findings are outstanding; a pipeline comment on a newer head supersedes this one.
Summary
Contract
knowledge.searchnow returns top-levelcandidate_provenancewith the lexical candidate state and whether the returned set is ANN fallback. Each result addsscore_provenancewith stable lexical/ANN sources, embedding-rerank use,s_over_s_plus_1normalization, andcalibrated: false.Scores remain useful for response-local ordering and
min_score, but they are request-relative hybrid ranking values rather than probabilities or absolute corpus-presence signals.knowledge.suggestkeeps its existing result shape so its strictknowledge.foldhandoff remains compatible.Verification
cargo test -p khive-pack-knowledge(403 passed, 1 ignored)cargo check --workspacecargo clippy --workspace --all-targets -- -D warningscargo fmt --check --allgit diff --checkThis PR is independent of the search-concurrency and query-cache branches.
Closes #1982