Skip to content

fix(calculators): carry a scope line with every score, and with the score that leaves the app - #2505

Merged
BigSimmo merged 4 commits into
mainfrom
claude/design-system-app-review-sxd0mm
Sep 1, 2026
Merged

fix(calculators): carry a scope line with every score, and with the score that leaves the app#2505
BigSimmo merged 4 commits into
mainfrom
claude/design-system-app-review-sxd0mm

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Closes the Calculators half of the clinical over-claim sweep that produced #2497 and #2499. Two real gaps, verified against the current source after #2491's safety work — and one reported gap that turned out not to exist.

Summary

  • The copied result was a bare assertion. formatResultSummary produced PHQ-9 18/27 — Moderately severe and nothing else. That text leaves the app on the clipboard, so it is the one place a score is read with none of the interface around it: pasted into a note or a letter it reads as an assessment result the software stands behind, with no instrument attribution and no caveat. Same defect class as the differential summary in src/lib/differential-detail.ts, corrected in fix(clinical): stop four surfaces calling themselves decision support, and pin two drifting design-system documents #2497 for the same reason. The score line now carries "Clinical reference — not validated decision support. Confirm scoring and interpretation against the source instrument."
  • The scoring sheet had no standing scope line. caution is set on one of the five released instruments (PHQ-9's item-9 suicide-risk prompt). The other four — GAD-7, K10, CAGE, AUDIT-C — showed a score, a severity label and a band legend with no caveat in view. The catalogue's existing "Scores support clinical judgement — they never replace a full assessment" note lives in the sidebar of the page behind the sheet, and the sheet is a modal, so it is not readable at the moment the score is. ScorePanel now carries the standing line beside the scoring note.

What was reported but is not a defect

The sweep flagged the heading "Validated psychiatry scores with the indication, items, and interpretation in one place" as the app asserting validation in its own voice. It is in directory-grid.tsx, which exports CalculatorsDirectoryGridMockup — design scratch that 404s in production and is exempt by policy. The production heading copy lives in ui-copy.ts, and #2491 already rewrote it to describe "scoring guidance, limitations, safety prompts, and source-linked clinical considerations", pinned by a test asserting it does not claim all tools are validated. Nothing to fix.

The sweep's broader claim that no scope line existed anywhere in Calculators was also wrong — AboutPanel has carried one since before this change. Only one of the seven files it listed (search-page.tsx) is production at all; the rest export …Mockup. The real gap was narrower and worse than reported: not the catalogue, but the sheet and the clipboard.

Verification

  • Full unit suite — 940 test files, 11,834 tests passed, 1 skipped, 0 failures.
  • npm run verify:cheapexit 0.
  • npm run lint, npm run typecheck — clean, both re-run after merging main (which changed the typecheck config in Keep the source typecheck out of Next's build output again (#210) #2501).
  • Both guards mutation-verified: removing the ScorePanel line fails the clinical-safety suite; returning the copy text to a bare score fails three assertions in calculator-scoring.

The guards are written not to pass by coincidence: the copy-text guard iterates a range of scores and asserts two lines with the caveat last, and the sheet guard iterates every released instrument that sets no caution rather than naming one — so an instrument gaining or losing a caution cannot silently hollow it out. The first draft of that guard asserted PHQ-9 had no caution, which was wrong; it does, and the failure is what surfaced the accurate one-of-five count.

UI verification not run: both changes are static copy inside existing elements with no layout, routing or state change, and DOM assertions covering both render paths run in the suite above.

Risk and rollout

  • Risk: low, and in the safe direction — both changes add a caveat and remove no information. The copied text gains a second line, which is a deliberate change to the shape of a string the clipboard carries; its consumers are one production call site plus three mockups, and its tests are updated to match.
  • Rollback: single-commit revert. No migration, no data change, no schema or behaviour change.
  • Provider or production effects: None. Every gate run was local and offline.
  • RAG impact: none — no retrieval, ranking, eval or fixture path is touched.

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

Each item is addressed below; the boxes keep the exact template text because scripts/pr-policy.mjs matches them literally.

Governance detail

  1. Linked source verification — strengthened. The new lines name the action ("confirm scoring and interpretation against the source instrument"), and ScorePanel's existing evidence-source links are untouched.
  2. Patient-identifiable workflow — none. Calculator answers stay in the browser session; that boundary statement is unchanged and still asserted by its own test.
  3. Supabase target — no Supabase configuration, migration or environment value is touched.
  4. Service-role keys / private document access — no API route, auth path or key handling is touched.
  5. Demo/synthetic separation — unchanged. The released set is still gated on instrumentStatus, rights.status, evidenceStatus and releaseStatus.
  6. Source metadata and conservative unknown-source behaviour — unchanged; no governance, review-status or freshness logic is touched.
  7. Deployment classification / TGA SaMD — checked. No behaviour changes and no scoring, banding or next-action logic is touched. The change makes the software claim less for its output at the two points where it previously claimed most: a score read in isolation, and a score pasted outside the app. That moves the surface toward the product's stated scope as a clinical reference prototype, not away from it.

Generated by Claude Code


Note

Low Risk
Copy-only and static disclaimer copy; scoring, banding, and clinical logic are unchanged.

Overview
Adds a standing clinical scope disclaimer wherever calculator scores are shown or copied, so bare severity lines are not read as validated decision support.

Clipboard: formatResultSummary now appends a second line — "Clinical reference — not validated decision support. Confirm scoring and interpretation against the source instrument." — after the score/band (and incomplete progress when applicable). Copy-to-clipboard therefore carries the same caveat as in-app framing.

Score sheet: ScorePanel shows that same line under the scoring note for every instrument, including those without a per-instrument caution, while the modal sheet hides the catalogue’s broader judgement note.

Tests: Unit expectations for summary text are updated, plus guards that pasted summaries are always two lines ending with the scope text, and that every released calculator without caution still renders the line in ScorePanel.

Reviewed by Cursor Bugbot for commit 62e1fa3. Configure here.

…core that leaves the app

Two gaps in the Calculators mode, found by a clinical over-claim sweep and
verified against the current source after #2491's safety work.

The copied result was a bare assertion

`formatResultSummary` produced `PHQ-9 18/27 — Moderately severe` and nothing
else. That text leaves the app on the clipboard, so it is the one place a score
is read with none of the interface around it — pasted into a note or a letter it
reads as an assessment result the software stands behind, with no instrument
attribution and no caveat. Same defect class as the differential summary in
src/lib/differential-detail.ts, corrected in #2497 for the same reason. The
score line now carries "Clinical reference — not validated decision support.
Confirm scoring and interpretation against the source instrument."

The scoring sheet had no standing scope line

`caution` is set on ONE of the five released instruments (PHQ-9's item-9
suicide-risk prompt). The other four — GAD-7, K10, CAGE, AUDIT-C — showed a
score, a severity label and a band legend with no caveat in view. The
catalogue's existing "Scores support clinical judgement — they never replace a
full assessment" note lives in the sidebar of the page BEHIND the sheet, and the
sheet is a modal, so it is not readable at the moment the score is. ScorePanel
now carries the standing line beside the scoring note.

What was NOT changed, deliberately

The sweep also reported the heading "Validated psychiatry scores with the
indication, items, and interpretation in one place" as the app asserting
validation in its own voice. It is in directory-grid.tsx, which exports
`CalculatorsDirectoryGridMockup` — design scratch that 404s in production, and
exempt by policy. The production heading copy lives in ui-copy.ts and #2491
already rewrote it to describe "scoring guidance, limitations, safety prompts,
and source-linked clinical considerations", pinned by a test asserting it does
not claim all tools are validated. Nothing to fix there.

The sweep's claim that no scope line existed anywhere in Calculators was also
wrong: AboutPanel has carried one since before this change. The real gap was
narrower and worse — the two places above.

Verification

Full unit suite 939 files / 11,818 tests passed, 1 skipped, 0 failures. lint and
typecheck clean. Both new guards mutation-verified: removing the ScorePanel line
fails the clinical-safety suite, and returning the copy text to a bare score
fails three assertions in calculator-scoring. The copy-text guard iterates the
score range rather than pinning one value, and the sheet guard iterates every
released instrument that sets no caution, so neither passes by coincidence.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015uQ7pGjA4hBxi9TRNsfjAL
@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 64e7d242-91e5-4063-873b-af3466cc045a


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@supabase

supabase Bot commented Sep 1, 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 ↗︎.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 1, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-01T13:33:29.359490Z 62e1fa3 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@cursor

cursor Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_67a195ca-cd6c-4022-9851-30c5dc7fd43a)

@BigSimmo
BigSimmo enabled auto-merge September 1, 2026 13:25

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 62e1fa3624

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/components/calculators/search-detail.tsx Outdated
@BigSimmo

BigSimmo commented Sep 1, 2026

Copy link
Copy Markdown
Owner Author

@codex resolve actionable Codex review findings for this pull request and current head using the repository instructions. This is the pull request's single automatic repair pass: do not perform a fresh review, create new standalone findings, or request another review. Work only the existing unresolved Codex threads on the current head. The only repository destination is BigSimmo/Database, and the only branch destination is the pull request head branch claude/design-system-app-review-sxd0mm at starting commit 62e1fa3; never publish fixes to a detached or synthetic work branch and never create a stacked pull request. Use the authenticated GitHub connector to commit each approved fix to BigSimmo/Database:claude/design-system-app-review-sxd0mm, then verify that the pull request head contains the published commit before reporting success. Always fix P0 and P1 findings. For P2 and lower findings, fix only clear, scoped, low-risk issues; otherwise disposition them with a concise reason. For a fixed thread, reply with as the first line and as the second line. For a no-code disposition, use followed by . These result markers authorize the workflow to close that exact thread only after it verifies a fixed commit is the pull request head; a local-only commit is not a fix. If publication or verification fails, do not use either result marker, do not claim success, and leave the thread open with the blocker. If human input or new authorization is required, do the same. Finish only after every actionable thread is fixed or dispositioned and closed, or explicitly left open for a human decision. Do not update the branch from main, address unrelated reviews, broaden scope, or create more than one scoped fix commit. Do not use external APIs, paid services, credentials, dependency changes, or broad refactors unless explicitly authorized. Add targeted tests where behavior changes and run the narrowest relevant validation.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

Reviewed commit: 62e1fa3624

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

…of the scroll body

Codex P2 on #2505, verified and correct. The first placement did not achieve what
the change was for.

`CalculatorSheet` renders a pinned live strip — running score, progress, severity
pill, band bar — above a scrolling body, and `ScorePanel` is the LAST thing in
that body, after the indication, the items and the next-actions panel. So while a
clinician works through a nine-item instrument watching the running score, the
caveat sat below the fold. The score was still read without it, which is the
defect this change exists to close.

The line now lives in the live strip, directly under the band bar, so it is
visible for exactly as long as the score is. Removed from `ScorePanel` rather
than duplicated: two identical sentences in one modal is noise, and in production
`ScorePanel` only ever renders inside this sheet.

The test was weak in the same way and is rewritten

It rendered `ScorePanel` alone, so it could not have caught this: any placement
inside that component passes. It now renders the whole `CalculatorSheet` and
makes the decisive assertion structural — the line must NOT be contained by the
scrolling region — rather than merely asserting the text exists somewhere.

Mutation-verified twice over: moving the line back into the scroll body fails it,
and removing the line entirely fails it. The previous version of this test passed
in the first of those two cases, which is precisely the hole Codex found.

jsdom implements no scroll methods and the sheet resets scroll position on mount,
so `Element.prototype.scrollTo` is stubbed for the duration and restored after —
stubbed rather than skipped, because the placement assertion is the point.

Verification

Full unit suite 940 files / 11,834 tests passed, 1 skipped, 0 failures.
verify:cheap exit 0; lint and typecheck clean.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015uQ7pGjA4hBxi9TRNsfjAL

BigSimmo commented Sep 1, 2026

Copy link
Copy Markdown
Owner Author

Codex P2 (Put the scope line beside the persistent live score) — verified and fixed in b75c73560.

The finding is correct, and it is the substantive kind: the original placement did not achieve what the change was for.

CalculatorSheet renders a pinned live strip — running score, progress, severity pill, band bar — above a scrolling body, and ScorePanel is the last element in that body, after the indication, the items and the next-actions panel. So while a clinician works through a nine-item instrument watching the running score, the caveat sat below the fold. The score was still being read without it.

Fix: the line now sits in the live strip directly under the band bar, so it is visible for exactly as long as the score is. Removed from ScorePanel rather than duplicated — two identical sentences in one modal is noise, and in production ScorePanel only ever renders inside this sheet.

The test was weak in the same way, and that is the more useful half of this finding. It rendered ScorePanel alone, so it could not have caught the placement problem: any position inside that component passes. It now renders the whole CalculatorSheet and makes the decisive assertion structural — the line must not be contained by the scrolling region — instead of merely asserting the text exists somewhere.

Mutation-verified twice: moving the line back into the scroll body fails it, and removing the line entirely fails it. The previous version of the test passed in the first of those cases, which is exactly the hole this comment identified.

Element.prototype.scrollTo is stubbed for the duration and restored afterwards, since jsdom implements no scroll methods and the sheet resets scroll position on mount — stubbed rather than skipped, because the placement assertion is the point of the test.

Full suite 940 files / 11,834 tests passed, 1 skipped, 0 failures; verify:cheap exit 0; lint and typecheck clean.


Generated by Claude Code

@BigSimmo
BigSimmo disabled auto-merge September 1, 2026 14:14
@BigSimmo
BigSimmo enabled auto-merge (squash) September 1, 2026 14:14
@BigSimmo
BigSimmo merged commit cdbfd4a into main Sep 1, 2026
29 checks passed
@BigSimmo
BigSimmo deleted the claude/design-system-app-review-sxd0mm branch September 1, 2026 14:19
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.

2 participants