Retrieval correctness: repair #325 golden regression, corpus-grounded finding #11 fix, RC9 confidence hardening - #343
Merged
Conversation
PR #325 merged with its golden retrieval eval unrun (no live keys in the authoring environment). Run live against the same corpus, pre-#325 code passes all 34 cases while main fails 3; both flagged changes regressed: - Weak-match OR-augmentation (default on) buried opioid-withdrawal-doses (docRecall@5 1.0 -> 0.0): OR recall is append-only at the RPC merge but not after re-ranking, so generic OR matches displace the expected document. RAG_TEXT_WEAK_OR_RELAXATION now defaults to false and is an opt-in experiment flag gated on a fresh full golden run. - The selectRetrievalEvidence pre-clamp tiebreak buried alcohol-ciwa-threshold and clozapine-cbc-abbreviation-threshold: ordering saturated ties by boost-stacking magnitude re-picks which tied candidate wins. Removed; the eval-proven pre-clamp deep tiebreak lives in rankClinicalResults below the engineered rankingTieBreakScore (PR #218) and stays. Golden retrieval eval after fix: 34/34, top_k_hit_rate=1, failed_cases=0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…inding #11) Valid bare topics ("bipolar disorder", "anorexia management") intermittently returned 0 results because the nondeterministic LLM classifier decided the unsupported soft tail. The corpus now decides first, deterministically: - New corpus_topic_term_stats RPC (migration 20260707100000, applied live; service_role-only, read-only) reports per query term: title-topic membership (documents_title_search_idx), chunk-level presence, and scoped corpus size — scoped exactly like retrieval (retrieval_owner_matches + status='indexed' + committed generation). - src/lib/corpus-grounding.ts classifies soft-tail queries: a title-topic anchor under a 5% genericity ceiling (measured live: "management"/"guideline" headline ~18-20% of titles; real topics <=3%) with no corpus-absent token => deterministic reclassification to broad_summary (mirrors an accepted classifier verdict, minus the coin flip); any corpus-absent token => skip the LLM so the soft-tail refusal is deterministic (trigram correction preserved); inconclusive / DB error / unapplied migration => legacy memoized-LLM path. - Scoped strictly to the soft-tail branch: pattern-guarded refusals (DKA, pneumonia, SSRI, consumer noise) and every higher-confidence class are untouched by construction. - Eval controls: golden cases bare-topic-bipolar / bare-topic-anorexia (rank-1 live) and invented-term ragEvalCases unsupported-invented-florbizone / unsupported-invented-quxbyria. Verified live: 4/4 identical runs per query (answer vs refuse), golden retrieval eval 36/36 (failed_cases=0), corpus_grounding telemetry recorded. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…confidence Consumer audit of the synthetic text similarity (findings item 21, updated): the headline least(0.95, 0.56 + text_rank*0.39) proxy no longer exists — match_document_chunks_text already returns similarity 0 with hybrid capped at 0.5. Three app-side fabricators remain (document-lookup fast path, memory-card chunk loader, table-fact signal matches), all tagged synthetic_text; their 0.58-floor values are deliberately load-bearing in route/coverage gates (always paired with structural checks), so re-gating those on native signals stays deferred to the telemetry-backed recalibration. The one provable defect is fixed: deriveConfidence let a fabricated 0.82+ (memory-card hybrid reaches 0.89, document-lookup 0.94) grant a "high" clinician-facing confidence label from purely lexical evidence. "high" now requires a genuine-cosine citation; synthetic-origin evidence caps at "medium". Strictly tightening; ordering, routing, and coverage gates untouched. Unit tests in tests/rag-score.test.ts. Also documents why the RC6 alias-group seed (workstream task 5) is deferred: the groups live in the synchronous analyzer while rag_aliases rows flow through the variant/short-circuit path — seeding both double-expands and changes behaviour corpus-wide, so it needs its own eval-gated change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Since the 2026-07-06 public promotion the whole corpus is owner_id NULL; a real RAG_EVAL_OWNER_ID scopes retrieval to zero documents and fails every golden case (observed as a 34-case wipeout before diagnosis). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Updates to Preview Branch (claude/retrieval-correctness) ↗︎
Tasks are run on every commit but only new migration files are pushed.
View logs for this Workflow Run ↗︎. |
BigSimmo
marked this pull request as ready for review
July 7, 2026 03:16
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
BigSimmo
enabled auto-merge
July 7, 2026 05:18
15 tasks
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Jul 7, 2026
BigSimmo pushed a commit
that referenced
this pull request
Jul 8, 2026
…h gate Adds the 2026-07-08 follow-up: DEFAULT_EVAL_OWNER_ID + resolveEvalOwnerId() are now shared across all read/eval scripts (item 1), with a one-line sentinel-fallback warning (item 3). Records the live eval:quality --rag-only result closing #347's answer-path gate (item 2): cases=44, unsupported_correct=1.0, citation_failure=0.0455, numeric_grounding=0.0227 (all identical to #343 baseline); grounded_supported=0.90, with the 5 failing cases all in #343's documented latency/route live-variance set. Corrects the earlier overstatement so #348 reads as closing the retrieval half only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BdP9DwsGdvtEvyVh3juYZ5
14 tasks
7 tasks
BigSimmo added a commit
that referenced
this pull request
Aug 18, 2026
This was referenced Aug 18, 2026
Merged
Merged
BigSimmo added a commit
that referenced
this pull request
Aug 20, 2026
A new P3 task landed on main after this PR's earlier reconcile: the B4 shadow-extraction Gate F runbook (docs/worker-deploy-runbook.md section 3) has four operator unknowns the repo can't answer -- Railway variable-change restart behaviour, no read path for documents.metadata.shadow_extraction, an unratified 10% timeout rollback threshold, and unverified worker memory headroom. This lands after the main-sync merge that brought it in; the #343/#318 requests queued earlier in this branch are still deliberately left pending for the same reason recorded in the earlier reconcile commit.
BigSimmo added a commit
that referenced
this pull request
Aug 20, 2026
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 freeto 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.
Retrieval correctness workstream
Branch:
claude/retrieval-correctness. Every behavior change below was gated live againstClinical KB Database(sjrfecxgysukkwxsowpy, 2065 public docs) withRAG_EVAL_OWNER_ID=00000000-0000-0000-0000-000000000000(the public-owner sentinel — the corpus went all-public on 2026-07-06, so the old real-UUID eval owner scopes to zero documents; runbook updated expectation).Commit 1 — repair PR #325 golden-eval regression (task 0, unplanned)
PR #325 merged with its golden eval unrun (documented eval debt). Settling that debt found main at 31/34. Isolated against the same live corpus (pre-#325 code passes all three):
opioid-withdrawal-doses(docRecall@5 → 0.00): OR recall is append-only at the RPC merge but not after re-ranking. →RAG_TEXT_WEAK_OR_RELAXATIONnow defaults off (opt-in experiment flag; re-enable only behind a fresh full golden run).selectRetrievalEvidencepre-clamp tiebreak buriedalcohol-ciwa-threshold+clozapine-cbc-abbreviation-threshold: "tie-only by construction" still changes which saturated candidate wins. → removed; the eval-proven pre-clamp deep tiebreak lives inrankClinicalResultsbelow the engineeredrankingTieBreakScore(PR fix(rag): deterministic ranking tiebreak + alias cache hardening (Phase 1) #218) and stays. Regression-guard unit test replaces Universal search: fix core RAG search defects and federate medications/services/forms/differentials/tools into one cross-entity search #325's test.Golden after fix: 34/34, top_k_hit_rate=1, failed_cases=0.
Commit 2 — finding #11: corpus-grounded relevance (task 2)
The unsupported soft tail is now decided by the corpus, not the LLM classifier lottery:
corpus_topic_term_statsRPC (migration20260707100000, applied live; read-only, additive, service_role-only, scoped exactly like retrieval:retrieval_owner_matches+status='indexed'+ committed generation).src/lib/corpus-grounding.ts: title-topic anchor under a 5% genericity ceiling (measured live: "management" 18.2% / "guideline" 19.6% of titles = scaffolding; real topics ≤3%: assessment 3.0%, disorder 1.6%, bipolar/anorexia <0.1%) + chunk-absence as the invented-term signal. In-corpus bare topic → deterministicbroad_summaryreclassification; corpus-absent token → LLM skipped, deterministic soft-tail refusal (trigram-correction escape hatch preserved); inconclusive/DB-error/missing-RPC → legacy behaviour (fail-open).bare-topic-bipolar/bare-topic-anorexia(must answer, rank-1 live) andragEvalCasesunsupported-invented-florbizone/unsupported-invented-quxbyria(must refuse).Live determinism probe (4 runs each, identical outcomes):
Commit 3 — RC9: fabricated similarity vs answer confidence (task 3)
Full consumer audit (recorded in
docs/rag-hybrid-findings-and-todo.mditem 21): the headlineleast(0.95, 0.56 + text_rank*0.39)proxy no longer exists —match_document_chunks_textalready returnssimilarity=0with hybrid capped at 0.5. The three remaining app-side fabricators (document-lookup fast path, memory-card chunks, table-fact signal matches) are taggedsynthetic_text; their 0.58-floor values are deliberately load-bearing in route/coverage gates (always paired with structural checks), so re-gating those on native signals stays deferred to the telemetry-backed recalibration (item 21).Fixed the one provable defect:
deriveConfidencelet a fabricated 0.82+ (memory-card hybrid ≤0.89, document-lookup ≤0.94) mint a "high" clinician-facing confidence label from purely lexical evidence. "high" now requires a genuine-cosine citation; synthetic-origin evidence caps at "medium". Strictly tightening; ordering/routing/coverage untouched.Tasks 1 & 4 — already on main (verify-only)
classifierVerdictMemo, NFKC-normalized keys, in-flight dedup, errors-not-memoized, 5 unit tests). Verified complete; corpus grounding now supersedes it for the soft tail and the memo remains for inconclusive verdicts.rankClinicalResultshas carried the pre-clamp deep tiebreak belowrankingTieBreakScoresince PR fix(rag): deterministic ranking tiebreak + alias cache hardening (Phase 1) #218 (eval-gated). The additional selection-layer copy from Universal search: fix core RAG search defects and federate medications/services/forms/differentials/tools into one cross-entity search #325 was the regression removed in commit 1.Task 5 — deferred with design note
Seeding
synonymGroups/domainAliasGroups/medicationAliasGroupsintorag_aliasesis not a data chore: the groups live in the synchronous analyzer (demo/test-safe) whilerag_aliasesrows flow through the variant + short-circuit-guard mechanism — seeding both double-expands and changes behaviour corpus-wide. Documented in findings item 10; needs its own eval-gated change.Eval summaries (live)
Golden retrieval eval — baseline on main (before commit 1)
Golden retrieval eval — after commit 1
Golden retrieval eval — after commits 2+3 (36 cases incl. new bare-topic controls)
eval:quality --rag-only — baseline (after commit 1, before commits 2+3)
eval:quality --rag-only — final head (44 cases incl. the 2 new invented-term controls)
Both new invented-term controls (
unsupported-invented-florbizone,unsupported-invented-quxbyria) pass (deterministic refusal viaout_of_corpus).Case-level deltas vs baseline are pre-existing live variance on cases outside the touched paths:
unsupported-close-title-noise(route flake in baseline) now passes;assessment-documentation/illegal-substancesflipped to "unexpected route strong" — both classifydocument_lookupat 0.73/0.78 confidence withneedsClassifierFallback=false(probed), so they never reach the classifier fallback, soft tail, or corpus grounding. The recurringlatency over 20000msfailures are local-machine→remote-DB latency (prod is co-located; same set failed at baseline).verify:cheap (rebased head)
Notes
.env.localrecovery + key rotation: the live Supabase keys were rotated twice (Jul 5 legacy-disable, Jul 6rotated_20260706); the current secret was recovered via the authenticated Supabase CLI--revealand never pasted into chat.corpus_topic_term_statsmigration was applied to live via the MCP migration mechanism with content identical to the committed file (additive, read-only, service_role-only; verified against probe terms before wiring).universal-search.test.ts) sat at the 15s global timeout edge under load; bumped that first test (and the new corpus-grounding first test) to 60s.🤖 Generated with Claude Code