Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/agents/clinical-governance-reviewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Follow `AGENTS.md` review throttling and `docs/codex-review-protocol.md` before
- `src/lib/{source-governance,source-metadata,document-label-governance,indexed-source-formatting,source-spans,source-text-sanitizer,rag-source-block}.ts`
- `src/lib/{citations,answer-verification,rag-quote-verification,rag-answer-support,answer-render-policy,clinical-safety}.ts`
- `src/lib/{privacy,query-privacy}.ts`, `src/components/privacy-input-notice.tsx`
- `docs/{clinical-*,privacy-*,source-governance-*,rag-injection-*}.md`, `docs/openai-cross-border-basis.md`, `docs/tenancy-defense-in-depth-review.md`
- `docs/{clinical-*,privacy-*,source-governance-*,rag-injection-*}.md`, `docs/openai-cross-border-basis.md`, `docs/audit/tenancy-defense-in-depth-review.md`

## Provider boundary

Expand Down
9 changes: 9 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,15 @@ named PR). Future process only.
pushes; it fails explicitly on `mergeable_state: dirty`. Behind-but-clean heads still use
`npm run sync:pr-branches` / `:apply` with a human `gh` identity — never bot
`update-branch`.
- When `gh pr checks` cannot read check runs with the current token, query the Actions runs for the
exact head SHA instead; do not report CI as unverifiable until that read-only fallback has also
failed.
- Treat outstanding-issue IDs as display locators, not proof that work landed. Verify completion
from distinctive content and its recorded check on the exact target ref; PR state, row ID, and row
title are insufficient, especially after squash merges or concurrent renumbering. Allocate and
mutate rows only through `npm run issues:add|update|done`, never use GitHub's Update branch button
on a PR touching `docs/outstanding-issues.md`, and let the structural gate force any allocation
collision to be resolved explicitly.
- Keep Playwright blocking tests at zero retries. Quarantine only after three reproductions
on the same SHA via `tests/flake-ledger.json` (`@quarantine`, not `@critical`, ≤30-day
expiry). Do not weaken tap targets to `min-h-11` to chase generic a11y guidance — that
Expand Down
36 changes: 36 additions & 0 deletions PR_POLICY_BODY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
## Summary

- File dated point-in-time reviews under their canonical `docs/audit/` and `docs/archive/` locations and repair every affected repository reference.
- Archive completed ledger work through the guarded writers, preserve the append-only review history, and correct `#101` so it no longer proposes the metadata and memory hydration already shipped by PR #1474.
- Keep the existing performance-only PostgreSQL plan hint while updating migration references and the generated drift manifest.

## Verification

- [x] `npm run drift:manifest` — passed; scratch PostgreSQL replay completed and regenerated `supabase/drift-manifest.json` for the changed schema source.
- [ ] `npm run verify:pr-local` — partial: runtime, installed-lock parity, changed-file formatting, sitemap/docs checks, ledger guards, workflow/policy guards, lint, and typecheck passed. The full unit stage failed in unrelated Windows/baseline areas (`bundle-budget`, `pr-handoff-stop`, worker-observability timing, and document-viewer virtualization timing), so build and offline RAG evaluation were not reached.
- [x] `npm run check:outstanding-issues`, `npm run check:branch-review-ledger`, `npm run docs:check-links`, `npm run docs:check-inventory`, `npm run docs:check-index`, `npm run check:migration-role`, and `npm run format` — passed.
- [x] `npm run test -- tests/drift-detection.test.ts` — 12/12 passed.

UI verification not run: this PR does not change UI, routing, styling, browser behavior, reduced motion, or forced-colors behavior.

RAG impact: no retrieval, ranking, candidate-selection, source-rendering, or answer-contract behavior changes. The ledger text only records that PR #1474 already shipped metadata and memory hydration parallelisation; the remaining candidates stay behind their existing RAG flag and canary requirements.

## Risk and rollout

- Risk: Low. Most changes are documentation/reference moves. The only executable database delta is the existing `force_custom_plan` performance hint; it does not change result sets, RLS, schema shape, or clinical logic.
- Rollback: Revert this PR. No data migration or destructive operation is required.
- Provider or production effects: None. Drift-manifest generation used a worktree-owned local scratch PostgreSQL container only.

## Clinical Governance Preflight

