feat(therapy): expose Therapy in production ahead of clinical sign-off - #2145
feat(therapy): expose Therapy in production ahead of clinical sign-off#2145BigSimmo wants to merge 7 commits into
Conversation
Queued at the owner's direction while Therapy is made production-visible ahead of clinical review. Three gaps it records: - `reviewStatus` is a bare string, so a record can be flipped to `reviewed` with all seven `reviewChecklist` booleans still false and nothing detects it. - No attribution: none of the 44 record fields carries `reviewedBy` or `reviewedAt`, the same defect `#318` flags against the medication interaction lexicon. - No review workflow: 205 records x 7 checks is 1435 clinical judgements by hand. Carries an explicit stop rule that an assistant must never tick the five clinical checks — those are qualified-clinician attestations — while `proofread` and `australianEnglishChecked` are non-clinical and may be done with attribution. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Therapy was gated out of production by two mechanisms: `devOnly: true` on the mode, which hid the entrance and made the generic route guard 404 the routes, and a record filter that served only `reviewStatus === "reviewed"`. With all 205 records `needs_review`, that meant an invisible mode over an empty library. The owner lifted both on 2026-08-18, deliberately and with the numbers in hand: 205 records, 0 reviewed, 1435 unticked checklist items. This is a private clinical reference tool and that exposure call is theirs. What was NOT done, because it would have been the easy way to the same screen: no record was relabelled. `reviewStatus` still reads `needs_review` on all 205. Marking them reviewed would have been a false clinical attestation rather than a product decision, and it would have destroyed the only signal a reader now has. The record filter is switched off by a named `HIDE_UNREVIEWED_IN_PRODUCTION` constant rather than deleted, so re-arming the gate after sign-off is a one-word edit, the condition stays greppable, and `therapyNeedsReview` keeps its meaning for every caller that surfaces review state. The route guard in `layout.tsx` is generic over `devOnly` and self-disarmed, so it is untouched and still protects the next mode that needs it. Three pinned tests are rewritten, not deleted, because the property they guarded moved rather than disappeared. While the gate stood, hiding the content WAS the protection. Now that it ships, the protection is that every surface still says "Needs source review" — so `therapy-ranking` pins exactly that, against the real catalogue: the record badge, the universal-search badge, the route metadata suffix, and the paired glyph that keeps the warning from being colour-only. `app-modes` inverts its visibility assertions so a silent re-hiding still fails, and `therapy-review-regressions` now asserts the gate machinery still exists and is re-armable rather than that it is engaged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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:26 minutes Limit details: You’ve used the included review currently available. Your 101 included PR review attempts over the past 7 days set your current allowance 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 within each organization. For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day 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 (7)
Comment |
BigSimmo
commented
Aug 18, 2026
Closing in favour of #2150, which supersedes this and does the job better. Both remove the Therapy production gate, but #2150 is the more complete change:
#2150 also completes the The one thing here that #2150 does not carry — the queued Therapy sign-off tooling task — has been re-queued in #2152 so it is not lost with this branch. No code from this PR is needed. Closing rather than merging avoids landing a second, weaker version of the same change. Generated by Claude Code |
docs(issues): re-queue the Therapy sign-off tooling task after #2145 closed
Summary
Therapy was invisible in production, and the reason was two separate gates rather than one:
devOnly: trueon the mode hid the entrance and made the generic route guardnotFound()the routes, while a record filter served onlyreviewStatus === "reviewed". With all 205 recordsneeds_review, that combination meant a hidden mode over an empty library — removing either one alone would not have produced a working Therapy mode.The owner lifted both on 2026-08-18, deliberately and with the numbers in hand: 205 records, 0 reviewed, 1435 unticked checklist items. This is a private clinical reference tool and that exposure call is theirs.
0e51be0e).devOnlyremoved from the therapy-compass mode, with the decision and its date recorded at the site rather than in a commit message nobody re-reads.0e51be0e). Switched off behind a namedHIDE_UNREVIEWED_IN_PRODUCTION = falseconstant instead of being deleted, so re-arming after sign-off is a one-word edit, the condition stays greppable when someone asks "why is unreviewed content live?", andtherapyNeedsReviewkeeps its meaning for every caller that surfaces review state.ee440f41). The sign-off tooling this PR deliberately does not build is queued as an immutable inbox request.What was not done, and this is the important part. No record was relabelled.
reviewStatusstill readsneeds_reviewon all 205. Marking themreviewedwould have produced exactly the same screen far more cheaply — and it would have been a false clinical attestation rather than a product decision, destroying the only signal a reader now has.layout.tsxis untouched. Its guard is generic overdevOnly, so it self-disarmed when the flag came off and still protects the next mode that needs it.What protects the clinician now
While the gate stood, hiding the content was the protection, and nothing needed to say "unreviewed" out loud. Now that it ships, the protection is that every surface still says so:
StatusBadge)TriangleAlertglyphtests/therapy-ranking.test.tsnow pins all four — including the glyph, so the warning can never degrade to colour-only — against the real 205-record catalogue rather than fixtures.Tests rewritten, not deleted
Three pinned assertions guarded a property that moved rather than disappeared, so all three were replaced with the stronger condition for the new world:
therapy-ranking— "excludes unreviewed content from production" → serves the catalogue and never drops the unreviewed marking. Strictly more than the old assertion checked: it now verifies the honesty channels, which nothing previously did.app-modes— visibility assertions inverted rather than dropped, so a silent re-hiding still fails.therapy-review-regressions— was "keeps Therapy unavailable in production until clinical review is complete"; now asserts the gate machinery still exists and is re-armable. A future change that rips the mechanism out fails loudly.Verification
npm run verify:cheapTest Files 673 passed (673),Tests 7276 passed | 4 skipped (7280),Design-system contract passed (784 production files; raw colors 2; literal shadows 0; legacy tap classes 0; sub-floor interactive min-heights 37; edge conflicts 18; 1px shadow spreads 2).npm run verify:uiwhen UI, routing, styling, browser behavior, reduced-motion, or forced-colors behavior changed447 passed (14.9m), Chromium. Run deliberately rather than by default: Playwright builds in production mode, so this is the first gate that renders Therapy as a production mode, and mode-list composition is exactly what these journeys exercise.npm run ensurewas intentionally skipped —verify:uibuilds and serves its own instance, and starting a dev server is precisely what triggers theBUILD_REFUSED_DEV_SERVERconflict queued as an issue earlier today.npm run check:production-readinesswhen clinical workflow, privacy, environment, Supabase, source governance, or deployment behavior changedRan, and did not fully pass — reporting it rather than calling it green. 2 PASS, 5 WARN, 2 FAIL. Both FAILs are missing
NEXT_PUBLIC_SUPABASE_URL/SUPABASE_SERVICE_ROLE_KEY/OPENAI_API_KEYin this offline container, which is the documented provider capability gap for the offline Cloud profile, not a regression. Nothing in the output relates to review status or mode exposure.npm run verify:release— not run: provider-backed, not authorized, no release confidence claimed.npm run eval:retrieval:quality— not applicable:ragRanking: false, no retrieval, ranking, selection, chunking or scoring surface touched.npm run eval:rag/eval:quality— not applicable: answer generation untouched.npm run check:deployment-readiness— not applicable: no deployment startup, hosting or rollout behaviour changed.Risk and rollout
needs_reviewon every surface, by the catalogue being source-grounded rather than generated advice, and by this being a single-clinician private reference tool rather than a multi-tenant product.HIDE_UNREVIEWED_IN_PRODUCTION = trueinsrc/lib/therapies.tsto restore the record filter, or restoredevOnly: trueinsrc/lib/app-modes.tsto hide the mode again. Both are one-word edits and both are covered by tests that will fail until the matching assertions are flipped back.git reverton either commit also works; they are independent.mainauto-deploys to the Railway production service, so merging this makes Therapy live onpsychiatry.tools. That is the intent of the change and is stated here so it is not a surprise.Clinical Governance Preflight
scripts/pr-policy.mjsreturnsclinicalRisk: falsefor this diff —src/lib/therapies.tsandsrc/lib/app-modes.tsmatch none of its filename patterns, so no governance section is enforced. That is itself a gap worth noting: the classifier does not flag the switch that controls whether unreviewed clinical content reaches production. Completed voluntarily, and honestly rather than compliantly.Clinical KB Database(sjrfecxgysukkwxsowpy)needs_reviewand every surface still displays it. But the behaviour is by design less conservative than before, because unreviewed records are now served rather than withheld. Ticking this would misrepresent the change, and a false tick here is the same category of error as a false sign-off.On the last item: the change alters who can reach existing decision-support content, not what it computes or claims. No new decision-support behaviour was introduced, so the classification is unchanged — but this is the item most worth a second opinion, since widening the audience for unreviewed clinical content is arguably a classification-relevant fact in its own right.
Notes
An assistant did not and must not tick the five clinical checks in
reviewChecklist(clinicalAccuracyReviewed,sourceChecked,evidenceAppraised,safetyCautionsChecked,patientExplanationChecked) — those are qualified-clinician attestations. The deferred issue records that stop rule explicitly, and notes thatproofreadandaustralianEnglishCheckedare non-clinical and may be done with attribution.This branch is separate from PR #2131 because AGENTS.md forbids bundling a change needing a governance preflight with unrelated docs chores.
🤖 Generated with Claude Code
https://claude.ai/code/session_01CXpFsse3vVMy7CTxNRi568
Generated by Claude Code