Skip to content

Fix clinical dose-verification & safety gaps missed by early-merged #38#41

Merged
BigSimmo merged 1 commit into
mainfrom
fix/rag-dose-safety-on-main
Jun 19, 2026
Merged

Fix clinical dose-verification & safety gaps missed by early-merged #38#41
BigSimmo merged 1 commit into
mainfrom
fix/rag-dose-safety-on-main

Conversation

@BigSimmo

Copy link
Copy Markdown
Owner

Summary

PR #38 (22 RAG fixes) was merged early at ab27de3, before the 6 critical blocking safety fixes were added. Those fixes lived on fix/rag-pipeline-stage3-generation (26a8a6d) and never reached main. PR #39 (security/safety) and PR #40 (RAG/search) since landed but did not address any of B1-B6. This PR re-implements the still-missing blockers against current main.

Gap analysis — all 6 were still missing on main

ID Issue Status before this PR Action
B1 Substring dose match (2.5 mg12.5 mg) Still broken on main (despacedHaystack.includes(...)) Newly fixed — exact token-set membership, fails closed
B2 Unicode superscript ×10⁹/L mangled to 2.0×10 Still broken on main (no superscript folding) Newly fixed — fold ⁰¹²…⁹ → ASCII before extract/match
B3 Percentages never extracted (trailing \b after %) Still broken on main Newly fixed% branch no longer ends in \b
B4 Gate ignored answerSections[].body Still broken on main (scanned only answer.answer) Newly fixed — verify each section body, scoped to its citation_chunk_ids
B5 safeFallbackAnswer back-fills citations + grounded:true, skips numeric gate Still broken on main Newly fixed — fail closed (ungrounded, no citations) + run numeric gate; extractive recovery + strong-retry routing updated
B6 TOCTOU race in retry route (SELECT-then-unguarded-UPDATE) Still broken on main Newly fixed — single conditional UPDATE … WHERE status≠processing OR lock stale/null; 0 rows ⇒ 409
N1 Numeric fallback verified against ALL results Still on main Fixed — fail closed when no cited chunk maps to a result

None of B1-B6 were already addressed by #39/#40; #39/#40 only hardened the regex units and the warning text. All six were re-applied here, ported to main's diverged code (e.g. retry route keeps main's status:"pending", regex keeps main's mmol/[lL] units).

Empirical B1 verification (the top-priority dose fix)

Run against the new verifyAnswerNumbers:

answer="2.5 mg"  vs source="12.5 mg" => UNVERIFIED
answer="12.5 mg" vs source="12.5 mg" => VERIFIED
answer="500 mg"  vs source="1500 mg" => UNVERIFIED
answer="2.0"     vs source="12.0"    => UNVERIFIED

All four required outcomes confirmed — wrong doses now fail closed; exact doses verify.

Testing

  • npm run typecheck — passes
  • npm run lint — passes (0 errors; 1 pre-existing unrelated warning in src/lib/chunking.ts)
  • npm run test381 passed (55 files), including the new B1-B6/N1 regression tests
  • Targeted suites (answer-verification, rag-trust, private-access-routes) — 79 passed

New/updated regression tests cover: B1 (2.5↔12.5, 500↔1500, 2.0↔12.0 + exact match), B2 (superscript extract + superscript↔ASCII match), B3 (percentage extract + mismatch flag), B4 (section-body dose flagged / verified), B5 (fail-closed fallback + numeric gate on parse-failure prose), B6 (refuse fresh-processing 409 / allow stale-or-non-processing), N1 (fail closed on unmapped citation).

Do not merge without review. This is a medical app — the dose-faithfulness gate must fail closed.

🤖 Generated with Claude Code

…rged #38

Re-applies the 6 blocking clinical-safety fixes (B1-B6) on top of current
main. PR #38 merged 22 RAG fixes before these blockers landed, and #39/#40
did not address them, so main still trusts wrong doses.

- B1: numeric verification now matches by exact normalized token-set
  membership instead of substring, so "2.5 mg" no longer verifies against
  "12.5 mg" (5x dose error). Fails closed.
- B2: fold unicode superscripts (×10⁹/L) to ASCII before extraction/match.
- B3: percentage branch no longer ends in \b (which could never match), so
  percentages extract and percentage mismatches are flagged.
- B4: numeric gate now scans answerSections[].body (medication_dose),
  scoped to each section's citation_chunk_ids.
- B5: safeFallbackAnswer fails closed on parse failure (ungrounded, no
  citation back-fill) and still runs the numeric gate; extractive recovery
  and strong-retry routing updated accordingly.
- B6: retry route reset is a single conditional UPDATE guarded on
  status/locked_at; 0 rows affected => 409, closing the TOCTOU race.
- N1: verifyAnswerNumbers fails closed when no cited chunk maps to a result.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@BigSimmo
BigSimmo merged commit e135126 into main Jun 19, 2026
8 of 11 checks passed
@BigSimmo
BigSimmo deleted the fix/rag-dose-safety-on-main branch June 19, 2026 08:58
BigSimmo added a commit that referenced this pull request Jul 25, 2026
Resolve docs/outstanding-issues.md by keeping main's ledger and re-applying closures for #9 #10 #32 #41 #63 into Resolved/archive.

Co-authored-by: Cursor <cursoragent@cursor.com>
cursor Bot pushed a commit that referenced this pull request Jul 25, 2026
* docs: close ledger #9 #10 #32 #41 #63

Record ops-only /api/jobs decision, coming-soon audit, governance
ranking REFUTED guardrail, Factsheets reading-model brief, and Current
Clinical Work privacy/persistence brief. Archive the five open items;
no RAG or application behavior changes.

Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>

* fix(ci): prettier ledger docs and drop stale PR_POLICY_BODY

Static PR checks failed on Prettier for five docs files. Also remove
leftover PR_POLICY_BODY.md from merged #1134 so Sync PR policy body
stops overwriting this docs PR description.

Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>

* docs: record PR #1175 review ledger outcome

Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>

* chore: restore PR #1175 description via PR_POLICY_BODY sync

Temporary template so CI Sync PR policy body replaces the polluted
search-performance description left from merged #1134.

Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>

* chore: remove temporary PR_POLICY_BODY after description sync

Keep the corrected PR #1175 description without leaving the sync
template on the branch for merge to main.

Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>

* docs: supersede PR #1175 review ledger after body sync

Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>

* style: prettier-format outstanding-issues after ledger merge

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant