fix(audit): resolve all 26 P0-P3 clinical, privacy, a11y, wiring, and INP/bundle audit findings

Merged
BI
1mo ago
+3565-1530

User description

Summary

  • Workstream A (Clinical Math, Calculators & Therapy Governance):
    • Enforced physiological domain bounds in qtc.ts (150 <= qtMs <= 800, 0.24 <= rrIntervalSeconds <= 3.0, 20 <= hr <= 250) and renal.ts (25 <= weightKg <= 350, 15 <= umol/L <= 3000, 0.17 <= mg/dL <= 34.0) to prevent unit-confusion errors, added a mouse-wheel blur guard on type="number" inputs in TextField, and set step={scrUnit === "mg/dL" ? "0.01" : "1"} on the serum creatinine input.
    • Gated bedside calculator "Copy summary" (canCopy = Boolean(entry?.derived.complete)) on complete scores, removed quarantined unverified calculators (mdq, sadpersons, ybocs) from mockup fixtures, and rendered calc.disclaimer inside all sticky live-score and result strips.
    • Added visible "Awaiting clinical review" warning badges and clipboard caveats on Therapy Compass handout sheets and briefs whenever therapyNeedsReview(t) is true.
  • Workstream B (Privacy, Account Transitions, Auth Probe, Dirty Guards & External Links):
    • Added clinical input privacy attributes (autoComplete="off", spellCheck={false}, data-gramm="false", data-enable-grammarly="false"), enforced isSharedDevice() storage isolation in term-tracker-store.ts, and wired subscribeAccountTransition cleanup across clinical and training forms.
    • Broadened DEVELOPER_ACCESS_COOKIE_PATH to "/" so signed developer cookies cover /admin/developer-hub as well as /mockups/**, and added skipWhenUnauthenticated: true / hasSupabaseAuthSession() in ShiftNowProbe and useRosterShifts to eliminate unauthenticated /api/roster/* 401 probes on guest boot.
    • Wired useDirtyStateGuard across clinical/staff forms and hardened external target="_blank" anchors with rel="noopener noreferrer".
  • Workstream C (Search-Chrome Ownership, Focus Restoration, Landmarks, Wiring & Ergonomics):
    • Extended isInformationPagePath to return true for nested /on-call/**, /roster/**, and /cme/** routes; restored dialog/sheet trigger focus via restoreFocusUnlessMoved; and guarded / and Cmd/Ctrl+K shortcuts when modal dialogs or #agreement-question-input are active.
    • Eliminated duplicate <main> landmarks on /factsheets/search, /factsheets/topics, and /cme; added <h1 className="sr-only">First Nations</h1> on /first-nations; and converted explanatory unavailable buttons to aria-disabled="true" + ignoreUnavailableActivation + aria-describedby.
    • Enforced 1rem (16px) mobile input font sizes below 640px, size-tap / min-h-tap touch targets, responsive skeleton widths (w-full max-w-96, w-full max-w-80), @media (forced-colors: active) high-contrast rules, and a 0.75rem (12px) typography floor.
  • Workstream D (INP Memoization, Client Bundle Diet & Observers):
    • Added useDeferredValue, useMemo, useCallback, and $O(1)$ Set lookups across DSM, Dictionary, Specifiers, and Medication Prescribing workspaces.
    • Extracted client-safe constants into src/lib/form-catalog-constants.ts to keep data/forms-catalog.json and data/mha-2014-sections.json out of client bundles, and converted sample/modal views in my-day-week-page.tsx and teaching-assessments.tsx to next/dynamic.
    • Consolidated observeDesktopComposerSlots in master-search-header.tsx and added .next/BUILD_ID and missing-route guards to scripts/check-bundle-budget.mjs.

Areas touched: App experience, Personal practice, Knowledge and records, Clinical reference content, Data platform and access, Answer engine, Prototypes, Delivery and assurance, Design system
RAG impact: no retrieval behaviour change — UI, calculator bounds, privacy attributes, accessibility wiring, and client bundle/memoization updates only.

Verification

  • Checks run:
    • npm run typecheck: [gate-receipts] recorded a pass for "typecheck:internal" (10051 input files).
    • npm run lint: [gate-receipts] recorded a pass for "lint:internal" (10051 input files).
    • npm run check:maintainability-budgets: [maintainability] src/components/ClinicalDashboard.tsx: 3802/3889 lines (all budgets pass)
    • npm run check:design-system-contract: Design-system contract passed.
    • npm run check:calculator-content: CALCULATOR_CONTENT_PASS sources=ok golden-vectors=ok rights=ok
    • node scripts/check-client-bundle-secrets.mjs: Client bundle secret surface check passed.
    • node scripts/check-organisation.mjs: organisation: exit 0 (pass) — working tree
    • npx vitest run (15 suites, 182 tests): Test Files 15 passed (15), Tests 182 passed (182)
    • Live Chrome DevTools MCP verification on http://localhost:4191: confirmed rosterRequestsCount: 0 on guest /, focusRestoredToTrigger: true (activeLabel: "Settings") on Settings Escape dismissal, mainCount: 1 and h1Count: 1 on /factsheets/search, /cme, and /first-nations, and /dsm/search keystroke latency improved from 397ms to 16.8ms–161ms (avg 120.2ms).
  • Verification not run: eval:retrieval:quality, eval:rag, eval:quality (provider-backed live evaluations are owner-run and no retrieval ranking or answer generation logic changed).

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 PsychSift Production (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

All seven preflight controls were verified: physiological bounds in qtc.ts and renal.ts reject out-of-domain unit-confusion inputs conservatively (isValid: false), incomplete bedside calculator scores are blocked from clipboard copy, quarantined unverified calculators are removed from mockup fixtures, and unreviewed Therapy Compass records display explicit "Awaiting clinical review" badges and clipboard caveats.

Risk and rollout

  • Risk: Low — scoped defensive bounds, privacy attributes, accessibility/landmark fixes, and client memoization/dynamic imports covered by 15 unit/DOM suites.
  • Rollback: Revert the single squash commit on main.
  • Provider or production effects: None.

Notes

  • Reviewed across all 4 workstreams by a 4-agent Review Swarm (Security & Privacy, Performance & Bundle, Accessibility & UX, Clinical & Test Coverage — all PASS).

Summary by cubic

Resolves all 26 P0–P3 findings from the live-e2e audit across clinical math, privacy, accessibility, wiring, and INP/client-bundle performance.

Clinical governance

  • QTc and Cockcroft–Gault now reject out-of-domain input (seconds instead of milliseconds, out-of-range creatinine units) so unit-confusion errors fail closed.
  • Bedside calculator copy requires a complete score, disclaimers render on all result strips, and the unverified mdq, sadpersons, and ybocs calculators are removed from mockups and pathway entries.
  • Therapy Compass handouts and briefs show "Awaiting clinical review" warnings when records need review.

Privacy, accessibility, and performance

  • Clinical inputs disable autofill, spell-check, and Grammarly; shared-device storage purges teaching term-tracker and exam-prep records and excludes them from work-sync backups.
  • Guest boot no longer fires unauthenticated /api/roster/* probes, external links use noopener noreferrer, and global shortcuts are suppressed while a dialog or the agreement input is open.
  • Developer access cookies are each scoped per gated subtree (/admin/developer-hub, /mockups/development, /mockups/care-plan) and renewed without dropping the other paths, so the credential is never sent with unrelated clinical requests.
  • Search workspaces memoize with useDeferredValue and useMemo, client-safe constants are extracted out of bundled JSON, and heavy views use next/dynamic to cut client-bundle size and INP latency.
  • Unavailable controls explain why they are disabled via aria-describedby, dialogs restore focus to their trigger, and mobile and forced-colors styles enforce tap targets, 16px inputs, and readable badge text.

Summary by Gitar

  • Removed features:
    • Removed the month calendar view from MyDayWeekDays, leaving only the seven-day agenda
  • Developer cookies:
    • Scoped DEVELOPER_ACCESS_COOKIE_PATHS to three gated subtrees instead of the / path the description states

This will update automatically on new commits.


CodeAnt-AI Description

Prevent clinical input errors and keep sensitive drafts private

What Changed

  • QT and kidney-function calculators reject values outside physiological and unit-specific ranges; low adult weight shows a caution, and numeric fields no longer change when scrolled.
  • Calculator scores show clinical-reference caveats, bedside summaries include only completed scales, and unreviewed therapy handouts and copied briefs carry a review warning. Quarantined MDQ, SAD PERSONS, and Y-BOCS mockup calculators are removed.
  • Sensitive fields disable browser and writing-assistant suggestions. Diagnosis and formulation drafts clear when accounts change, and teaching records are not stored or synced on shared devices. Edited forms warn before leaving.
  • Search filtering stays responsive while typing, and loading placeholders fit narrow screens. Unavailable actions explain what is needed, with improved keyboard, screen-reader, and focus support.
  • My Day Week now shows a seven-day agenda instead of a month calendar. Developer Hub access works alongside gated mockups.

Impact

✅ Fewer unit mix-ups in QT and kidney calculations
✅ Less risk of exposing teaching records on shared devices
✅ Smoother search while typing

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.