Skip to content

fix(rag): verify imperative dosing claims against descriptive guideline norms (packet S1c, R2+R3) - #2052

Merged
BigSimmo merged 6 commits into
mainfrom
claude/s1c-residuals-r2-r3-4pb1at
Aug 17, 2026
Merged

fix(rag): verify imperative dosing claims against descriptive guideline norms (packet S1c, R2+R3)#2052
BigSimmo merged 6 commits into
mainfrom
claude/s1c-residuals-r2-r3-4pb1at

Conversation

@BigSimmo

Copy link
Copy Markdown
Owner

Summary

  • R2 — directive-normativity strictness (packet S1c, ledger #6BG9X2):normativeDirectiveActions in src/lib/rag/rag-claim-support.ts gains one additional normative-signal disjunct recognising descriptive guideline norm phrasing — norm adjective → action form premodifying the dose noun (≤2 intervening words) → "is/are" → a digit within 16 characters, guarded by the existing !descriptiveContext flag and never crossing a .!?;: or newline boundary. An imperative claim such as "Start lithium at 500 mg nocte" now verifies against the EMHS guideline's "The usual oral starting dose for adults is 500 mg nocte …" instead of degrading the whole answer to source-only. Adversarial negatives pin that unrelated imperatives still fail: care-record prose ("Progress notes: … was started on lithium 500 mg nocte at this visit"), same-sentence and cross-sentence stop phrasing, incidental norm-adjacent action words ("A typical error is a repeated dose when the schedule is unclear", "The typical patient monitored on this dose is reviewed weekly"), a norm adjective without a dose noun, and a foreign-medication claim. The digit anchor and premodifier bound are load-bearing: looser shapes were constructed to false-positive on the repeat/monitor/stop sentences above and are pinned red.
  • R2 directionality pin: the function runs on claim and evidence alike, so a descriptive-norm claim ("The usual starting dose is 500 mg nocte") now also expects normative evidence and stops being supported by incidental care history ("Patients were started on an average dose of 500 mg nocte"). This is a fail-closed tightening and is pinned by its own test.
  • R3 — topic-overlap dilution (measured before loosening): the ≥50 % single-segment topic-overlap requirement in evidenceTextSupportsClaim may now count topic tokens lent by an immediately adjacent, atom-free segment of the same source representation. Every other gate — entities, foreign-medication binding, polarity, directive actions, safety dimensions, the high-risk trigger check, and clinical-value-atom containment — still evaluates against the single segment. Segments are grouped by representation (content / synopsis / per-table-fact / index unit) so flat-list neighbours across representation boundaries are never treated as adjacent. A neighbour carrying its own clinical value atoms is excluded from lending because it is a competing value context: this is what keeps the cross-bullet population/dose mis-binding claim ("For patients over 65 years, start lithium at 500 mg nocte" over adjacent Adults-500/over-65-250 bullets) rejected, pinned by a discriminating negative alongside non-adjacent-synthesis and alien-topic negatives.

R3 measurement (packet requirement, offline, instrumentation not committed): across the full offline contract corpus (eval:rag:offline, 25 suites / 613 tests) the overlap clause was the sole rejector of a claim/segment evaluation 87 times (46 unique pairs) at base. After the change: 78 / 42. The four lifted pairs are (1) the evidenced S1c R3 claim — the intended recovery — and (2–4) segment-level lifts inside fixtures whose asserted outcomes were already supported via another segment of the same source (convergent, no behaviour change at the fixture level). Protective flips: zero — every fixture asserting non-support still rejects; the full suite is green before and after (modulo the intended R3 recovery).

Non-inferiority argument (only false-positive rejections removed): every gate outside the two named artefacts is byte-identical. R2 can only mark an action normative when that action's surface form is already present in the evidence (the enclosing loop's pattern.test guard) and only under a digit-anchored norm-phrase shape; its claim-side growth is strictly fail-closed. R3 widens only the overlap ratio's token corpus, only from an immediately adjacent atom-free segment, with atoms/entities/directives/polarity/safety/trigger still single-segment; the measurement above shows zero protective rejections flipped. The post-merge canary pair validates live behaviour.

RAG impact: behaviour change — canary pair baseline run 32039841070 (92f7618, latest green) -> post-merge dispatch (owner-approved)

