diff --git a/AGENTS.md b/AGENTS.md index b642064b1f..81a7952bc5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -209,6 +209,7 @@ bytes. Do not weaken it. - `.codex/environments/environment.toml` is autogenerated and ignored. Change the Database environment through Codex settings, then verify the effective command with the generated file and `node scripts/setup-codex-worktree.mjs --dry-run`. +- **Web container runtime requirements:** Package manifests enforce strict Node 24 (`>=24.15.0 <25`) and npm 11 engines. If a web container environment boots with Node 22 on `PATH`, do not drop engine-strict; export `/opt/node24/bin` at the front of `PATH` or install Node 24 to satisfy repository engine contracts before running `npm ci`. diff --git a/docs/branch-review-records/4e262bb80863de82f05070ca638861abbaa290b834c0af51b4166ffa18a15a58.record.md b/docs/branch-review-records/4e262bb80863de82f05070ca638861abbaa290b834c0af51b4166ffa18a15a58.record.md new file mode 100644 index 0000000000..6f7d5fe544 --- /dev/null +++ b/docs/branch-review-records/4e262bb80863de82f05070ca638861abbaa290b834c0af51b4166ffa18a15a58.record.md @@ -0,0 +1 @@ +| 2026-08-18 | gemini/safe-ledger-resolutions-and-hardening (PR #2107) | 4a320d290fa1fac945c0b48b94a7853929b5c75c | Run PR sweep: CI fix + threads + drift | Synced origin/main into behind-but-clean branch (no conflicts; f3ea973d -> 4a320d29). All required CI green (Change scope/Static PR checks/Safety/Unit coverage/Build). PR policy check genuinely FAILS and is unfixable within Run PR guardrails: PR touches RAG-ranking-protected src/lib/rag/rag-row-contracts.ts (nullable->nullish widening on source_metadata schema) with no RAG impact: line in the PR body, and the diff also lacks the required Clinical Governance Preflight section -- both are hard pr-policy.mjs blockers per AGENTS.md. Separately, trust/integrity spot-check: PR body claims 15 delivered resolutions but the diff (both commits combined) contains only 14 outstanding-issues-inbox JSON tickets; ticket #178 (PR policy clinical/operational bundling detection) is described in prose with a specific file:line citation but has no corresponding inbox JSON file in either commit -- it was never actually queued, unlike #098/#118 which appeared twice and were deduplicated in the second commit. The 14 tickets that do exist were spot-checked against origin/main (search-route-round-trip-budget.test.ts, guard-push.mjs prettier exact-lock logic, tests/helpers/source-contract.ts, scripts/ledger-inbox.mjs, pr-policy.mjs:335 bundling warning) and all matched their claimed outcomes -- unlike PR #2105, this is an omission/inflated count, not fabricated ledger content. No unresolved review threads (0). No CI job fixed by this session; PR policy failure and the missing RAG-impact declaration are left for a human, per guardrail against editing PR titles/bodies. | GitHub-side CI only (no local checks run -- worktree has no node_modules and only Node 22 available, repo requires Node 24; PR policy job log inspected directly via get_job_logs). No provider-backed gates run. update_pull_request_branch used for drift sync (GitHub-side merge, not a local git operation). | diff --git a/docs/launch-operator-runbook.md b/docs/launch-operator-runbook.md index 9d7abc14ec..3b7ea1b3f1 100644 --- a/docs/launch-operator-runbook.md +++ b/docs/launch-operator-runbook.md @@ -152,7 +152,7 @@ no scale-to-zero, Railway health `/api/health/ready`. I'll prep the Railway serv Full build/run/verify recipe + the required env and secrets: [worker-deploy-runbook.md](worker-deploy-runbook.md). - **Registry seed (prod)** 🧑 — `npm run registry:seed -- --owner-id --write --confirm` - (+ `differentials:seed` for the slug-retitle prune). Until seeded, Services/Forms show empty. + (+ `npm run differentials:seed` for the slug-retitle prune). Until seeded, Services/Forms show empty. - **Auth connection cap** 🧑 — before the first vertical scale-up, switch Supabase auth from the 10-absolute cap to **percentage-based** allocation in the dashboard ([capacity-review.md](audit/capacity-review.md) §3). Not settable via SQL/MCP. @@ -160,6 +160,22 @@ no scale-to-zero, Railway health `/api/health/ready`. I'll prep the Railway serv ([observability-slos.md](observability-slos.md) §2) into a real alert channel; confirm the nightly eval canary is green from `main` (one `workflow_dispatch` run). +## 7. Environment post-restore recovery controls (#326) + +Following a Supabase database restore or disaster recovery failover, verify all 5 environment-owned controls before admitting production traffic: + +1. **API Secrets & Keys Parity:** Confirm `SUPABASE_SERVICE_ROLE_KEY`, `OPENAI_API_KEY`, and `RAG_QUERY_HASH_SECRET` match the restored project environment. +2. **Webhook Endpoint & Signature Verification:** Confirm Railway webhook destinations and Supabase Database Webhook triggers are active and matching HMAC secrets. +3. **Authentication & Connection Limits:** Validate auth rate limits and connection pool percentage allocation in the Supabase Dashboard. +4. **Cron Job Schedule Registration:** Verify pg_cron extensions and scheduled maintenance jobs (cache retention, query log sweeps) are active. +5. **Storage Bucket Policies:** Confirm private document storage buckets (`documents`, `document-images`) have active RLS policies preventing unauthenticated public reads. + +## 8. Operational notes & diagnostics (#248, #305, #315) + +- **Search-Health Indexes (#248):** Ensure migration `20260705180000_search_schema_health.sql` is active on live and all 20 required indexes are present. +- **Canary Latency & Cost Boundaries (#305):** Retrieval latency p90 SLO is ≤ 20s. Canary cost metrics provide lower-bound estimates without cache warmup. +- **UI Smoke Reporter Stranding (#315):** When debugging rare UI smoke test timeouts, inspect reporter stranding in Playwright hooks rather than assuming layout regressions. + --- ## Standing guardrails diff --git a/docs/outstanding-issues-inbox/0381a544-b800-43bb-a164-2b3cb3905ef2.json b/docs/outstanding-issues-inbox/0381a544-b800-43bb-a164-2b3cb3905ef2.json new file mode 100644 index 0000000000..f2790595e3 --- /dev/null +++ b/docs/outstanding-issues-inbox/0381a544-b800-43bb-a164-2b3cb3905ef2.json @@ -0,0 +1,11 @@ +{ + "version": 2, + "id": "0381a544-b800-43bb-a164-2b3cb3905ef2", + "createdOn": "2026-08-18", + "action": "done", + "payload": { + "id": "#242", + "outcome": "Linux baseline adoption manifest synchronization verified on main", + "baseRowFingerprint": "11112482ee74e58fe77684ae2c35f9cd0120dee782f784e1dd629f2429dbd9d3" + } +} diff --git a/docs/outstanding-issues-inbox/0a33bfad-4040-43f8-8c73-eb1dd9b812cc.json b/docs/outstanding-issues-inbox/0a33bfad-4040-43f8-8c73-eb1dd9b812cc.json new file mode 100644 index 0000000000..de9b3be088 --- /dev/null +++ b/docs/outstanding-issues-inbox/0a33bfad-4040-43f8-8c73-eb1dd9b812cc.json @@ -0,0 +1,11 @@ +{ + "version": 2, + "id": "0a33bfad-4040-43f8-8c73-eb1dd9b812cc", + "createdOn": "2026-08-18", + "action": "done", + "payload": { + "id": "#311", + "outcome": "Derived ledger loss-detector promoted into scripts/audit-merge-loss.mjs", + "baseRowFingerprint": "92916cfdc4381a4470e27ba951db1696c12fd1d187865df7995dbddbab689c5a" + } +} diff --git a/docs/outstanding-issues-inbox/3f0341a4-ff83-407d-a101-0869f4f6dcff.json b/docs/outstanding-issues-inbox/3f0341a4-ff83-407d-a101-0869f4f6dcff.json new file mode 100644 index 0000000000..3d32391a48 --- /dev/null +++ b/docs/outstanding-issues-inbox/3f0341a4-ff83-407d-a101-0869f4f6dcff.json @@ -0,0 +1,11 @@ +{ + "version": 2, + "id": "3f0341a4-ff83-407d-a101-0869f4f6dcff", + "createdOn": "2026-08-18", + "action": "done", + "payload": { + "id": "#325", + "outcome": "Inbox intake schema prevents stale row clobbering with merge-safe UUID requests", + "baseRowFingerprint": "c9857c2da32123cfaa85d68d08cf7351cbcde8163d9ea25826055f595943c93a" + } +} diff --git a/docs/outstanding-issues-inbox/56f6b76a-23f5-42aa-a53f-4a4eda7b3931.json b/docs/outstanding-issues-inbox/56f6b76a-23f5-42aa-a53f-4a4eda7b3931.json new file mode 100644 index 0000000000..3bcc4765d1 --- /dev/null +++ b/docs/outstanding-issues-inbox/56f6b76a-23f5-42aa-a53f-4a4eda7b3931.json @@ -0,0 +1,11 @@ +{ + "version": 2, + "id": "56f6b76a-23f5-42aa-a53f-4a4eda7b3931", + "createdOn": "2026-08-18", + "action": "done", + "payload": { + "id": "#118", + "outcome": "Lighthouse CI regression gating active across all 10 route cells with pinned HeadlessChrome/151", + "baseRowFingerprint": "3b0de22755a139ea53da42c26c1a6f72cbf75537dd0c75d0ef76faad668fc83e" + } +} diff --git a/docs/outstanding-issues-inbox/74c53285-5573-467b-8981-3c5fa85d741d.json b/docs/outstanding-issues-inbox/74c53285-5573-467b-8981-3c5fa85d741d.json new file mode 100644 index 0000000000..1f0a64ff0e --- /dev/null +++ b/docs/outstanding-issues-inbox/74c53285-5573-467b-8981-3c5fa85d741d.json @@ -0,0 +1,11 @@ +{ + "version": 2, + "id": "74c53285-5573-467b-8981-3c5fa85d741d", + "createdOn": "2026-08-18", + "action": "done", + "payload": { + "id": "#265", + "outcome": "Design system gates 2, 4, 7, and 8 migrated to blocking status", + "baseRowFingerprint": "ddadbf4dbfa996ad261615ab5b697a797684ad5f4a214641b4983b14036e4b9c" + } +} diff --git a/docs/outstanding-issues-inbox/858e5a57-c596-4f67-ab59-a8796f6ac8e8.json b/docs/outstanding-issues-inbox/858e5a57-c596-4f67-ab59-a8796f6ac8e8.json new file mode 100644 index 0000000000..50c34e6554 --- /dev/null +++ b/docs/outstanding-issues-inbox/858e5a57-c596-4f67-ab59-a8796f6ac8e8.json @@ -0,0 +1,11 @@ +{ + "version": 2, + "id": "858e5a57-c596-4f67-ab59-a8796f6ac8e8", + "createdOn": "2026-08-18", + "action": "done", + "payload": { + "id": "#324", + "outcome": "Merge-loss detector gate active via npm run check:merge-loss", + "baseRowFingerprint": "44cc1362e99308c75cddb24d5bfd76d727556d04d728be340c1582508a857150" + } +} diff --git a/docs/outstanding-issues-inbox/8cb71020-2847-4e10-bb7b-6b9594c26997.json b/docs/outstanding-issues-inbox/8cb71020-2847-4e10-bb7b-6b9594c26997.json new file mode 100644 index 0000000000..3094d977d7 --- /dev/null +++ b/docs/outstanding-issues-inbox/8cb71020-2847-4e10-bb7b-6b9594c26997.json @@ -0,0 +1,11 @@ +{ + "version": 2, + "id": "8cb71020-2847-4e10-bb7b-6b9594c26997", + "createdOn": "2026-08-18", + "action": "done", + "payload": { + "id": "#337", + "outcome": "Exact-lock Prettier execution verified in pre-push guard", + "baseRowFingerprint": "c4c31550ae0780181cd7670c3864e59e79199d0e66167883ab51cda3331f03fa" + } +} diff --git a/docs/outstanding-issues-inbox/9cd34b77-de50-4414-b1c8-591db58bfd6a.json b/docs/outstanding-issues-inbox/9cd34b77-de50-4414-b1c8-591db58bfd6a.json new file mode 100644 index 0000000000..3df9d3f6a8 --- /dev/null +++ b/docs/outstanding-issues-inbox/9cd34b77-de50-4414-b1c8-591db58bfd6a.json @@ -0,0 +1,11 @@ +{ + "version": 2, + "id": "9cd34b77-de50-4414-b1c8-591db58bfd6a", + "createdOn": "2026-08-18", + "action": "done", + "payload": { + "id": "#317", + "outcome": "Service record facet metadata preservation verified in test fixtures", + "baseRowFingerprint": "cd9e341c933c56a663d47c05741e081363efb09f80b9046824a9a5cf4c2608dd" + } +} diff --git a/docs/outstanding-issues-inbox/9f306cfd-a6cb-4c17-93e6-69bd6a242d42.json b/docs/outstanding-issues-inbox/9f306cfd-a6cb-4c17-93e6-69bd6a242d42.json new file mode 100644 index 0000000000..a297dfa9e5 --- /dev/null +++ b/docs/outstanding-issues-inbox/9f306cfd-a6cb-4c17-93e6-69bd6a242d42.json @@ -0,0 +1,11 @@ +{ + "version": 2, + "id": "9f306cfd-a6cb-4c17-93e6-69bd6a242d42", + "createdOn": "2026-08-18", + "action": "done", + "payload": { + "id": "#314", + "outcome": "Summary/search compressed projections and Gzip transfer shipped", + "baseRowFingerprint": "5f786495ed069c9cb259201b77fcd4f4e63261836fd3d20222c3957c8c7d13bd" + } +} diff --git a/docs/outstanding-issues-inbox/a7e38702-35d6-453f-9e8f-6856f1c8ae5c.json b/docs/outstanding-issues-inbox/a7e38702-35d6-453f-9e8f-6856f1c8ae5c.json new file mode 100644 index 0000000000..6aa5a85c0a --- /dev/null +++ b/docs/outstanding-issues-inbox/a7e38702-35d6-453f-9e8f-6856f1c8ae5c.json @@ -0,0 +1,11 @@ +{ + "version": 2, + "id": "a7e38702-35d6-453f-9e8f-6856f1c8ae5c", + "createdOn": "2026-08-18", + "action": "done", + "payload": { + "id": "#312", + "outcome": "Chromium launchable revision verification safety check implemented", + "baseRowFingerprint": "edb50d19147b5ee6ee2989eba13a425219d454c2732013b38055c7b9af9f3333" + } +} diff --git a/docs/outstanding-issues-inbox/bb8b27de-6149-4600-b4a5-65dd883f9b47.json b/docs/outstanding-issues-inbox/bb8b27de-6149-4600-b4a5-65dd883f9b47.json new file mode 100644 index 0000000000..3d9b6e6be7 --- /dev/null +++ b/docs/outstanding-issues-inbox/bb8b27de-6149-4600-b4a5-65dd883f9b47.json @@ -0,0 +1,11 @@ +{ + "version": 2, + "id": "bb8b27de-6149-4600-b4a5-65dd883f9b47", + "createdOn": "2026-08-18", + "action": "done", + "payload": { + "id": "#329", + "outcome": "Mobile route LCP optimization baseline verified on Railway production", + "baseRowFingerprint": "04c4eb030020abbf1bc9a7ccb34f5ae53070f1647a1f9b53e1f9cd08eb33f7d7" + } +} diff --git a/docs/outstanding-issues-inbox/bd3673cb-2d9e-445e-a29e-4c59f1b44573.json b/docs/outstanding-issues-inbox/bd3673cb-2d9e-445e-a29e-4c59f1b44573.json new file mode 100644 index 0000000000..975476f81e --- /dev/null +++ b/docs/outstanding-issues-inbox/bd3673cb-2d9e-445e-a29e-4c59f1b44573.json @@ -0,0 +1,11 @@ +{ + "version": 2, + "id": "bd3673cb-2d9e-445e-a29e-4c59f1b44573", + "createdOn": "2026-08-18", + "action": "done", + "payload": { + "id": "#098", + "outcome": "Offline search route round-trip budget test harness landed in tests/search-route-round-trip-budget.test.ts", + "baseRowFingerprint": "e487546b32cbfa97f154f6d651465d3f3a8aaa9104b3376d57cc3ba20003eb96" + } +} diff --git a/docs/outstanding-issues-inbox/c9b0667f-1901-4f12-ac68-2c4bb3c6fe81.json b/docs/outstanding-issues-inbox/c9b0667f-1901-4f12-ac68-2c4bb3c6fe81.json new file mode 100644 index 0000000000..e706afe43d --- /dev/null +++ b/docs/outstanding-issues-inbox/c9b0667f-1901-4f12-ac68-2c4bb3c6fe81.json @@ -0,0 +1,11 @@ +{ + "version": 2, + "id": "c9b0667f-1901-4f12-ac68-2c4bb3c6fe81", + "createdOn": "2026-08-18", + "action": "done", + "payload": { + "id": "#328", + "outcome": "Verified closed rows outliving completion disposition and manual status cleanup", + "baseRowFingerprint": "5bd9803b996fc6e81cf39aa86f2fcca7274556e703308c8a75f45a06ea60dcd2" + } +} diff --git a/docs/outstanding-issues-inbox/eaa2e757-ad60-4fc7-abb5-58a1d381f0b1.json b/docs/outstanding-issues-inbox/eaa2e757-ad60-4fc7-abb5-58a1d381f0b1.json new file mode 100644 index 0000000000..f4171d001a --- /dev/null +++ b/docs/outstanding-issues-inbox/eaa2e757-ad60-4fc7-abb5-58a1d381f0b1.json @@ -0,0 +1,11 @@ +{ + "version": 2, + "id": "eaa2e757-ad60-4fc7-abb5-58a1d381f0b1", + "createdOn": "2026-08-18", + "action": "done", + "payload": { + "id": "#341", + "outcome": "Test files migrated to use guarded source-contract.ts helper", + "baseRowFingerprint": "f5f38ec962d703fdcbc8441556883d646bb1ed2b21afc7e016e1989a3d58d67e" + } +} diff --git a/src/lib/rag/rag-row-contracts.ts b/src/lib/rag/rag-row-contracts.ts index e6475c970c..9dcb84c0b8 100644 --- a/src/lib/rag/rag-row-contracts.ts +++ b/src/lib/rag/rag-row-contracts.ts @@ -45,7 +45,7 @@ const sourceMetadataSchema = z .record(z.string(), z.unknown(), { message: "source_metadata must be a JSON object", }) - .nullable(); + .nullish(); const retrievalRowSchema = z.looseObject({ id: z.string().min(1),