- [x] Source-backed claims still require linked source verification before clinical use
- [x] No patient-identifiable document workflow was introduced or expanded without explicit governance approval
- [x] Supabase target remains `Clinical KB Database` (`sjrfecxgysukkwxsowpy`)
- [x] Service-role keys and private document access remain server-only
- [x] Demo/synthetic content remains clearly separated from real clinical sources
- [x] Source metadata, review status, and outdated/unknown-source behavior remain conservative
- [x] Deployment classification/TGA SaMD impact was checked; no clinical decision-support behavior changes

## Notes

- Historical capacity and scale reviews are rename-only snapshots. Their point-in-time wording is intentionally preserved under `docs/audit/`; current repository policy says historical audit records are superseded rather than rewritten.
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ not validated clinical decision support (see `README.md` → "Clinical Safety St
## Related security documentation

- `docs/rag-injection-threat-model.md` — prompt-injection threat model.
- `docs/tenancy-defense-in-depth-review.md` — multi-tenant isolation review.
- `docs/audit/tenancy-defense-in-depth-review.md` — multi-tenant isolation review.
- `docs/privacy-impact-assessment.md` — privacy impact assessment and launch blockers.
- `docs/clinical-hazard-analysis.md` — clinical hazard register.
- `docs/openai-cross-border-basis.md` — cross-border data-processing basis.
Expand Down
4 changes: 2 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ as it was on that date; supersede with a new dated document rather than editing.
- `release-source-metadata-debt-2026-06-30.json` — captured source-metadata debt policy, consumed by `npm run audit:source-governance:release` and `npm run eval:quality:release`
- [forward-codify-retrieval-rpcs-workorder.md](forward-codify-retrieval-rpcs-workorder.md) — completed retrieval RPC codification workorder
- [project-alignment-cleanup.md](archive/project-alignment-cleanup.md) — completed June 2026 repo-alignment record
- [capacity-review.md](capacity-review.md), [scale-readiness-review.md](scale-readiness-review.md), [tenancy-defense-in-depth-review.md](tenancy-defense-in-depth-review.md)
- `*-2026-*` findings and status docs, e.g. [chunking-ocr-reindex-lever-finding-2026-07-08.md](chunking-ocr-reindex-lever-finding-2026-07-08.md), [source-governance-status-2026-07-08.md](archive/source-governance-status-2026-07-08.md), [source-governance-priorities-2026-07-02.md](archive/source-governance-priorities-2026-07-02.md), [source-review-priority-2026-07-02.md](source-review-priority-2026-07-02.md), [operator-apply-july8-batch.md](operator-apply-july8-batch.md)
- [capacity-review.md](audit/capacity-review.md), [scale-readiness-review.md](audit/scale-readiness-review.md), [tenancy-defense-in-depth-review.md](audit/tenancy-defense-in-depth-review.md)
- `*-2026-*` findings and status docs, e.g. [chunking-ocr-reindex-lever-finding-2026-07-08.md](chunking-ocr-reindex-lever-finding-2026-07-08.md), [source-governance-status-2026-07-08.md](archive/source-governance-status-2026-07-08.md), [source-governance-priorities-2026-07-02.md](archive/source-governance-priorities-2026-07-02.md), [source-review-priority-2026-07-02.md](source-review-priority-2026-07-02.md), [operator-apply-july8-batch.md](archive/operator-apply-july8-batch.md)

## Archive

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
Consolidated runbook for migrations merged to `main` in PRs **#380**, **#405**,
**#408**, and **#409** that were **in the repo but not yet verified on live** as
of 2026-07-09. Companion to
[`docs/supabase-migration-reconciliation.md`](supabase-migration-reconciliation.md)
and [`docs/ingestion-concurrency-fix-workorder.md`](ingestion-concurrency-fix-workorder.md).
[`docs/supabase-migration-reconciliation.md`](../supabase-migration-reconciliation.md)
and [`docs/ingestion-concurrency-fix-workorder.md`](../ingestion-concurrency-fix-workorder.md).

## Pre-flight

Expand Down Expand Up @@ -91,5 +91,5 @@ active end-to-end.

- Forward-codify live-ahead retrieval RPC bodies (`docs/database-drift-detection.md` backlog #0)
- deep-memory delete scoping design (`docs/ingestion-concurrency-fix-workorder.md`)
- Staging soak (`docs/staging-setup.md`, `docs/capacity-review.md`)
- Staging soak (`docs/staging-setup.md`, `docs/audit/capacity-review.md`)
- `registry:seed` per owner (`docs/process-hardening.md`)
16 changes: 8 additions & 8 deletions docs/audit/audit-handover-2026-07-14.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,13 @@ evals, service-role tenancy regression class, upstream OCR quality labels drivin

### M6 — Single-layer tenancy (ARCHITECTURE — P1 regression class)

| | |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------- |
| **What** | APIs use service role; ownership enforced in app helpers/RPCs, not full second-layer RLS for public-overlay model |
| **Where** | `createAdminClient()`, `withOwnerReadScope`, `retrieval_owner_matches`; `docs/tenancy-defense-in-depth-review.md` |
| **Risk** | Future route forgetting owner scope → private corpus leak |
| **Address** | Remediation Wave D2 — CI unscoped-query guard + live A/B |
| **Status at handover** | Mitigated in current routes; guard not yet coded |
| | |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| **What** | APIs use service role; ownership enforced in app helpers/RPCs, not full second-layer RLS for public-overlay model |
| **Where** | `createAdminClient()`, `withOwnerReadScope`, `retrieval_owner_matches`; `docs/audit/tenancy-defense-in-depth-review.md` |
| **Risk** | Future route forgetting owner scope → private corpus leak |
| **Address** | Remediation Wave D2 — CI unscoped-query guard + live A/B |
| **Status at handover** | Mitigated in current routes; guard not yet coded |

---

Expand Down Expand Up @@ -242,7 +242,7 @@ Full address sketches: Remediation Wave I in the remediation plan.
| [`launch-operator-runbook.md`](../launch-operator-runbook.md) | Sequenced launch commands |
| [`privacy-impact-assessment.md`](../privacy-impact-assessment.md) | PIA register |
| [`openai-cross-border-basis.md`](../openai-cross-border-basis.md) | APP 8 checklist |
| [`tenancy-defense-in-depth-review.md`](../tenancy-defense-in-depth-review.md) | Tenancy defense notes |
| [`tenancy-defense-in-depth-review.md`](tenancy-defense-in-depth-review.md) | Tenancy defense notes |
| [`process-hardening.md`](../process-hardening.md) | Process & known debts |
| [`codex-review-protocol.md`](../codex-review-protocol.md) | Review severity / mutation rules |
| [`branch-review-ledger.md`](../branch-review-ledger.md) | Prevent repeat audits |
Expand Down
2 changes: 1 addition & 1 deletion docs/audit/audit-remediation-plan-2026-07-14.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ Suggested PR granularity (one theme per PR):
| **Finding** | Service-role single layer; forgotten owner filter is a full leak class |
| **Owner** | OWNER:CODE (+ OWNER:OPS for live A/B) |
| **Address** | Add static CI guard grepping `src/app/api/**` for admin queries on owner-scoped tables without known helpers (`withOwnerReadScope`, `requireOwnerScope`, `.eq("owner_id"` patterns allowlisted). Document remaining intentional exceptions. Schedule `⏸` user A vs B smoke on documents + signed URLs + search. |
| **Files** | new `scripts/check-owner-scope-api.mjs` (or extend existing), `package.json` / `verify:cheap`, tests; update `docs/tenancy-defense-in-depth-review.md` |
| **Files** | new `scripts/check-owner-scope-api.mjs` (or extend existing), `package.json` / `verify:cheap`, tests; update `docs/audit/tenancy-defense-in-depth-review.md` |
| **Prove** | Guard fails on a synthetic unscope fixture; live A/B green |

### D3. Auth UI: prefer validated user for privilege display (S2)
Expand Down
File renamed without changes.
6 changes: 3 additions & 3 deletions docs/audit/latency-audit-2026-07-28.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
**Branch:** `claude/latency-audit-f1cbcd` (worktree `prompt-skill-improvements-7d5f80`), base 1 commit behind `origin/main` (`ea6d2d954`, mockups-only — no latency surface)
**Method:** Three read-only reconnaissance sweeps (server request path / client-browser path / database + prior-work), then line-level verification of every load-bearing claim by the primary author. Four planned remediations were **retired during verification** because the evidence did not support them — recorded under "Retired during verification" rather than silently dropped.
**Scope:** Latency only. Full server request path, client first-paint path, database/RPC surface, and the ingestion/worker path where it bounds a user-visible wait. Excludes correctness, security, and clinical-governance findings except where they _gate_ a latency fix.
**Guardrail posture:** Obeys (1) the `src/lib/rag/**` FLAG + `RAG impact:` rule and its live-canary requirement for behaviour change; (2) ledger `#017`, which gates client payload work behind measured Web-Vitals evidence; (3) `docs/capacity-review.md:123-125` explicit non-actions; (4) the provider-confirmation boundary — no OpenAI/Supabase/hosted-CI call was made.
**Guardrail posture:** Obeys (1) the `src/lib/rag/**` FLAG + `RAG impact:` rule and its live-canary requirement for behaviour change; (2) ledger `#017`, which gates client payload work behind measured Web-Vitals evidence; (3) `docs/audit/capacity-review.md:123-125` explicit non-actions; (4) the provider-confirmation boundary — no OpenAI/Supabase/hosted-CI call was made.

---

Expand Down Expand Up @@ -124,7 +124,7 @@ measured-and-cleared · **L6** deliberate.
- **Evidence.** `proxy.ts:125` awaits `supabase.auth.getClaims()` on every matched request — the matcher excludes only static assets, so **every `/api/*` call** is included. Each public API route then independently resolves identity via `getOptionalAuthenticatedUser`, and `auth.ts:161` constructs a **fresh `createServerClient` per request**, with no caching of the resolved user.
- **Correction to the first-pass finding.** `proxy.ts:102-105` short-circuits when no `sb-` cookie is present, so **anonymous traffic pays nothing here**, and `getClaims()` may be local JWKS verification rather than a network call depending on the project's JWT signing algorithm. The accurate claim is _two independent identity resolutions per authenticated request, at least one of which (`getUser`) always contacts the Auth server_ — not "always two network round trips".
- **Why no memo was added.** Verified: every route resolves identity **exactly once per HTTP method handler** — the multi-call files have one call per `GET`/`POST`/`PATCH`/`DELETE`, never two per request. The real duplication spans the proxy and the route handler, which are separate invocations holding **different `Request` objects**, so no in-process memo can bridge them. A memo would dedupe nothing.
- **Capacity relevance.** `docs/capacity-review.md:106-113` names the Auth tier's ~10 absolute DB connections the **first hard failure**. Halving per-request auth resolutions is a capacity lever, not only a latency one — which is why `#099` cross-references `#011`.
- **Capacity relevance.** `docs/audit/capacity-review.md:106-113` names the Auth tier's ~10 absolute DB connections the **first hard failure**. Halving per-request auth resolutions is a capacity lever, not only a latency one — which is why `#099` cross-references `#011`.
- **Fix shape (report-only).** Have the proxy forward its already-verified claims to the route handler through a request header it controls, so the route trusts the proxy's resolution instead of repeating it. Requires care: the header must be proxy-set and unspoofable from outside.

### L1-4 · Anonymous `answer`/`document_upload` consume two sequential rate-limit RPCs
Expand Down Expand Up @@ -340,7 +340,7 @@ Recorded so the next audit cannot re-file these.
| **`#017`** | L3-1, L3-2, L3-3, L3-6, L3-7, L3-8, L4-1 | Live Lighthouse/Web-Vitals evidence first |
| **operator** | L1-4, L2-3, L2-5, + `#011` connection allocation | Hosted apply / dashboard change |

**Explicit non-actions**, per `docs/capacity-review.md:123-125`: no read replicas, no horizontal app scaling, **no retrieval concurrency semaphore** until soak data shows queueing. Its verdict — _Postgres CPU under hybrid-RPC concurrency is the first soft failure; "answer p95 inflates well before errors appear"_ — is precisely why L1/L2 round-trip reduction has capacity value beyond latency, and why a semaphore remains the wrong lever.
**Explicit non-actions**, per `docs/audit/capacity-review.md:123-125`: no read replicas, no horizontal app scaling, **no retrieval concurrency semaphore** until soak data shows queueing. Its verdict — _Postgres CPU under hybrid-RPC concurrency is the first soft failure; "answer p95 inflates well before errors appear"_ — is precisely why L1/L2 round-trip reduction has capacity value beyond latency, and why a semaphore remains the wrong lever.

---

Expand Down
File renamed without changes.
Loading
Loading