Verification

  • npm run verify:pr-local — heavy scope (RAG surface), decisive lines pasted below
  • npm run verify:ui — UI verification not run: no UI, routing, styling, or browser behaviour changed
  • npm run verify:release — not run: not a release/handoff-confidence claim
  • npm run eval:retrieval:quality — Verification not run: retrieval, ranking, selection, chunking, and scoring are untouched (claim-support gate only); live behaviour is covered by the owner-approved post-merge canary pair
  • npm run eval:rag -- --limit 15 / npm run eval:quality -- --rag-only — Verification not run: provider-backed; the owner-approved post-merge canary pair is the live gate for this change
  • npm run check:production-readiness — offline run; the only FAIL items are the expected provider capability gaps in a credential-free environment (missing NEXT_PUBLIC_SUPABASE_URL/SUPABASE_SERVICE_ROLE_KEY, missing OPENAI_API_KEY), not diff regressions

Decisive lines:

npx vitest run tests/rag-claim-support.test.ts → Tests 157 passed (157)
npm run eval:rag:offline → Tests 613 passed (613)
Offline RAG fixture and production-contract checks passed.
npm run check:rag:fixtures → Offline RAG fixture and manifest validation passed (36 golden cases, 25 suites).
npm run verify:pr-local → PR-local verification summary:
completed: check:runtime, check:installed-lock-parity, format:changed, lint, typecheck,
test, build, eval:rag:offline, check:medication-interactions, check:medication-lexicon-report
failed: (none) · not reached: (none)

Fail-first evidence: at the merge base (26f2459) the new R2 positive, R3 positive, and R2 claim-side pin were red (Tests 3 failed | 154 passed); after R2 alone 156 passed | 1 failed (the R3 positive); after R3 157 passed.

