fix(handover,notes,teaching,cli): resolve follow-up adversarial audit findings
User description
Summary
- Shift scratchpad expiry & manual clear (
src/components/on-call/handover/handover-page.tsx,src/lib/on-call/handover.ts): KeeploadOnCallHandoverScratchpadside-effect-free during initialuseStateevaluation, run the active shift expiry timer andClear allaction whenever scratchpad text is present (even with zero patient rows), and prevent scratchpad edits on an already-expired shift from silently refreshing the 12-hour label TTL. ClinicalNoteEditordebounce stability & status recovery (src/components/clinical-notes/note-editor.tsx,tests/note-editor-caret.dom.test.tsx): StoreonChangein a ref so parent re-renders with inlineonChangehandlers do not cancel the 400ms auto-save debounce timer on every keystroke, and resetsaveStatuswhen edits revert tolastSavedValueinstead of leaving"Unsaved changes"permanently stuck.- First-publication CLI content pin verification &
--executecredential guard (scripts/publish-site-content-first-catalogue.ts,tests/site-content-first-publication-cli.test.ts): VerifyreviewedContentSha256for form sign-offs againstrecordContentSha256(..., "form", { catalog: formsCatalog })and fail closed when--executeis invoked withoutNEXT_PUBLIC_SUPABASE_URLandSUPABASE_SERVICE_ROLE_KEY. - EPA magic link cleanup & clipboard fallback (
src/lib/teaching/assessments/magic-link.ts,src/components/teaching/assessments/assessments-help.tsx): Revoke locally minted EPA supervisor magic link tokens if thePUT /api/teaching/assessmentspersistence request fails, and display a manual copy fallback URL ifnavigator.clipboard.writeTextrejects or is unavailable. - Fail-closed
display.revokeauthorization (src/lib/teaching/repository.ts,tests/teaching-display-revoke-auth.test.ts): Require validgranted_atandjoined_attimestamps (grantedMs >= joinedMs) and fail closed if membership/role tables are unavailable when rotating a shared display session withoutcurrent_display_token.
Verification
- Checks run:
npx vitest run tests/note-editor-caret.dom.test.tsx tests/site-content-first-publication-cli.test.ts --no-file-parallelism --maxWorkers=1->Test Files 2 passed (2), Tests 20 passed (20)npx vitest run tests/teaching-display-revoke-auth.test.ts->Test Files 1 passed (1), Tests 6 passed (6)npx prettier --write ...-> all 10 modified files formatted cleanly- Full repository static/UI suites and hosted CI checks: unrun locally by bare-PR publication request (GitHub Actions is the verification surface).
Risk and rollout
- Risk: Low — scoped bug fixes and fail-closed guards across handover scratchpad privacy, clinical note editor debounce, first-publication CLI validation, EPA magic link error cleanup, and teaching display revocation.
- Rollback: Revert commit
bdbeb841d3. - Provider or production effects: None
Summary by cubic
Resolves the follow-up adversarial audit findings across handover privacy, clinical note autosave, teaching magic links and QR check-in, roster swaps, and clinical calculators.
- Handover scratchpad respects shared-device privacy, loads after hydration, syncs across tabs, runs expiry and
Clear allwhenever text is present, and stops expired-shift edits from refreshing the label TTL; writes also check the stored shift stamp so a late expiry timer cannot start a fresh shift for stale text.Save nowis the deliberate save, so it keeps text on shared devices even though auto-save is suppressed. ClinicalNoteEditorkeeps its auto-save debounce stable across parent re-renders, queues changes made while a save is in flight so reverting to stored text mid-save loses nothing, ignores saves that finish after the parent replaces the note, resets when a genuinely new controlled value arrives (canceling the queued save), and clears a stuckUnsaved changesstatus when edits revert; no falseSavedstate whenonSaveis omitted.- First-publication CLI verifies form sign-off content hashes and fails closed in production when
--executelacksALLOW_DESTRUCTIVE_SITE_CONTENT_INIT=trueor live Supabase credentials; EPA magic-link assessments are refused in production without a durable store. - EPA magic links revoke locally minted tokens when persistence fails, fall back to manual copy when the clipboard API is unavailable, and reject invalid clinician names before sharing; the write route rate-limits before the sign-in lookup.
- Teaching display revocation fails closed against invalid or crossed timestamps and unavailable membership tables.
- Clinical calculators parse inputs strictly with no fabricated empty-state results and add adjusted-body-weight support with bounds checks.
- Roster safe-number editing re-flags conflicts when a third edit arrives after the banner opens; swap rule warnings verify actor role and require a matching acknowledgement on retry.
- QR check-in accepts
/teaching/c/links and enforces demo-mode guards with manual entry hidden on attendance sheets; attendance gaps show loading and retryable errors instead of empty states.
Summary by CodeRabbit
- Bug Fixes
- Clinical note editing now handles in-progress saves and external updates more reliably, reducing the risk of stale or unsaved changes.
- On-call handover notes now respect shift expiry, with clearer save and clear controls.
- Magic-link registration now handles failed link creation and clipboard errors more clearly.
- Display-link revocation now checks organiser access more consistently.
CodeAnt-AI Description
Protect handover privacy and fix note-saving and supervisor-link issues
What Changed
- Handover scratchpads are cleared on shared devices and when a shift expires. Users can clear a scratchpad even when no patient entries are present.
- Clinical notes keep saving after parent updates, and reverting to the last saved text clears the unsaved status.
- Failed supervisor-link registration revokes the link; if copying is unavailable, the full link is shown for manual copying.
- Display-link revocation now fails closed when organiser access or its timestamps cannot be verified. Live catalogue publishing also requires Supabase credentials.
Impact
✅ Scratchpads cleared on shared devices and at shift end
✅ Clinical note autosaves continue after parent updates
✅ Failed supervisor registrations leave no usable link
✅ Unverified display-link revocations are blocked
💡 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.