fix: resolve reconciled adversarial review findings R01-R34
Summary
Resolves all 34 reconciled adversarial review items (R01–R34) plus the 5xx and database-advisor diagnostic items:
- R01, R02, R18 & R34 (Unified Release Identity, Worker Pause & Control-Plane Deadlines): Bakes
deploy/release-identity.json(commitSha,sentryRelease) into bothDockerfileandDockerfile.worker, exposesdeploymentCommitShaandclaimLoopPausedon/api/healthand worker/healthz, supportsWORKER_PAUSED=true/WORKER_CLAIM_LOOP_ENABLED=falseso the worker stays paused when unifiedmainpromotes, and wraps all worker control-plane Supabase queries/RPCs in finite 30s deadlines (WORKER_CONTROL_PLANE_TIMEOUT_MS). - R03, R09, R17 & R32 (UI, Citation Hit Targets, CPD Draft Persistence, Pilot Labels & Restored Answer Notice): Clips
.answer-source-mark::beforeand.answer-source-mark-overflow::beforehit areas atcalc(-0.5 * var(--answer-mark-gap))with center/inner-edgeelementFromPointassertions; persists CPD plan edits across internal navigation and failed saves insessionStorage; labels uncited"Also found"rows as"Searched, not cited", populates fallback inline snippets, and distinguishes.txt("TXT","View original text") from.pdf; and renders a"Restored from earlier in this session"age banner with a"Recheck now"button on restored answers. - R04, R05, R06, R07, R08, R20 & R23 (RAG Cancellation, Latency, Tie-Break, Visual Evidence, Comparison & Pilot Isolation): Threads
AbortSignalintocorrect_clinical_query_terms,fetchMemoryCardsForQuery,loadChunksForMemoryCards,attachDocumentContextPackAdmission,fetchBestDocumentLookupChunks,fetchDocumentTitleAliasRows,loadChunksForSignalMatches,fetchRelatedDocuments,hydrateCandidatesWithMetadataAndMemory, andpackAdjacentSourceContext; addsdocument_title_phraseclamped-score tie-breaking inrankCandidatesForSelection; hydrates chunk-linkedresult.image_ids, re-evaluatesclinical_use_class === "ambiguous"table crops, and retains same-document visual evidence; applieswithAdmissionDischargeContextPair/withAdmissionDischargeSideEvidencetoanswerInputResultsandselectedContextPair; isolates pilot-ticket expiry soOWNER_IDis never blocked on unrelated documents/queries; deduplicatesdeep-memory.ts; and adds worker ranking producer paths toragRankingPatternsinscripts/pr-policy.mjs. - R10, R11, R12, R21 & R22 (Pre-Parse Streamed Body Limits, Paperwork Sync, Strict Schemas & Open-Shift Idempotency/Alerts): Adds
readBoundedFormDataandreadBoundedJsonpre-parse byte limits to/api/cme/missed/[id],/api/teaching/assessments/dual-sign-off,/api/teaching/import/read,/api/speech/transcribe, and/api/upload; enforces server-sidefirstPaperworkPatientProblemonadminPaperworksync; enforces.strict()recursive Zod schemas onteachingTermTracker,teachingExamPrep, andcpdApplications; removes client-side similarity suppression inopen-shifts-post-page.tsxand evicts non-active shift keys inpublic.roster_open_post_once; and tracks alert delivery inpublic.roster_open_post_alertsso replayedopen.postactions recover failed notifications without duplicating delivered ones. - R13, R14, R15, R16, R19, R24, R25, R26, R27, R28, R29, R30, R31 & R33 (Trivy Scan Gate, Runtime Check, Live Admin Role Check, Credentials, Retention, SLOs & Test Boundaries): Requires structured JSON
STATUS=okfor both app and worker images inscripts/trivy-image-scan.mjsanddocker-image.yml; verifies@types/nodemajor parity inscripts/check-runtime.ts; re-verifies liveauth.usersadministrator status insidepublic.admit_administrator_document; enforces a 90-day inactivity TTL inpublic.calendar_feed_owner, addsrevokeEpaMagicLinkByIdanddisplay.revokebyoccurrenceId, and supportsDEVELOPER_AREA_ACCESS_KEY_PREVIOUS/HEALTH_DEEP_PROBE_SECRET_PREVIOUSrotation overlap; expands SLO alerting (source-gap and unsupported rates are now counted server-side over the whole window) and 6-hourlyops-digest.ymlcadence; tightens maintainability budgets; and adds SQL/unit boundary tests.
Areas touched: Data platform and access, Personal practice, App experience, Delivery and assurance, Answer engine, Source intake and indexing, Knowledge and records, Clinical reference content, Design system, Prototypes
RAG impact: no retrieval behaviour change — the title-phrase tie-break and the other ranking/evidence changes moved to draft #3599 (canary pair required there); this PR keeps only cancel-signal plumbing in the retrieval path.
The RAG-affecting parts are the document_title_phrase clamped-score tie-break (rag.ts / retrieval-selection.ts) and the admission/discharge side-evidence file. The AbortSignal plumbing, visual-evidence retention and worker producer path coverage are not intended to change ranking. A live eval-canary before/after pair is required before merge and has not been run.
Verification
npx vitest runon all 27 affected unit and DOM test suites (176 tests passed)npm run typecheck(passed, 0 errors)npm run lint(passed, 0 warnings)npm run check:maintainability-budgets(passed)npm run check:migration-immutability&npm run check:migration-role&npm run check:function-grants(passed)npm run check:diff-integrity(passed, 340 -> 403 test cases)npm run check:organisation&npm run check:pr-policy&npm run check:runtime&npm run docs:maintain:check(passed)npm run drift:manifest(replayed cleanly against scratch Postgres)
Risk and rollout
- Database migration and merge gate:
supabase/migrations/20261016210000_adversarial_review_rpc_and_ttl_hardening.sqlis additive and backward-compatible (CREATE OR REPLACE FUNCTION,CREATE TABLE IF NOT EXISTS public.roster_open_post_alerts,ALTER TABLE public.calendar_feed_tokens ADD COLUMN IF NOT EXISTS rotated_at). This PR contains a migration, so merging it reaches the live clinical database within seconds. Merge only inside an approved window and only with the owner's explicit permission for this database change. - Drift manifest:
supabase/drift-manifest.jsonmust be regenerated withnpm run drift:manifest(needs Docker) before merge; the Migration replay check fails until it is. - Worker pause preservation:
WORKER_PAUSED=trueis configured on the Railwayworkerservice so promoting the unifiedmainrelease keeps the background PDF claim loop paused while serving/healthzwithclaimLoopPaused: trueanddeploymentCommitSha. - Rollback: Revert the commit on
main; database functions androster_open_post_alertsremain backward-compatible with prior app/worker builds.
Clinical Governance Preflight
- If this PR changes clinical prompts, answer generation, citation logic, retrieval ranking, source policy, or clinical UI presentation, I reviewed
docs/clinical-governance.mdand recorded the clinical safety impact above. - If this PR adds or changes clinical guidance sources, I checked approval metadata and provenance requirements (
npm run check:source-governancewhere applicable). - Real patient identifiers, clinical notes, and private health information are not included in code, tests, fixtures, screenshots, or PR text.
Summary by cubic
Resolves the 34 reconciled adversarial review findings (R01–R34) across the app, worker, and database, hardening security and operational boundaries without changing retrieval behavior. The ranking and evidence changes originally planned here (title-phrase tie-break, community admission preference, admission/discharge context pairing, ambiguous-clinical-image handling, direct image_ids attachment) were split out into a separate draft PR that needs a live eval-canary pair before merge.
Application behavior
- Threads
AbortSignalcancellation through RAG query, candidate, and context functions; isolates pilot-ticket expiry so unrelated documents and queries never block the pilot owner. - Fixes in-prose source mark hit areas, labels uncited rows "Searched, not cited", distinguishes
.txtfrom.pdf, and shows a "Restored from earlier in this session" banner with a recheck action that survives a failed recheck. - Persists CPD plan drafts in
sessionStoragescoped to the account owner; adds bounded pre-parse body limits to five upload/transcribe/import routes, strict schemas on teaching and CPD sync, and server-side open-shift post idempotency whose alert delivery is deduplicated, persisted only after success, and retried after lookup or in-flight failures. - Snapshots prior teaching display links before creating replacements, so revoking by
occurrenceIdnever orphans an active link.
Release, security, and operations
- Bakes a release-identity manifest into both Dockerfiles; health endpoints expose the deployment commit SHA and worker claim-loop pause state, and worker control-plane queries run under finite 30s deadlines.
- Makes the Trivy image scan fail closed on structured
STATUS=okJSON evidence for both images (writable cache mount so the scans actually run) and verifies@types/nodemajor parity. - Re-verifies live administrator status in document admission, enforces a 90-day calendar feed TTL, adds magic-link revocation by
occurrenceIdwith replacement links created before revocation, and supports previous-secret rotation overlap. - Adds source-gap, unsupported-answer, and latency-budget SLO alerts (budgets keyed to each route's routing mode), moves the ops digest to 6-hour sampling, records recovery-drill RPO/RTO metrics, and ships a backward-compatible migration with incident runbook SQL switched to
payload::text.
Summary by CodeRabbit
- New Features
- Restored answers now show when they were saved and note that library documents may have changed, with an option to recheck the answer.
- Answer sources more clearly distinguish documents that were searched from those cited, and link to the appropriate original file.
- CME plan drafts persist across page visits and are kept separate between accounts.
- Bug Fixes
- Uploads are checked against size limits, and failed image scans now stop the release check.
- Open-shift retries handle cancelled or otherwise unavailable shifts without navigating to them.
🤖 Generated with Claude Code