fix(rag): content-aware saturated-tie ordering + offline guards for the #901 eval regression class#982
Conversation
…th ordering guards The 2026-07-19 golden retrieval eval failed 4/36 on the raw #901 ordering. The same-day remediation (#913-#926) restored live results (fresh eval on remediated main passed 36/36 today), but the failure class had zero offline coverage and one reproducible defect survived: when the embedding-free text fast path imputes byte-identical primaries, selection's clamped sort keys all tie exactly and the chunk-id fallback decides — an arbitrary order that the second stage's position-based adjustment then launders into releaseRankScore and the released order, burying the answer-bearing document. - retrieval-selection: carry contentRankScore (the content-aware clinical rank) on candidates and use it ONLY as the tie-break between the clamped rerank confidence and the chunk-id fallback. It is never added to a score, so the measured clamped-score contract is unchanged. - tests/rag-fast-path-ordering.test.ts: four end-to-end guards replaying the failed eval cases' shapes through the production ordering pipeline. - tests/ranking-tuning.test.ts: gate the four golden-mapped hard negatives at production weights plus a full-snapshot high-risk assertion. - tests/retrieval-selection.test.ts: amend #901's saturated-tie pin (chunk-id order was never live-eval-validated) to the content-rank-then-id contract, with an id-fallback case for identical content ranks. 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
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughThe retrieval pipeline now preserves ChangesRetrieval ranking correction
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant TextFastPath
participant buildRetrievalCandidates
participant selectRetrievalEvidence
participant SecondStageRerank
participant ReleasedOrder
TextFastPath->>buildRetrievalCandidates: build candidates with contentRankScore
buildRetrievalCandidates->>selectRetrievalEvidence: provide candidates and clamped scores
selectRetrievalEvidence->>SecondStageRerank: pass selected evidence
SecondStageRerank->>ReleasedOrder: stabilize reranked results
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
…urface comments Review follow-ups from the pre-merge rag-retrieval and clinical-governance reviewer passes: acknowledge in-code that the tie-break key carries the bounded source-governance terms (deliberate — conservative direction at ties), correct the snapshot-gate caveat (the gate keys on relevanceGrade metrics, not documentMatch flags), state which repro binds the tie-break versus the remediation stack, and add an end-to-end case proving an outdated/poor-extraction twin loses the saturated tie to the current document instead of winning it by chunk id. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EXsJcLrbZUXwnBeG91cVo9
…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
…rank score (#987) * fix(rag): break saturated selection ties by query-term coverage, not 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 * docs(ledger): record run-#50 finding and coverage tie-break review row Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EXsJcLrbZUXwnBeG91cVo9 --------- Co-authored-by: Claude <noreply@anthropic.com>
Summary
b3ae061this morning (run 29731533081) passed — golden retrieval 36/36 and the answer-quality subset green — confirming the same-day remediation (Fix repository regression findings #913–Fix residual audit findings #926) closed the live regression. That failing July-19 run had tested the rag: add deterministic and opt-in semantic reranking #901 state before any of those fixes landed; nobody had re-evaled since.score,lexicalScore, clampedrerankScore) all tie exactly and the chunk-id fallback decides the order arbitrarily — andsecondStageScore's position-based adjustment then launders that arbitrary winner intoreleaseRankScoreand the released order (in the repro this buried the CIWA answer document below a generic overview). Fix:RetrievalCandidatenow carriescontentRankScore(the content-aware clinical rank) used only as the tie-break between the clamped rerank confidence and the chunk-id fallback (src/lib/retrieval-selection.ts). It is never added to any score, so the measured clamped-score contract ("golden doc-recall@5 regressed 1.0 → 0.76 with unbounded boosts") is untouched — selection membership, per-document capping, and all non-tied orderings are unchanged.tests/rag-fast-path-ordering.test.tsreplays all four failed eval cases' shapes end-to-end through the production ordering pipeline (rankClinicalResults→selectRetrievalEvidence→applySecondStageRerankIfNeeded→stabilizeReleasedSearchOrder), including tag-wiring assertions for the fix(rag): restore bounded live retrieval reranking #919clinical_subjectguard and an input-order-independence check;tests/ranking-tuning.test.tsgains a gate holding the four golden-mapped hard negatives below the first relevant candidate at production weights, plus a full-snapshot high-risk assertion.a871dd7) and was never validated by any live eval (the only golden eval on rag: add deterministic and opt-in semantic reranking #901's state failed 4/36). It pinned exactly the chunk-id arbitrariness fixed here. Amended to the content-rank-then-id contract, with a new case proving identical content ranks still fall back to the stable chunk-id order.expectedDocumentSubstrings,expectedContentTerms,expectTableEvidence,clinicalDocumentAliases) is deliberately not touched — the passing baseline shows the identity-pinned cases resolve on the live corpus without alias changes.Verification
npm run test -- tests/rag-fast-path-ordering.test.ts tests/rag-second-stage-ranking.test.ts tests/retrieval-selection.test.ts tests/ranking-tuning.test.ts— 37/37npm run test— 2981 passed; sole failure is the long-baselined container-onlytests/pdf-extraction-budget.test.tschild-process artifact (hosted-CI-green through feat(pwa): retirement kill-switch, offline-version binding guard, and dev teardown flag #826–fix(ci): keep dispatched and scheduled CI runs alive through main churn #979)npm run verify:cheap— all 18 pre-test checks green (incl. lint, typecheck, knip, pr-policy/ci-scope/actions-pin self-tests); test step carries only the artifact abovenpm run check:production-readiness— substantive checks pass; the two FAILs are the documented missing-secret class in this secretless container (no Supabase/OpenAI env)npm run build+ client-bundle secret scan +npm run check:rag:fixtures(36 golden cases, 21 suites) — passUI verification not run: no UI surface changed (lib + tests only).
Risk and rollout
fd5dcd1(the ledger commit is documentation-only). No cache, schema, provider, or config surface is touched.rag_queriestelemetry rows.Clinical Governance Preflight
Clinical KB Database(sjrfecxgysukkwxsowpy) — no env/config changetests/onlyNotes
claude/clinical-kb-pwa-review-asi3wbserially after fix(ci): keep dispatched and scheduled CI runs alive through main churn #979 (ci.yml concurrency fix) merged; both changes belong to the same authorized closeout of the two parked release-gate items.docs/branch-review-ledger.mdcarries the full review row including the baseline-run forensics.🤖 Generated with Claude Code
https://claude.ai/code/session_01EXsJcLrbZUXwnBeG91cVo9
Generated by Claude Code
Summary by CodeRabbit