Skip to content

test(eval): recognize real Discharge Planning docs in golden alias - #206

Merged
BigSimmo merged 1 commit into
mainfrom
claude/remaining-supported-triage
Jul 2, 2026
Merged

test(eval): recognize real Discharge Planning docs in golden alias#206
BigSimmo merged 1 commit into
mainfrom
claude/remaining-supported-triage

Conversation

@BigSimmo

Copy link
Copy Markdown
Owner

Smallest safe fix for the admission-discharge-comparison golden failure (item #2 from triage).

Root cause

The golden fixtures reference synthetic MHSP.* filenames that no longer exist — the corpus was repopulated with real named documents. The clinicalDocumentAliases layer maps the old names to real ones, but the Discharge alias listed only "…to Discharge" mental-health variants, not the "Discharge Planning for Community Patients / Inpatients" documents that actually rank for this query. So the case reported a false top-5 recall miss on the non-existent MHSP.Discharge.pdf, even though a real, relevant discharge document ("Discharge Planning for Community Patients (NMHS).pdf") was retrieved and the answer was grounded.

Fix

Add "Discharge Planning" to the Discharge alias. Any "Discharge Planning …" document is unambiguously a discharge document, so this recognizes a genuine hit rather than masking a miss (the concern I flagged during triage).

Verification

  • admission-discharge-comparison now passes: grounded, 5 citations, no failures.
  • tests/eval-quality.test.ts 11/11; typecheck/lint/prettier clean.

Not included (deliberately): the NOCC and agitation-table failures are a separate, deeper issue — the deterministic document-list / table answers are mangled by the clinical-prose sanitizer (sanitizeStructuredText) they shouldn't run through. That has no small safe fix (the sanitizer is shared and load-bearing for real LLM prose), so it's left as a scoped follow-up rather than risking regressions.

🤖 Generated with Claude Code

… alias
The golden fixtures reference synthetic MHSP.* filenames that were superseded
when the corpus was repopulated with real named documents. Most alias-match, but
the Discharge alias listed only "…to Discharge" mental-health variants, not the
"Discharge Planning for Community Patients / Inpatients" documents that actually
rank for the admission-vs-discharge comparison. That made
admission-discharge-comparison report a false top-5 recall miss on the
non-existent MHSP.Discharge.pdf even though a real, relevant discharge document
was retrieved.
Add "Discharge Planning" to the Discharge alias. Any "Discharge Planning …"
document is unambiguously a discharge document, so this recognizes a genuine hit
rather than masking a miss. admission-discharge-comparison now passes (grounded,
5 citations); eval-quality unit tests 11/11.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@BigSimmo
BigSimmo merged commit 4df9ad4 into mainJul 2, 2026
4 checks passed
@BigSimmo
BigSimmo deleted the claude/remaining-supported-triage branch July 2, 2026 17:22
BigSimmo added a commit that referenced this pull request Aug 2, 2026
…+8) (#1576)
* DS V2 PR-E: answer safety, form foundation, announcements (slices 6+7+8)
Build the five specified safety components so a degraded answer, an absent
clinical value, an invalid field and a route change all become states the type
system and assistive technology can see.
Slice 6 - answer safety. VerificationNotice owns eight approved strings (four
states x clinician/plain); AnswerCard requires both `state: AnswerState` and
`verification`, and a degraded state cannot be constructed without the
`onOpenSource` route that turns the caution into an affordance. DoseLine takes a
structured dose model, composes Quantity, and marks overdue in three channels
(amber rule + "Source review overdue" + StatusMark shape). MissingValue replaces
the bare dash with four phrases. DateDisplay takes ISO only and renders <time>.
AnswerFooter now names an absent field instead of dropping it - on a provenance
strip the absence is the governance signal. answerClipboardText carries the
degraded caveat out of the app and routes provenance through the one existing
clipboardProvenanceLine() implementation.
Slice 7 - FormField/FieldHint/FieldError/ErrorSummary. Hint and error are both
in the DOM and both in describedBy when invalid; caller ids merge ahead of them
rather than being overwritten; required/optional is label text; ErrorSummary
takes focus rather than announcing.
Slice 8 - LiveAnnouncer/RouteAnnouncer/announce. One singleton owns every
announcement, with a dedupe window and a queue gap; route change moves focus to
the new <h1> unless focus sits inside a dialog or a preserve-focus workflow.
Step 0 contract pre-check passed with no change to src/lib/rag/** or
source-review: ready, stale_evidence and source_only all project from fields the
retrieval layer already decides, so no component infers staleness from a date.
partial_retrieval has no producer and is recorded as such in SPEC, COMPONENTS,
/issues #206 and tests/answer-state-contract.test.ts.
All components are built, not registered - registration and product adoption
stay in PR 13.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(ds-v2): tighten answer-safety states after clinical governance review
Eight findings from the PR 6 clinical governance review, all in code this
branch introduced, all safety-positive. No product surface imports any of
these modules yet, so nothing rendered changes.
Counting and identity
- answerStateFromRetrieval() counts and keys by document, not chunk.
RagAnswer.sources is chunk-level, so the previous projection produced
duplicate React keys, repeated a document as several overdue rows, and
reported fractions that were wrong in both directions — including the
direction that under-warns ("1 of 6" when half the documents are stale).
- Where chunks of one document disagree on governance status, the more
severe reading wins.
Governance status carried, not collapsed
- OverdueSource gains `status`, and DoseRow replaces the optional
`overdue` boolean with a required `status: DocumentStatus`. An overdue
status additionally requires `source`, so a warned row with no route
back to the document is unrepresentable. `outdated` (superseded) now
renders the slashed mark and the word "superseded" rather than the
half-ring "review overdue" vocabulary of a document still in force.
Cautions that cannot argue against themselves
- stale_evidence with an empty overdue list now throws in development
(mirroring the partial_retrieval guard) and, in production, states the
caution without a count instead of "0 of 3 sources are past their
review date". Same rule in answerClipboardText().
- VerificationNotice falls back to the most cautionary wording for an
unrecognised state, and logs once, rather than failing open to `ready`.
- The stale clinician wording says "some of which are past their review
date" rather than asserting every cited source is overdue.
- SourceOnlyBody no longer claims "nothing has been paraphrased": the
tier is inferred from the routing mode and the extractive builder
composes sections, so the surface cannot stand behind verbatim fidelity.
Provenance precision
- DateDisplay renders a date-only ISO as a date, even for kind="generated".
It previously printed "14/03/2026, 08:00" for "2026-03-14" — a precision
that was never recorded, on a provenance strip.
Clipboard (exceeds the original SPEC slice-8 scope, deliberately)
- answerClipboardText() now carries attribution and "Verify against the
linked source documents before clinical use." on every state including
`ready`, enumerates the cited documents, and suppresses the
single-document provenance line where it would contradict a
multi-source stale caveat. A copied answer loses the banner, the notice
and the links; unattributed clinical prose in a record reads as
clinician-endorsed. It remains narrower than formatAnswerRenderCopyText
and is not a replacement for it.
Recorded rather than fixed, so PR 13 cannot inherit them as clearance:
AnswerState has no channel for an ungrounded answer (#208), the clipboard
constraint above (#209), and the Gate 1 contrast pair for --warning at
text tier plus the per-process logged-once Sets (#210). All three are
also written into SPEC.md and COMPONENTS.md.
Co-authored-by: Cursor <cursoragent@cursor.com>
* chore(ledger): record PR-E answer-safety review at 8ad91e3
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(ds-v2): resolve PR-E review findings for answer safety
Filter staleness to cited supporting sources, reject rolled calendar dates,
make duplicate production announcers a no-op, re-focus ErrorSummary on
repeated submits, clear-then-set identical live announcements, and realign
AnswerCard/DoseLine dtsPropsFor declarations.
* fix(ds-v2): suppress duplicate LiveAnnouncer without lint cascade
Keep production duplicate ownership in an effect with a targeted
set-state-in-effect exemption, matching the repo pattern, so the
duplicate never registers a listener and unmounts its live regions.
* fix(ds-v2): address Copilot findings on banner and form tests
Import ComponentProps from react, require exact overdue/sourceCount
equality for the totality headline, and derive the partial-retrieval
numerator from the rendered missing list.
* fix(ds-v2): address CodeRabbit findings on answer-safety surfaces
Merge the broken OverdueSource doc comment, omit clipboard provenance
when metadata is absent, keep unidentified overdue sources as stale,
give ErrorSummary an accessible heading name, fail over LiveAnnouncer
ownership when the active instance unmounts, harden MissingValue phrase
lookup against prototype keys, and treat sourceCount underflow as totality.
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
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.

1 participant

@BigSimmo