fix(rag): break saturated selection ties by query-term coverage, not rank score#987
Conversation
…rank score The 2026-07-20 post-merge golden run (eval-canary #50, 35/36) showed the #982 tie-break regressing alcohol-ciwa-threshold: keying saturated ties on the boost-laden rankScore let generic clinicalSignalBoost stacking promote screening/monitoring chunks over the chunk containing the queried terms — the same failure mode the clamped-score contract exists to prevent. The tie-break key is now the clinical rank's lexicalCoverageScore (query-term coverage, immune to boost stacking), renamed contentCoverageScore; ties on coverage still fall back to the stable chunk-id order. The saturated-tie contract test now pins coverage winning against a HIGHER rankScore, and the fast-path CIWA guard adds the screening-chunk shape from run #50. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EXsJcLrbZUXwnBeG91cVo9
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EXsJcLrbZUXwnBeG91cVo9
📝 WalkthroughWalkthroughThe retrieval candidate tie-break changed from rank score to lexical coverage for saturated primary-score ties. Candidate types, selection tests, fast-path ordering fixtures, and the review ledger were updated to reflect and validate coverage-first ordering. ChangesRetrieval coverage tie-break
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Summary
b9057f0) came back 35/36: the three verifiable July-19 regressions (lithium-therapy-monitoring,clozapine-anc-threshold,patient-safety-plan-include) now all pass live, butalcohol-ciwa-thresholdflipped pass→FAIL versus the same-morning pre-fix(rag): content-aware saturated-tie ordering + offline guards for the #901 eval regression class #982 run chore(deps-dev): bump @vitest/coverage-v8 from 4.1.8 to 4.1.9 #49 (36/36). The failing top-3 was ordered by descending boost-ladenrankScore(1.85/1.75/1.53, allfinalScore-saturated) — fix(rag): content-aware saturated-tie ordering + offline guards for the #901 eval regression class #982's tie-break let genericclinicalSignalBooststacking (screening/monitoring vocabulary) outvote the chunk that actually contains the queried terms (ciwa/score/threshold). fix(rag): content-aware saturated-tie ordering + offline guards for the #901 eval regression class #982 was the only retrieval-path change in the window, so this is our regression to fix, and it is precisely the failure mode the clamped-score contract exists to prevent.RetrievalCandidateis renamedcontentRankScore→contentCoverageScoreand sourced from the clinical rank'slexicalCoverageScore— query-term coverage, which is exactly what the golden eval's content gate measures and is immune to boost stacking. It remains ONLY a tie-break between the clampedrerankScoreand the chunk-id fallback; scores are never modified; coverage ties still fall back to the stable chunk-id order.rankScorebut higher coverage — the old fix(rag): content-aware saturated-tie ordering + offline guards for the #901 eval regression class #982 key fails this test, so the pin discriminates. The fast-path CIWA guard (tests/rag-fast-path-ordering.test.ts) gains a third candidate modeling run Save Codex local changes #50's winning screening chunk plus the eval's content-term assertion.Verification
rag-fast-path-ordering,rag-second-stage-ranking,retrieval-selection,ranking-tuning) — 38/38npm run test— 3012 passed; sole failure is the long-baselined container-onlypdf-extraction-budgetartifact (hosted-CI-green through feat(pwa): retirement kill-switch, offline-version binding guard, and dev teardown flag #826–fix(rag): content-aware saturated-tie ordering + offline guards for the #901 eval regression class #982)npm run verify:cheap— all static checks, lint, typecheck green; same single artifact in the test stepnpm run build+ client-bundle secret scan +npm run check:rag:fixtures— pass (36 golden cases, 21 suites)npm run check:production-readiness— substantive checks pass; the two FAILs are the documented missing-secret class (no live secrets in this container)npm run eval:retrieval:quality(must stay 36/36) — cannot run locally (needs live keys, which exist only in Actions). Live validation lands via tonight's Sunday 18:00 UTC scheduled eval-canary on post-merge main; the authorized dispatch budget (2 runs, ≈$2–4) is spent. Both today's run logs (chore(deps-dev): bump @vitest/coverage-v8 from 4.1.8 to 4.1.9 #49 pass / Save Codex local changes #50 fail) are the paste-equivalent evidence and are cited in the ledger row.Risk and rollout
Clinical Governance Preflight
Clinical KB Database(sjrfecxgysukkwxsowpy)Notes
🤖 Generated with Claude Code
https://claude.ai/code/session_01EXsJcLrbZUXwnBeG91cVo9
Generated by Claude Code
Summary by CodeRabbit
Bug Fixes
Documentation