fix(rag): verify imperative dosing claims against descriptive guideline norms (packet S1c, R2+R3) - #2052
Conversation
…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
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. 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 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 configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
Comment |
…#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
CI triageCI failed on this PR. Automated classification of the 3 failed job(s):
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
…t' into claude/s1c-residuals-r2-r3-4pb1at
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
Summary
#6BG9X2):normativeDirectiveActionsinsrc/lib/rag/rag-claim-support.tsgains 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!descriptiveContextflag 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.evidenceTextSupportsClaimmay 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.testguard) 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 belownpm run verify:ui— UI verification not run: no UI, routing, styling, or browser behaviour changednpm run verify:release— not run: not a release/handoff-confidence claimnpm 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 pairnpm 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 changenpm run check:production-readiness— offline run; the only FAIL items are the expected provider capability gaps in a credential-free environment (missingNEXT_PUBLIC_SUPABASE_URL/SUPABASE_SERVICE_ROLE_KEY, missingOPENAI_API_KEY), not diff regressionsDecisive lines:
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 alone156 passed | 1 failed(the R3 positive); after R3157 passed.Risk and rollout
Clinical Governance Preflight
Clinical KB Database(sjrfecxgysukkwxsowpy)Notes
docs/rag-improvement/HANDOVER.md; closes ledger#6BG9X2(inboxdonerecord queued in this PR). HANDOVER §2 S1c row updated in this PR per the update rule.rag-routing.ts(S1b),rag-extractive-answer.ts(S1d), andrag-row-contracts.ts/types.ts(G1) untouched.Generated by Claude Code