Risk and rollout

  • Risk: a widened claim-support acceptance on the grounding gate could, in principle, let a wrong high-risk claim read as supported. Bounded by: the enclosing action-form guard and digit-anchored shape (R2), the atom-free-adjacent-only lending with all other gates single-segment (R3), eleven adversarial negatives pinning the dangerous shapes, and the zero-protective-flip offline measurement. Residual (pre-existing, documented): condition-first population phrasing ("For patients over 65 years, …") is not extracted by the high-risk trigger check, so population↔value mis-binding within one segment that states both values in one sentence is not blocked by any gate; R2 makes that single-segment case reachable for dosing claims. Queued as a follow-up candidate rather than widened scope here (the trigger check is outside this packet's two named artefacts).
  • Rollback: single-commit revert of this squash; no data, schema, config, or dependency changes.
  • Provider or production effects: None in this PR. The post-merge eval-canary dispatch is provider-backed and owner-approved separately.

Clinical Governance Preflight

  • Source-backed claims still require linked source verification before clinical use
  • No patient-identifiable document workflow was introduced or expanded without explicit governance approval
  • Supabase target remains Clinical KB Database (sjrfecxgysukkwxsowpy)
  • Service-role keys and private document access remain server-only
  • Demo/synthetic content remains clearly separated from real clinical sources
  • Source metadata, review status, and outdated/unknown-source behavior remain conservative
  • Deployment classification/TGA SaMD impact was checked when clinical decision-support behavior changed

Notes

  • Packet S1c from docs/rag-improvement/HANDOVER.md; closes ledger #6BG9X2 (inbox done record queued in this PR). HANDOVER §2 S1c row updated in this PR per the update rule.
  • Hard boundaries respected: no grounding-gate weakening beyond the two named artefacts; no retrieval/ranking/selection edit; no budget change; rag-routing.ts (S1b), rag-extractive-answer.ts (S1d), and rag-row-contracts.ts/types.ts (G1) untouched.
  • The design-system adoption manifest hunk is pre-commit-hook regeneration (the new chart-record fixture text mentions "Progress").

Generated by Claude Code

…ne norms (packet S1c, R2+R3)
R2: normativeDirectiveActions gains a descriptive-norm disjunct — norm
adjective, action form premodifying the dose noun, and a digit-anchored
is/are — guarded by descriptiveContext, so guideline phrasing like 'the
usual oral starting dose for adults is 500 mg nocte' counts as normative
for an imperative claim. Adversarial negatives pin care-record prose,
unrelated imperatives, incidental norm-adjacent action words, and
foreign-medication claims as still unsupported.
R3: the >=50% topic-overlap requirement may count topic tokens lent by an
immediately adjacent atom-free segment of the same source representation;
atoms, entities, polarity, directives, safety dimensions, and the trigger
check still bind to the single segment. Measured offline before loosening:
87 -> 78 sole-overlap rejections (46 -> 42 unique), the only outcome-level
recovery being the evidenced two-bullet synthesis claim; zero protective
fixture flips across the 613-test offline corpus. Discriminating negatives
pin cross-bullet dose mis-binding, non-adjacent synthesis, and alien-topic
claims as still unsupported.
The design-system adoption manifest is regenerated by the pre-commit hook
(the new chart-record fixture mentions 'Progress').
Closes ledger #6BG9X2 (packet S1c, HANDOVER §3).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TNq5LiNDoZVaggA3mHBT5Q
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@supabase

supabaseBot commented Aug 17, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

coderabbitaiBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in:1 minute

Limit details: You’ve used all 1 included review currently available under your plan. You completed 94 included PR reviews in the past 7 days; at that activity level, included reviews refill at 1 review per hour.

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6290ffe7-a25f-4000-a233-5984cfc8c3d1

📥 Commits

Reviewing files that changed from the base of the PR and between 093f934 and fb9ccca.

📒 Files selected for processing (6)
  • docs/branch-review-records/a8521fd05bde007f6203e4cdd7fee80e20e0dbfc7f8d3d99fc588dfef30b50fe.record.md
  • docs/design-system/adoption-manifest.json
  • docs/outstanding-issues-inbox/632c50f9-6e6a-4247-8b75-11572137e579.json
  • docs/rag-improvement/HANDOVER.md
  • src/lib/rag/rag-claim-support.ts
  • tests/rag-claim-support.test.ts

Comment @coderabbitai help to get the list of available commands.

…#6BG9X2 closure (PR #2052)
The inbox done request is emitted through the repo inbox schema and
validated with the module's own validateRequest/applyRequest because
npm run issues:done rejects ULID display ids (issueRowFingerprint
matches numeric ids only) — noted in the request outcome as a tooling
follow-up.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TNq5LiNDoZVaggA3mHBT5Q
…r2-r3-4pb1at
# Conflicts:
#	docs/rag-improvement/HANDOVER.md
@BigSimmo
BigSimmo enabled auto-merge August 17, 2026 16:49
@github-actions

Copy link
Copy Markdown
Contributor

CI triage

CI failed on this PR. Automated classification of the 3 failed job(s):

  • Unit coverageneeds investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.
  • Lighthouse budgetneeds investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.
  • PR requiredneeds investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.

Compared with main CI run #11488 (success).

Classification is evidence routing, not permission to ignore a failure. Exact quarantined Playwright identities remain governed by the flake ledger.

…r2-r3-4pb1at
# Conflicts:
#	docs/rag-improvement/HANDOVER.md
@BigSimmo
BigSimmo merged commit b8e774b into mainAug 17, 2026
24 checks passed
@BigSimmo
BigSimmo deleted the claude/s1c-residuals-r2-r3-4pb1at branch August 17, 2026 17:22
BigSimmo pushed a commit that referenced this pull request Aug 18, 2026
While this PR was open, a concurrent session landed an equivalent fix on
main as 049760a ("fix(theme): clear and guard the theme-transition
removal timer"), root-caused on PR #2052. Its implementation is
functionally identical to the one here: same `typeof document ===
"undefined"` early return, same tracked handle cleared before scheduling.
Keeping a second, cosmetically different version of the same fix would be
pure churn and a conflict magnet, so use-theme.ts is reverted to main's
version byte-for-byte. What main does NOT have is any regression test for
this behaviour, so that is all this PR now carries.
The test was re-verified against main's implementation rather than the
one it was written for: it passes 3/3, and removing main's guard turns it
red with the original `ReferenceError: document is not defined`. So it
genuinely guards the code that shipped.
This duplication is the failure mode tracked as outstanding issue #292 —
two assistants building the same thing because neither checked the open
PR list first.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UYndHWrYJzirxbBvt68Tmx
Sign up for freeto 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.

2 participants

@BigSimmo@claude