audit fixes (P10): Privacy and governance documents - #2622
Conversation
The "Who can access your data" section claimed "There is no shared corpus across accounts: another signed-in user cannot search, retrieve, or cite your uploads." Committed migrations promote indexed documents to the null-owner public corpus, resolveRetrievalAccessScope always sets includePublic, and /api/search serves unauthenticated callers as publicOnly - so published documents are searchable, retrievable and citable by every account and by signed-out visitors. Trigger: any reader of the /privacy notice, for any document published into the public corpus. The section now states both tiers (shared public corpus vs owner-scoped uploads under row-level security) and its gist matches. Proven by a new case in tests/privacy-page.dom.test.tsx, "describes the shared public corpus alongside owner-scoped uploads", which renders the page and asserts the removed claim is gone and both tiers are described. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSPY4VSqg7WVukCvmHQP9t
…A (M2) The privacy impact assessment's data inventory had no row for the browser-side persistence of raw clinical query text. answer-thread-storage writes the raw query, the generated answer and the source excerpts for up to 12 turns (4.5 MB cap, 12-hour TTL) to window.sessionStorage under an owner-scoped key that signed-out visitors share as guest-tab-session, and recent-query-storage keeps the last five raw queries per owner. The PIA's only browser-storage statement covered Safety Plan content. Trigger: any completed answer in the dashboard; the thread stays restorable in that tab for 12 hours. Adds a section 2 inventory row and a section 6 retention row plus a "Browser-side retention" note giving the TTL, the size cap, the clearing paths, the shared-workstation residual risk, and the tests that pin the behaviour, so a future move to localStorage reads as a PIA deviation. Documentation only; no test added because no behaviour changed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSPY4VSqg7WVukCvmHQP9t
…igration (L103) The PIA presented pg_cron job ids 11, 12, 13 and 16 as current retention evidence, and the migration that superseded them is named "enable_staging_privacy_retention_schedules". It ships in supabase/migrations, so merging it to main applied it to the live clinical database too: it unschedules the five named purge jobs and re-schedules four, giving them new job ids on production. Trigger: any reader treating the quoted job ids as the current APP 11 retention control, or the file name as proof the change was staging-only. Section 6 now marks the jobs active by name, labels the 2026-07-06 verification block as superseded, and adds a dated note that the migration re-created the jobs on production as well as staging, points at the post-merge live-drift run as the application gate, and records no replacement job id because re-reading it is provider-backed. Documentation only; no test added because no behaviour changed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSPY4VSqg7WVukCvmHQP9t
Section 2 published warn/page thresholds for answer latency p95 by route mode, /api/search latency, source-gap rate and unsupported rate as if they were alerted. Nothing in the repository computes a latency percentile, a source-gap rate or an unsupported rate, and the ops digest has no alert code for any of them - its complete code list covers only the hybrid-RPC error rate, the degraded-answer rate, projected spend and canary staleness. Trigger: an operator reading a "page" row as monitoring coverage; a latency or unsupported-rate regression would stay invisible until someone hand-ran the SQL, which is the silent-degradation failure mode the document exists to close. Adds an automation-status note naming the two alerted objectives and their OPS_* codes, labels the three unmeasured sections "Manual SQL - not alerted", and corrects the deep-probe block count from three to four by documenting the spend block. Documentation only; no test added because no behaviour changed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSPY4VSqg7WVukCvmHQP9t
…a clinical source (L7) The calculator evidence registry attaches source:governance - an internal_governance_record pointing at a repository Markdown spec - to every active instrument's sourceIds, and both the score panel and each clinical consideration rendered it inside the same "Sources:" line as a validation study, hyperlinked to a GitHub blob URL. Trigger: opening any calculator detail on /calculators; a clinician saw a release-decision record presented as clinical evidence beside the PHQ-9 validation study. Adds partitionEvidenceSources to calculator-evidence.ts and renders the governance record on its own "Governance reference:" line, keeping the link. Proven by a new case in tests/calculators-clinical-safety.dom.test.tsx, "separates the internal governance record from the clinical sources line", which asserts the Sources line no longer carries the record and the labelled line still links it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSPY4VSqg7WVukCvmHQP9t
…mbers (L4) publicCrisisContacts holds the only non-fictional data in the care-plan prototype - MHERL Perth 1300 555 788, MHERL Peel 1800 676 822 and Rurallink 1800 552 002 - each stamped verifiedOn 2026-08-20. Nothing in the repository ages that date, while the same file models CMHT contacts as review_due after months. Trigger: time passing. A redirected or retired crisis number would keep printing on the Personal Safety Plan and Patient Plan sheets, the one place the prototype's synthetic framing does not protect the reader. Adds an explicit 12-month cadence (next due 2026-08-20 plus one year) and a re-use precondition beside the values in fixtures.ts, and the same cadence in the patient-facing-sheets README that lists the numbers. The numbers, the verifiedOn dates and the rendered output are unchanged, so no test changed; tests/care-plan-linked-routes.dom.test.tsx still passes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FSPY4VSqg7WVukCvmHQP9t
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DHSyfuC6mS98ystWFiitAR
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Team Run ID: 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. Comment |
…aims (review follow-up)
Four accuracy corrections to the user-facing /privacy page, verified against
the code they describe:
- The shared corpus is now stated as intent, not enforced fact. Nothing in the
application inspects document content, and docs/privacy-impact-assessment.md
section 2 classifies uploaded documents as possibly carrying PHI.
- Publication is no longer implied to be only the per-document, approval-gated
path. set_document_corpus_access_mode('public')
(supabase/migrations/20260825025032_reversible_document_corpus_access_mode.sql)
snapshots every row in public.documents, disables the
documents_require_publication_approval trigger, and publishes all of them at
once, bypassing document_publication_approvals.
- Owner scoping is attributed to the application tier first. The app reads
through the service-role admin client and enforces ownership in code
(withOwnerReadScope in src/lib/public-api-access.ts); the authenticated-role
RLS policies stand behind that for direct database access. See
docs/audit/tenancy-defense-in-depth-review.md section 2.
- "Your uploads" is corrected for a non-administrator reader. POST /api/upload
requires { administrator: true } (src/app/api/upload/route.ts:116).
Test assertions in tests/privacy-page.dom.test.tsx and tests/privacy-ui.test.ts
are re-pinned to the new wording; four new cases pin each corrected claim.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DHSyfuC6mS98ystWFiitAR
…n the PIA (review follow-up) Four accuracy corrections, each verified against the code or workflow it describes: - Section 1 "query redaction" now says raw query text is not persisted *server-side* by default, and points at the section 2 browser row and the section 6 browser-side retention note, which record raw query text and the generated answer held in sessionStorage for up to 12 hours. - The "verified running on live (both jobs active = true)" bullet now carries its date and the fact that the job ids were re-issued on 2026-09-01, so the reader is sent to section 6 rather than treating a 2026-07-06 read as current. - The post-merge live-drift workflow is no longer named as the schema- application gate for the pg_cron purge jobs. scripts/check-drift.ts compares extensions, tables, views, functions, indexes, policies, constraints, triggers and storage buckets only; cron.job rows are outside that inventory, which the repository audit records as finding M23. The only proof is an operator `select jobname, schedule from cron.job` read. The four section 6 table cells drop the "Active" assertion accordingly. - Adds PIA-8 (Low-Medium) to the section 10 gap register and the section 1 summary table: the browser answer thread retains raw query text for 12 h, which section 6 already named as the residual control question but which the register did not carry. No clinical number, retention period, or schedule is changed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DHSyfuC6mS98ystWFiitAR
…he Sentry DB SLO (review follow-up) - "Nothing in this repository computes an answer-latency percentile" was false: scripts/eval-retrieval.ts enforces a p90 latency budget (p90BudgetMs, default 20 s) using the percentile helper in scripts/eval-utils.ts, and the same budget is cited under "Anchors" in the section immediately below. The claim now says no *production monitor* computes one, and names the eval harness as the on-demand, fixture-corpus exception. - The "Database latency - Sentry production DB span SLO" section was the only objective left without an alerted/not-alerted label, so a reader could not tell whether it is monitored. It is now labelled as a Sentry-side alert whose provisioning is unverified: SENTRY_AUTH_TOKEN appears in this repository only in the build-time sourcemap upload (next.config.ts), and no script provisions, reads, or tests the alert. No threshold, SLO value, or alert code is changed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DHSyfuC6mS98ystWFiitAR
…eached production (review follow-up)
The PRIV-PROVIDER-RETENTION-SCHEDULE-PARITY externalEvidenceReference still
described 20260901033250 as staging-only. The migration ships in
supabase/migrations and its own header is environment-neutral ("environments
where the historical retention migrations ran before pg_cron was available"),
so merging it to main applied it to the live Clinical KB Database project
within seconds. One dated superseding sentence is appended; the dated, signed
attestation documents are left untouched.
check:privacy-readiness -> PRIVACY_READINESS_PASS mode=structural requirements=11
tests/privacy-readiness-contract.test.ts -> 8 passed
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DHSyfuC6mS98ystWFiitAR
…(review follow-up) The README told the reader to re-verify all four numbers "against the WA Health service pages recorded as each contact's sourceUrl". Only three of the four are WA Health: SYN-CRISIS-CONTACT-002/003/004 cite East Metropolitan Health Service pages on emhs.health.wa.gov.au (a single MHERL page serving both the Perth metropolitan and Peel numbers, and a Rurallink page), while SYN-CRISIS-CONTACT-001 (000) cites the Commonwealth Triple Zero service at triplezero.gov.au. No number and no verifiedOn date is changed. Note: the same "(the WA Health service pages)" phrasing appears in the fixture file's own header comment at src/components/care-plan/mockups/fixtures.ts; left as-is to keep this commit inside its reviewed scope. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DHSyfuC6mS98ystWFiitAR
…cation note The header comment told the next reader to re-verify each number against "the WA Health service pages" recorded as its sourceUrl. Three of the four contacts cite East Metropolitan Health Service pages; 000 cites triplezero.gov.au, which is Commonwealth. Same correction the README carried in d5a29b8. No number and no verifiedOn date changed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DHSyfuC6mS98ystWFiitAR
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Bugbot couldn't run - usage limit reachedBugbot 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_32ec3404-ae4d-41c3-9b19-d0551ca48ed3) |
…urce-page correction Package 21 merged to main while this branch was open and replaced this header with a pointer to docs/care-plan/crisis-lines-verification.md, which is now the record of when these numbers were checked and when they are next due. This branch had corrected the same header's claim that every sourceUrl is a WA Health page: three cite East Metropolitan Health Service pages and 000 cites Triple Zero (Commonwealth). Resolved as a union with one deliberate omission: main's pointer is kept and the source-page correction folded into it, but this branch's twelve-month cadence sentence is NOT reinstated, because the new document states a six-monthly cadence and two different re-check intervals in the same repository is worse than either one. The document owns the cadence; that disagreement is the owner's to settle. No number and no verifiedOn date changed. Verified: tsc clean; care-plan, privacy-page and calculators suites 93 passed (93). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DHSyfuC6mS98ystWFiitAR
Summary
Audit remediation package P10 — Privacy and governance documents, from
docs/audit/full-repository-audit-2026-09-02.md(PR #2573). Findings fixed:M7,M2,L103,L104,L7,L4. Each fix landed test-first as its own commit.Findings in this package not fixed here, with reasons:
L5— Cannot be completed inside the owned files. public/brand/preview.html is owned, but tests/developer-hub-panels.test.ts asserts it is byte-identical to docs/brand/preview.html (not owned, not generated by any script), so editing only the owned copy would fail that test, and weakening a test is prohibited. The X-Robots-Tag noindex header for /brand/:path* also lives in next.config.ts (not owned). Exact change for the owner, applied identically to both HTML copies: delete the fonts.googleapis.com and fonts.gstatic.com preconnect links and the Google Fonts stylesheet link (the proxy CSP already blocks the stylesheet, so the page already renders in fallback fonts), and add<meta name="robots" content="noindex, nofollow">.L103(readiness-register half) — The PIA half is fixed. The privacy readiness register entry whose externalEvidenceReference still describes migration 20260901033250 as a staging-only change is outside the package's owned file list, so it was left untouched.Decisions needed from the owner:
RAG impact: none
Verification
npm run verify:pr-local— result:- completed: check:runtime, check:installed-lock-parity, format:changed, check:diff-integrity, sitemap:check, check:repo-awareness-snapshot, docs:check-index, docs:check-inventory, docs:check-scripts, docs:check-links, check:branch-review-ledger, check:outstanding-issues, check:ledger-write-discipline, lint, typecheck, test, build, check:rag:fixtures, check:medication-interactions, check:medication-lexicon-report·- failed: (none)·- not reached: (none)·Test Files 1127 passed | 1 skipped (1128)·Tests 14964 passed | 2 expected fail | 3 skipped (14969)(the gate runner recorded exit code 0)npm run check:diff-integrity—[diff-integrity] PASS — 2 changed test file(s), 22 -> 24 test case(s), against base 51ddfcd83.Verification not run:
npm run verify:ui— browser proof left to CI (the pinned Chromium is not installed in this container); no narrowed browser run is claimed as the full gate.Verification not run:
npm run verify:release— no release or handoff confidence is claimed.Verification not run: provider-backed gates (
check:production-readiness, everyeval:*) — nothing here touches OpenAI, Supabase, Railway or Sentry at run time; all work was offline.Risk and rollout
Clinical Governance Preflight
Each item confirmed against this package's diff (findings
M7,M2,L103,L104,L7,L4). The checked line is the exact policy item; the note beneath it is the evidence.no change to source verification or citation requirements.
none introduced or expanded.
Clinical KB Database(sjrfecxgysukkwxsowpy)no Supabase env value, migration target or configured project changes.
no client exposure of service-role credentials; private access paths unchanged or tightened.
unchanged.
unchanged or made more conservative.
reviewed; the changes correct reference rendering defects the 2026-09-02 audit recorded and do not add decision-support behaviour.
Notes
src/lib/privacy-page-content.tsx,tests/privacy-page.dom.test.tsx,docs/privacy-impact-assessment.md,docs/observability-slos.md,src/components/calculators/calculator-evidence.ts,src/components/calculators/search-detail.tsx,tests/calculators-clinical-safety.dom.test.tsx,src/components/care-plan/mockups/fixtures.ts,docs/care-plan/patient-facing-sheets/README.md,docs/design-system/adoption.md(regenerated by the pre-commit hook on the M7, L7 and L4 commits)🤖 Generated with Claude Code
https://claude.ai/code/session_01DHSyfuC6mS98ystWFiitAR
Generated by Claude Code
Note
Medium Risk
Medium risk from privacy-facing copy that asserts public corpus access and signed-link behavior, plus calculator citation labeling; changes are mostly documentation with two UI/copy paths covered by new tests and no retrieval or clinical scoring changes.
Overview
Audit remediation P10 aligns privacy/governance docs and user-facing copy with how the product actually behaves, without changing RAG or scoring logic.
Privacy and PIA:
/privacynow states a two-tier access model—operator-published shared public corpus (searchable including without sign-in) versus owner-scoped uploads and logs—and that signed URLs can cover public-corpus files. The PIA adds browsersessionStorage(12-hour answer threads, recent queries) to data classification and retention, documents stale pg_cron job ids after migration20260901033250, and expands shared-workstation residual risk.Observability docs:
docs/observability-slos.mdclarifies that only hybrid-RPC error rate and degraded answer rate are repo-computed and alerted (answerSloSnapshot/OPS_*); latency p95, source-gap, and unsupported thresholds are manual SQL targets, not monitoring. The deep health probe is documented as returning up to four blocks includingspend.Calculators (presentation):
partitionEvidenceSourcessplitsinternal_governance_recordfrom clinical validation sources; Score and clinical-considerations panels show “Governance reference:” separately while keeping links—pinned by a new DOM test.Care-plan prototype: Docs and fixture comments add a 12-month re-verification cadence (next due 20 Aug 2027) for real WA crisis numbers in
fixtures.ts, with correction only in fixtures—not rendered sheets.Reviewed by Cursor Bugbot for commit c40cfd0. Configure here.