diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index 9a81fcb72b..4105503cb3 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -171,17 +171,15 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-07-30 | claude/outstanding-issues-triage-24c8ow | 8d2710fd6cbdc84e8c50a6c9bc0a1e1a0cd612c8 | open PR changed-scope review | APPROVE: completed items 095, 096, 104, 109, and 115 move to archive with no deletion, duplicate ID, or stale next-id. | check:outstanding-issues PASS; check:branch-review-ledger PASS; diff review; no unresolved threads | | 2026-07-30 | claude/latency-findings-impl-s8g01v | e7ff5e933ba1f34d5adbd46dd77c38aced11ed44 | open PR changed-scope review | APPROVE: ordering-risk documentation is accurate and the near-bottom refusal guard now proves its geometry is non-vacuous before asserting no hide. | diff check PASS; focused test review; no unresolved threads; exact-head Production UI required | | 2026-07-30 | claude/ci-testing-review-2l8klp | 2e2160bc8b9d2d824209c217c67cb9cac1be3a8d | open PR changed-scope review | APPROVE: three-way UI sharding, critical-first gating, measured drag travel, and gate-manifest updates preserve required-check aggregation and deterministic Playwright settings. | check:github-actions PASS; check:ci-scope PASS; check:gate-manifest PASS; ledger guards PASS; exact-head sharded Production UI required | -| 2026-07-30 | codex/docs-sync-automation | 76d7372d8aa886008e2fb637e5911e9c00bb33e3 | documentation synchronization automation review | APPROVE after deletion-path fix; no remaining P0-P2 findings | docs/update and static gates pass; focused Vitest admission blocked | | 2026-07-30 | PR #1430 | a9ae22ac4915e86d51ee05787059382a39bd8ba8 | phone chrome diagnostics and merge repair | fixed and ready for CI | issues guard; ledger guard; 37 focused tests; phone-chrome dry-run | -| 2026-07-30 | PR-1442 | 35fc11a2665ecd0464a23949babbbddba8055dcd | PR #1442 documentation synchronization automation | hook is fail-closed for mixed staged inputs and does not auto-stage; generated inventories remain deterministic; no findings | docs update/checks pass; focused Vitest 4 passed; issue and ledger guards pass | -| 2026-07-30 | PR-1440 | f7260cc6a0da87cb4df1ac95ef962967e667c3f0 | PR #1440 issue #102 ordering correction | accurately restores the two canary-gated retrieval ordering constraints; no findings | outstanding-issues and ledger guards pass; documentation-only diff | -| 2026-07-30 | PR-1445 | 07933e08cff6c7d81345e02c03727032ccf522b6 | PR #1445 close duplicate issue | correctly archives duplicate #140 while preserving #133 as the surviving open conflict-frequency record; no findings | outstanding-issues and docs-link guards pass; docs-only diff | | 2026-07-30 | PR-1434 | f6bebf2a8c658df8b3840c1b1133be5c94a977b0 | PR #1434 Codex Cloud setup consolidation and prompt perfector | fixed Cloud runtime verification gaps and reconciled duplicate implementation after #1438; no remaining findings | check:codex-cloud pass; codex-cloud-setup Vitest 4/4; outstanding-issues and ledger guards pass | +| 2026-07-30 | PR-1440 | f7260cc6a0da87cb4df1ac95ef962967e667c3f0 | PR #1440 issue #102 ordering correction | accurately restores the two canary-gated retrieval ordering constraints; no findings | outstanding-issues and ledger guards pass; documentation-only diff | | 2026-07-30 | PR #1432 | a2b53c815b3c060dec2619af2855a63f9f496858 | Playwright browser preflight review and repair | fixed; focused tests pending coordinator | Prettier PASS; issues guard PASS; focused Vitest blocked by active Playwright lease | | 2026-07-30 | PR #1432 | f85995ade3a19513a531713724813adc742c360d | Playwright browser preflight verification | focused tests pass; typecheck lease-blocked | 16 focused tests PASS; Prettier PASS; typecheck admission blocked | | 2026-07-30 | PR-1432 | 7c7b63cf40d59652954e539ce1b3027005916bf1 | PR #1432 Playwright browser preflight final exact-head review | fixed existing project-isolation contract after preflight refactor; no remaining findings | preflight and isolation Vitest 9/9; typecheck pass; Prettier and diff checks pass | | 2026-07-30 | PR-1432 | a5d234302b57be6f7ce5d1957c9ec00bc7f191f0 | PR #1432 Playwright preflight and phone-scroll reliability | cross-platform preflight fails closed and production focus-restore race is removed from the phone-scroll proof; no remaining findings | preflight tests 9 passed; focused Chromium journey 2 passed; formatting and ledger guards pass | | 2026-07-30 | PR-1432 | 330086eff76f704ce6b9cf5405aeecfdd375027c | PR #1432 visual-config preflight follow-up | visual runs now preflight chromium-artifacts instead of the unrelated main browser matrix; unknown configs fail closed | config-selection tests added; formatting passes; exact-head CI pending | +| 2026-07-30 | PR-1445 | 07933e08cff6c7d81345e02c03727032ccf522b6 | PR #1445 close duplicate issue | correctly archives duplicate #140 while preserving #133 as the surviving open conflict-frequency record; no findings | outstanding-issues and docs-link guards pass; docs-only diff | | 2026-07-30 | claude/organize-local-worktree-d22bc3 | 2f26a53b5aeb3df451cf7b1d04f80b07edf0d6fe | docs organisation: dated-record filing, docs index gaps, orientation maps | PR #1436 opened — 5 dated docs filed into docs/audit and docs/archive, root codex-cloud-review moved under docs/prompts, 17 docs README index gaps closed, root data/ documented in CLAUDE.md + codebase-index; no product code, schema or RAG surface touched | docs:check-links 1368 refs pass; docs:check-scripts 378 pass; docs:check-index OK; format:check whole-tree clean; verify:cheap 26 static gates + lint + typecheck pass, unit 4562 pass / 1 pre-existing Windows path-separator failure in tests/repo-hygiene.test.ts | | 2026-07-30 | PR-1436 | 9d8e081f3e7003d4f2210b00a7b7e54bf7ca2f0b | PR #1436 documentation organization and link repair | fixed stale no-driver wording and renumbered three union-collided issue records; no remaining findings | docs index, links, scripts, outstanding-issues, and ledger guards pass | | 2026-07-30 | cursor/ci-hygiene-gates-1bf5 | b660dbc5a10d7ca3da03541028017f0abc6b5bd3 | ci-hygiene-gates-merge-readiness | NOT READY: cancel-to-green behavior still allowed required PR CI to pass incorrectly; fixed at subsequent head 8f3283d00da274dee507a1b8e9b611321d1f35be | check:ci-scope; check:gitleaks-pinned; scope-classify PR files ui_changed=false; cancelled-as-neutral simulation exposed #095 | @@ -202,7 +200,15 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-07-30 | codex/issue-ledger-upload-parity | f35a4ca178724ff59e7a876c4d819bed0b786662 | PR #1441 final current-main sync | approved after merging #1457 without overlap; upload parity and repository guards remain green | upload self-test pass; issues 141; ledger 141+1206; actions pin, format, diff pass | | 2026-07-30 | codex/issue-ledger-upload-parity | dc8068590d5be469ff30789b8b345896a3f1cdb9 | PR #1441 sync after PR #1470 | approved; catalogue payload disposition and upload-limit closures both preserved | upload self-test, issues, ledger, diff pass | | 2026-07-30 | codex/cloud-readiness-consolidation-20260730 | 8ff0a7ec309c80379bd8a9a76ab107a65ac7b837 | PR #1434 Codex Cloud setup and isolation tooling | approved after current-main sync, helper typing repair, static Cloud contracts, and isolation review | codex-cloud, skills, docs, maintainability, issues, ledger, format, isolation 14/14 pass; focused Vitest coordinator-blocked; shell runtime acceptance deferred to hosted Linux | +| 2026-07-30 | codex/issue-ledger-upload-parity-v3 | 95b0e289f03afc46d45def9ed1a165cd614684fd | Replacement PR: issue closures, upload-limit parity, production env precedence | No findings; intended replacement scope preserved on current main | verify:pr-local PASS pre-rebase; exact-head runtime/install/format/lint PASS; focused guards PASS; typecheck rerun blocked by unrelated Playwright lease | +| 2026-07-30 | codex/issue-ledger-upload-parity-v3 | 9dff07f85bcce7822eb2b2701b82a80d1e0a145e | PR #1482 Docker-context CI repair | No findings; hosted ENOENT fixed without weakening effective parity | hosted app-image log inspected; normal 150/150 PASS; Docker-context 50/50 PASS; Docker-context 50/40 rejected | +| 2026-07-30 | codex/issue-ledger-upload-parity-v3 | 9867f72eddf51e25322028af6ff232dba3560871 | PR #1482 post-#1441 ledger-only salvage | No findings; duplicate implementation dropped and only four resolved issue records remain | diff vs origin/main two docs files; outstanding-issues PASS; branch-review-ledger PASS; main implementation byte-identical | +| 2026-07-30 | codex/issue-ledger-upload-parity-v3 | 0a074d9b2572ee06f663d8bbee3b50fb6d4fbd9a | PR #1482 final current-main ledger-only review | No findings; current main preserved and PR diff is ledger-only | three-dot diff two docs files; issue and review ledger guards PASS; four resolutions verified against merged main | +| 2026-07-30 | codex/issue-ledger-upload-parity-v3 | fc116cfa0cf06d359548c1bc00d383b872fb1a48 | PR #1482 upload-parity deployment-input repair | No findings; checker changes now trigger build, container, and Railway app paths | check:ci-scope PASS with single-file assertion; upload parity PASS; Railway config test queued behind primary live-provider lease | +| 2026-07-30 | claude/latency-findings-impl-s8g01v | fd3753b4c8cc041889c39f74a0f763edc358c183 | PR #1459 final docs issue review | PASS - no P0-P2 findings; restores open issue 105 and records deletion-guard gap | outstanding-issues, ledger guard, docs links, diff-check | +| 2026-07-30 | codex/issue-ledger-upload-parity-v3 | b4e68aa9e4892d4031479240f7783b7c22bd4bbb | PR #1482 final current-main review | PASS - no P0-P2 findings; ledger archives preserved and deployment inputs repaired | issues, ledger, docs links/scripts, ci-scope self-test, diff-check; hosted full unit pending | +| 2026-07-30 | codex/docs-sync-automation | 76d7372d8aa886008e2fb637e5911e9c00bb33e3 | documentation synchronization automation review | APPROVE after deletion-path fix; no remaining P0-P2 findings | docs/update and static gates pass; focused Vitest admission blocked | +| 2026-07-30 | PR-1442 | 35fc11a2665ecd0464a23949babbbddba8055dcd | PR #1442 documentation synchronization automation | hook is fail-closed for mixed staged inputs and does not auto-stage; generated inventories remain deterministic; no findings | docs update/checks pass; focused Vitest 4 passed; issue and ledger guards pass | | 2026-07-30 | codex/docs-sync-automation | fba8ab4af465c96b8aa318f25d792fefd10e9ada | PR #1442 documentation synchronization automation | approved after current-main conflict resolution, generated inventory refresh, and dirty-output preservation review | docs inventory 194/209; focused 5/5; index, links 1417, scripts 405, issues, ledger, format, diff pass; pre-commit executed successfully | | 2026-07-30 | codex/docs-sync-automation | 1c80a938f27af80df323fb1d6063ef9077f55fdf | PR #1442 hosted gate-count follow-up | approved after static CI exposed and corrected verify:cheap count drift | gate manifest, docs inventory, format, diff pass | -| 2026-07-30 | claude/latency-findings-impl-s8g01v | fd3753b4c8cc041889c39f74a0f763edc358c183 | PR #1459 final docs issue review | PASS - no P0-P2 findings; restores open issue 105 and records deletion-guard gap | outstanding-issues, ledger guard, docs links, diff-check | | 2026-07-30 | codex/docs-sync-automation | e1c514f289a864bc741841accae5352a419fbb59 | PR #1442 sync after PR #1459 | approved; issue-evidence correction and docs automation closures preserved | issues, ledger, inventory, gate manifest, diff pass | diff --git a/docs/outstanding-issues.md b/docs/outstanding-issues.md index 60440ce154..43e087d1e4 100644 --- a/docs/outstanding-issues.md +++ b/docs/outstanding-issues.md @@ -139,12 +139,10 @@ removed after current-main verification; it is not missing recommended work. | #101 | P3 | rec | Canary-gated retrieval parallelisation candidates | **Outcome:** independent retrieval stages stop running serially, proven by a live canary pair. Candidates: metadata/memory/visual hydration triples repeated on four branches (`rag.ts:2460,2493,2521` and three more) while `rag.ts:2751-2804` already parallelises three RPCs in one `Promise.all`, so the omission is inconsistency rather than intent; the nested `await`-in-loop scope enumeration (`search-scope.ts:202,328`); typeahead results never cached (`rag.ts:2698-2711`); universal-search coalescing (`/api/search` has it, `/api/search/universal` does not). Each changes candidate assembly, truncation, or what the next keystroke returns, so each needs 36/36 retrieval plus recall 1.0 and zero per-case rr regressions. Distinct from #001 (semantic rerank). Resolved #075 and #083 are the precedents for why these are gated rather than free. **Stop:** needs the #098 harness and explicit canary approval first. | `docs/audit/latency-audit-2026-07-28.md` L2-1/L2-2/L2-8/L1-5 | 2026-07-29 | | #102 | P3 | task | Apply the additive `documents` index debt (operator) | **Outcome:** bare-column `ILIKE` and the paged status scan on `documents` are index-served on hosted. `documents_title_trgm_idx` indexes a CONCATENATED expression, so the bare-column predicates in `api/documents/route.ts:193` and `rag-candidate-sources.ts:477` (RAG path) cannot use it and fall back to scanning; `search-scope.ts:271-277` sorts per page against the single-column `documents_status_idx`. **Runbook prepared 2026-07-29 — NOT applied, item stays open:** three `CREATE INDEX CONCURRENTLY` statements authored and reviewed in `docs/operator-apply-performance-latency-remediation.md` — additive, though **the "recall is byte-identical" claim was RETRACTED on 2026-07-29 review**: `fetchDocumentTitleAliasRows` (`rag-candidate-sources.ts:482`) applies `.limit(12)` with no `ORDER BY`, so a new index can change which title-alias documents feed candidate assembly. Only the documents-list use stays ordering-safe; `(status,id)` is canary-gated too — see runbook, and making that `.limit(12)` deterministic first does **not** lift the gate — an unordered `LIMIT` has no stable selection to preserve, so imposing an order can pick a different twelve and is itself an ordering behaviour change on a retrieval surface, which AGENTS.md requires a canary pair for. Sequencing the ordering fix first is worthwhile (unordered `LIMIT` on a retrieval input is latent nondeterminism regardless) but yields two canary-gated changes, not one (PR #1377 review). **Deliberately NO migration file:** an additive-index migration without a synchronized `schema.sql` mirror and regenerated drift manifest is exactly what closed PR #1312, and the mirror cannot come first because `required_indexes` in `search_schema_health()` (`schema.sql:3178`) runs against live. **Next (operator):** **author the migration first** — `supabase/migrations/` is the source of truth and `schema.sql` only a mirror, so hand-run operator SQL never reaches staging, disaster-recovery replay, or a local `supabase db reset`, and a `required_indexes` registration would fail there (PR #1377 review); follow the `20260717170000_registry_projection_cleanup.sql` idempotent pattern. **That migration must also carry the health-function change** — `required_indexes` lives inside `search_schema_health()`, which is redefined by `create or replace function` in eleven migrations (copy `20260705180000_reconcile_search_health_indexes.sql:62`); editing `schema.sql:3177` alone moves only the mirror and leaves the indexes unmonitored on hosted (PR #1377 review). Then apply concurrently, confirm `indisvalid`, mirror both the index statements and the identical function body into `schema.sql`, run `npm run drift:manifest` (Docker), and deploy the migration LAST — in that order, in one change. Expect `check:drift` to report them as unexpected between steps 1 and 2. **Rollback is three deployed phases, not the reverse of one:** retract `required_indexes` via its own `create or replace function` migration and deploy → drop concurrently live → only then deploy the `schema.sql` removal plus an idempotent forward `drop index if exists` migration, because Supabase wraps migrations in a transaction and a plain `DROP INDEX` there takes the lock the concurrent procedure exists to avoid (PR #1377 review). | `docs/audit/latency-audit-2026-07-28.md` L2-3/L2-5; `docs/operator-apply-performance-latency-remediation.md` | 2026-07-29 | | #103 | P2 | issue | Wide table-facts trigram index missing from `schema.sql` | **Outcome:** the migration chain and `schema.sql` agree on `document_table_facts` trigram indexes. `supabase/migrations/20260714190000_document_table_facts_trgm_idx.sql` creates a wide 5-column trigram index that is **absent from `supabase/schema.sql`**, so local replay and the live database can diverge. Distinct from #102: different owner and verification path. **Next:** confirm whether the wide index exists live, then take one of exactly two routes — **retained:** mirror `document_table_facts_text_trgm_idx` into `supabase/schema.sql` beside the narrow one and regenerate `drift-manifest.json`; **redundant:** drop it through a new forward migration, never by deleting `20260714190000`. **`drift-allowlist.json` is NOT a third option** (PR #1377 review): its own header scopes it to _"Known live-vs-`schema.sql` divergence"_, so it can silence a live drift finding but cannot reconcile the migration chain with the mirror — a fresh `supabase db reset` still runs `20260714190000` and creates the index while `schema.sql` still omits it, leaving this row's stated outcome unmet. **No offline gate catches this today:** the migration↔`schema.sql` parity test (`tests/drift-detection.test.ts:59-68`) only asserts one migration's `schema_drift_snapshot` function definition, not an index inventory — which is why this sits open rather than red in CI, and why a replay-to-schema inventory comparison is the check that would have caught it. Note the narrow `document_table_facts_title_row_param_trgm_idx` (`schema.sql:6425`) is the one the effective RPC expression (`:6726`) actually matches, so the wide index may be genuinely redundant — do not drop it without live scan evidence, per the monitored-not-auto-fixed index policy. | `docs/audit/latency-audit-2026-07-28.md` limitations; `npm run check:drift` | 2026-07-29 | -| #105 | P3 | task | Verify the `#017`-exempt client latency wins in a browser | **Outcome:** the two zero-payload client fixes are confirmed in a real browser. `#017` gates _payload_ decisions (#012/#013/#016 are all byte-count items); a `loading` fallback ships zero bytes and a resource hint ships ~60, so neither can be justified or refuted by a Lighthouse number — that is why neither was held behind #017. **Preconnect half DONE 2026-07-30.** Verified against a dev server started with a placeholder `NEXT_PUBLIC_SUPABASE_URL` — locally the var is unset, `supabaseOrigin()` returns null and nothing renders, so the check fails silently without it. React 19 hoists both tags out of ``: SSR HTML and the live DOM both show `preconnect` and `dns-prefetch` in ``, zero stray `preconnect` in ``, and `crossOrigin="anonymous"` preserved — load-bearing, since without it supabase-js's CORS fetches open a second connection. **`LoadingPanel` half STILL PENDING, and a claimed verification of it was WITHDRAWN 2026-07-30 — read this before re-verifying.** It was briefly recorded as done on the strength of `role="status" aria-label="Loading"` appearing in the SSR HTML of `/`, `/dsm` and `/forms`. Those hits are real but they are **not `LoadingPanel`**: that exact string has exactly one renderer in `src/`, `ModeHomePageSkeleton` (`src/components/mode-home-page-skeleton.tsx:8`), and `LoadingPanel` never emits a bare `"Loading"` label — it renders `aria-label={label}`, always a specific string such as `"Loading differentials"`. Re-checked per route against a running server: `/`, `/dsm`, `/forms`, `/differentials` and `/favourites` return **zero** `aria-label="Loading "` matches. **Why, and what it means for the technique:** Codex's mechanism finding on PR #1459 is correct — the installed Next 16 loader sets `hasSuspenseBoundary` when a `loading` element is supplied, and `BailoutToCSR` throws on the server, so a mounted `ssr:false` surface DOES emit its fallback into the response HTML. But that only fires for a surface that mounts during the initial render, and none of the eleven in `clinical-dashboard-lazy.tsx` do: every one sits behind interaction state (`answer` present, a drawer open, results present — see the mount conditions in `ClinicalDashboard.tsx:3666-4070`). So neither a cold-load grep nor a throttled cold load can observe them. **Next:** verify with a driven browser session — navigate, perform the interaction that mounts the surface, and assert its specific `LoadingPanel` label — or accept that these fallbacks are unobservable on cold load and re-scope the row to say so. **Stop:** the two sidebar dialogs are intentionally excluded — they mount on open, so a fallback would render into a closed dialog. Do not re-close this row on a cold-load grep; that is the exact mistake being withdrawn here. | `docs/audit/latency-audit-2026-07-28.md` L3-4/L3-5; `src/components/clinical-dashboard/clinical-dashboard-lazy.tsx` | 2026-07-29 | | #106 | P2 | rec | Ingestion worker and indexing agent are verified by grepping their own source | **Outcome:** the ingestion worker and indexing agent are verified by executing code, not by asserting on their own source text. **Detail:** measured 2026-07-29 via `npm run test:coverage` — `worker/main.ts` (2,015 lines) and `supabase/functions/indexing-v3-agent/index.ts` (1,966 lines) each report **0% executed lines**; no test imports either module. Both are covered only by `readFileSync` + `toContain` assertions in `worker-safe-logging.test.ts`, `worker-visual-capture.test.ts` and `document-metadata-merge.test.ts`, which pass whenever a string is present and break on harmless refactors; `document-metadata-merge.test.ts` additionally reimplements the SQL deep-merge in TypeScript and tests the reimplementation rather than the worker. Area totals: `worker/` 18.6% lines, `supabase/functions/` 4.5%. **Next:** continue the extraction pattern that already works here — `indexing-v3-agent/behavior.ts` (167 lines, 96%) and `ingestion-worker/auth.ts` (30 lines, 90%) — pulling the highest-risk decision points out of `worker/main.ts` (job claim/retry, generation commit, failure classification) into importable modules with executing tests, retiring the matching source-text assertion as each lands. Roughly cost-neutral: each extracted test replaces a grep assertion. **Stop:** do not try to make the 2,000-line entrypoint importable in one pass; extract incrementally and keep each step green. | session 2026-07-29 test-coverage analysis | 2026-07-29 | | #107 | P2 | rec | Component state matrices are the largest untested surface | **Outcome:** loading / empty / error / disabled states on interactive components are covered by executing tests, not only by E2E happy paths. **Detail:** measured 2026-07-29 — production components (excluding mockups) sit at **38.2% lines / 22.8% branch** across 12,602 lines, with **83 of 208 files at zero executed lines**; there are 51 `.dom.test.tsx` files against 195 components. Playwright does visit these routes, so they are smoke-covered, but branch coverage is where the state matrix lives and smoke journeys rarely reach it. Worst by uncovered lines: `global-search-shell.tsx` (7%), `mode-action-popup.tsx` (21%), `answer-content.tsx` (27%), `document-search-results.tsx` (32%), `universal-search-command-surface.tsx` (39%), `master-search-header.tsx` (43%). A concrete first target with clinical meaning: `calculator-ui.tsx` now covers all exported scoring logic, but `seedCheckboxDefaults`, `toggleCheckboxAnswer` and `selectOptionAnswer` stay uncovered because they are module-private and only reachable through React event handlers — `seedCheckboxDefaults` is what makes an all-negative CAGE / SAD PERSONS screen read as a valid 0 rather than incomplete, so a regression there is a false-negative risk. **Next:** treat as a per-PR convention rather than a backfill push — `docs/testing.md` already prescribes the state matrix, so the gap is enforcement. Start with `global-search-shell.tsx`, which `docs/search-chrome-behaviour.md` treats as a contract surface. Keep additions in the jsdom tier (measured ~0.54s per file) instead of new Playwright journeys (~231 production journeys already run serially at `workers: 1` against a 45-minute CI budget). **Stop:** do not chase the coverage percentage by backfilling low-risk components; the re-ratcheted broad floor in `vitest.config.mts` holds the line. | session 2026-07-29 test-coverage analysis | 2026-07-29 | | #110 | P3 | task | Design-system project token manifest lags its stylesheet | **Outcome:** the claude.ai/design token panel matches the shipped stylesheet. **Detail:** PR #1375 pushed a recompiled `_ds_bundle.css` (Clinical Sky, `--e0`–`--e4`, 4px radius grid, `--tracking-eyebrow`/`--leading-display`/`--leading-prose`) plus the four changed guideline docs to project `08d6f126`, but `_ds_manifest.json` is converter-generated and still advertises `--text-4xs: 0.5rem`, the old `--radius-lg/xl/2xl` values, and `--tw-leading`/`--tw-tracking` entries scoped to the retired `.leading-[…]` / `.tracking-[0.08em]` utilities. Rendering is correct; only the token inventory lags. Hand-editing was rejected — `kind`/`scope`/`annotation` are converter heuristics and a wrong panel is worse than a stale one. **Next:** in a session with the `/design-sync` skill, `npm ci`, then `npm install --prefix .ds-sync --no-save --package-lock=false esbuild ts-morph @types/react @tailwindcss/cli geist`, read `.design-sync/NOTES.md`, and run `resync.mjs --remote` so bundle and manifest regenerate together. **Stop:** do not hand-author `_ds_manifest.json`; the converter is not a published npm package and ships with the skill. | PR #1375; `.design-sync/NOTES.md`; project `08d6f126` (`_ds_needs_recompile` marker present) | 2026-07-29 | | #121 | P3 | issue | Container Playwright browser build lags the pinned client | **Outcome:** browser gates run in remote sessions without hand-patching. **Evidence 2026-07-30:** the repo's Playwright client resolves headless-shell build `1234`; the container image provides `1194` at `/opt/pw-browsers`, so every browser test fails at launch. Worked around in-session by symlinking `chromium_headless_shell-1234/chrome-headless-shell-linux64/chrome-headless-shell` to the `1194` `headless_shell` binary plus its sibling resources — container-local, nothing committed, and it disappears with the session. `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1` means the mismatch cannot self-heal. **Next:** decide whether the image pins the browser build or the repo pins a client matching the image; until then any remote session claiming browser proof must state which it used. **Added 2026-07-30 (session closing `#120`):** the mismatch reproduced unchanged on `main` at `c5c1a86` — `npx playwright install --dry-run chromium` reports `chromium v1234` while `/opt/pw-browsers` holds only `chromium-1194` and `chromium_headless_shell-1194`, and one `verify:phone-chrome` run lost all 13 browser tests at launch. It has now been misread twice: the 2026-07-30 handoff records 13 launch failures taken as "my change is wrong", and `#120` was filed as a gate defect from a reading taken under this condition (closed as not reproducible; the gate exits 1 correctly). **Detection, before trusting or filing anything from a browser gate:** compare `npx playwright install --dry-run chromium` against `ls /opt/pw-browsers`. **Stop:** do not file a gate defect from a run whose tests never launched — zero assertions executed, so the output describes the environment, not the diff. | `docs/testing.md`; container `/opt/pw-browsers` | 2026-07-30 | -| #125 | P3 | issue | `ui-therapy-nav-scroll.spec.ts` cites a spec file that does not exist | **Outcome:** a reader following the comment finds the coverage it names, or the comment stops naming it. **Detail:** the spec's comment points at `mode-nav-bar-anchoring.spec.ts`, left behind when PR #1390 moved `ModeNav` into the universal header; no such file exists anywhere in the repo. Harmless at runtime, but it sends the next person looking for anchoring coverage to a file that is not there, and it is the kind of stale pointer that makes a reader distrust the surrounding comments. Either repoint it at the coverage that actually exists (`ui-mode-nav-density.spec.ts`, landed in #1405) or delete the reference. | Noticed and explicitly deferred in PR #1405's body to keep that diff scoped to `#113` | 2026-07-30 | | #126 | P3 | task | Quarterly branch-review ledger rotation reminder | **Outcome:** live ledger stays navigable after #1418 L4 bootstrap. **Next:** each UTC calendar-quarter start (or when the live table feels unwieldy), run `npm run ledger:rotate -- --dry-run`, then `npm run ledger:rotate` and commit live+archive. Lookup/sweep/check already read archives. **Stop:** do not hand-move rows; do not delete unique review content. | session 2026-07-30; follow-up to #1418 / L4 | 2026-07-30 | | #117 | P2 | rec | Therapy Compass catalogue payload is the mobile LCP outlier | **Outcome:** `/therapy-compass` mobile LCP lands near the other mobile routes instead of double them. **Measured 2026-07-30** by the new pre-merge Lighthouse budget: mobile LCP 5229 ms, TBT 612 ms, CLS 0.142, against 2123-2460 ms on every other mobile route and 826 ms on desktop — so it is client-side work under mobile CPU/network throttling, not server latency. **Cause:** `useTherapyData` fetches `public/therapy-compass-data/therapies-index.json` (690 KB raw, 139 KB gzipped, 205 records x 16 fields) for the home/search/pathways screens, so the download plus JSON parse sits on the critical path before content paints. 90% of that weight is long-form clinical prose — indications 159 KB (26%), contraindicationsOrCautions 139 KB (23%), bestUsedFor 73 KB (12%), clinicalSummary 67 KB (11%), patientPopulation 59 KB (10%), targetSymptoms 48 KB (8%) — while name, slug, category, tags and setting together are 54 KB (7%). **Blocked on one decision per field group: rendered on the card, matched by search, or neither.** `therapy-card.tsx` references five of those prose fields and the same index feeds the search screen, so stripping fields could silently change clinical display or search recall. **Next:** settle that per-field question, then either pre-truncate prose that only feeds card display, or move search matching server-side / load prose on first keystroke. **Gate:** `check:therapy-data-index` plus the therapy Playwright journeys; re-measure with `npm run verify:lighthouse`. **Stop:** do not drop a field from the catalogue payload without confirming no card renders it and no search path matches on it. Same class as #013 (route-chunk / catalogue JSON weight), different route and now measured. | session 2026-07-30 Lighthouse budget first run; PR #1404 | 2026-07-30 | | #118 | P2 | task | Adopt the visual and Lighthouse baselines so the two new gates actually gate | **Outcome:** `visual-baseline` and `lighthouse-budget` stop reporting and start blocking. **Detail:** PR #1404 added both as `continue-on-error` jobs outside `pr-required`, deliberately. `tests/ui-visual-baseline.spec.ts` has no committed baselines, so all six targets fail with a missing-snapshot error by design; the job uploads them on every run (run 30513537912, artifact 8748062487, 31 files). `lighthouse-budget.json` ships `enforce: false` with `baseline: null`, so the grader warns rather than grades. **Next:** (1) download that artifact, review the six PNGs and commit them under the platform-scoped screenshots directory that `playwright.visual.config.ts` names in its `snapshotPathTemplate` — from CI, never a developer machine, because font hinting differs between them; (2) run `npm run check:lighthouse-budget -- --update` against a known-good CI build and flip `enforce`, but not before #117 or the baseline pins a known-slow route; (3) then add each job to `pr-required` and drop `continue-on-error` in the same edit. **Also:** PR #1404 added the first rendered-effect contract for #094, but 37 of the 38 unlayered visual classes still carry exemptions in `tests/helpers/style-contracts.ts` rather than contracts; and `scripts/run-lighthouse-budget.mjs` duplicates about 50 lines of the isolated-server boot in `scripts/run-playwright.mjs`, deferred to avoid destabilising the required UI gate in the same change. **Stop:** do not make a missing baseline skip instead of fail — that is the soft-skip-green pattern `AGENTS.md` forbids. | session 2026-07-30; PR #1404 | 2026-07-30 | @@ -176,6 +174,10 @@ Move resolved rows here with the resolution date and a one-line outcome. Keep th | ID | Type | Summary | Outcome | Resolved | | ---- | ----- | ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | +| #085 | rec | Upload-limit client/server sync is unguarded | Resolved 2026-07-30. A provider-free parity checker now validates both configured limits, their shared 150 MB default, invalid and over-ceiling values, and mismatches. It runs in `verify:cheap`, the static PR job, and before every production build so a client-side value cannot silently diverge from the server runtime limit. | 2026-07-30 | +| #105 | task | Verify the `#017`-exempt client latency wins in a browser | Verified 2026-07-30 in installed Chrome at 390×844. Delaying the real prescribing-workspace chunk for three seconds exposed the accessible `LoadingPanel` fallback, and an inert local Supabase origin produced matching `preconnect` and `dns-prefetch` links in `` without provider traffic. The full production Chromium gate ran; its only failure was the unrelated PWA installability assertion because installed Chrome reports `in-incognito` under Playwright. | 2026-07-30 | +| #119 | issue | `ci/circleci: verify` is failing repo-wide | Retired 2026-07-30. CircleCI was removed from the repository in commit `977982857`, and the user confirmed the integration is deleted. The prior request to inspect build 672 is obsolete; GitHub Actions remains the repository CI path. | 2026-07-30 | +| #125 | issue | `ui-therapy-nav-scroll.spec.ts` cites a spec file that does not exist | Resolved 2026-07-30. The Therapy navigation comment now points to the live `ui-mode-nav-density.spec.ts` coverage instead of the deleted `mode-nav-bar-anchoring.spec.ts` file. | 2026-07-30 | | #095 | issue | `PR required` reports failure for concurrency-cancelled jobs | RESOLVED 2026-07-30. The `pr-required` aggregate now distinguishes a cancelled job from a failed one. `require_success` / `require_skipped_or_success` are thin wrappers over one `record()` collector that reads **each job's own `result`** and appends to a `failures` or `cancellations` array; both arrays are filled before anything is reported. **Genuine failures win:** every failure is emitted as its own `::error::` and a concurrent cancellation is demoted to a `::warning::`, so a run that is cancelled AND broken cannot read as an excuse (refinement reported by Codex on PR #1409). Cancelled with nothing failing stays **RED**, and the message states the two possibilities rather than asserting supersession: it points the reader at a newer `PR required` run on the PR's current head SHA, and says that if there is none the run was cancelled by hand and must be re-run rather than merged past. It deliberately does NOT read the workflow-level cancelled status function — an earlier revision passed that through an `env:` value, which is invalid because GitHub allows those functions only in `if:` conditions, so the whole file failed to parse, ran as `.github/workflows/ci.yml` instead of `CI`, and created zero jobs; valid YAML but invalid Actions schema, so prettier and every local gate passed it. **The tempting fix was rejected as unsafe:** treating `cancelled` as neutral, or skipping the aggregate via a not-cancelled condition, would make the red disappear, but GitHub counts a SKIPPED required check as PASSING, so a hand-cancelled run on the current head would become mergeable with nothing verified — `if: always()` is therefore deliberate. Guarded by ten cases in `tests/ci-cache-safety.test.ts` that EXECUTE the extracted aggregate script under synthetic job results rather than grepping the YAML. **Corrected in review (Codex, PR #1428):** the first version of this record described a shared `cancelled_error` helper that never existed and claimed the error names the newest run; both were carried over from an obsolete sentence in the open row and neither matched the shipped implementation. Source: PR #1316 runs 30340972329 / 30341225585; PR #1409 | 2026-07-30 | | #096 | task | PR #1316 review follow-ups — adoption-gate coverage closed | RESOLVED 2026-07-30. Every sub-item is dispositioned. The band adoption gate's root-path gap closed on PR #1394 — root and href-less modes now resolve to `src/app/(search-app)/page.tsx` — and closing it surfaced two further defects in the same gate the original finding did not name: the hand-rolled walk was capped at two import hops where the root route's real chain is four, and it followed neither `layout.tsx` (where that route's band actually comes from) nor `dynamic(() => import(...))` (how the dashboard code-splits its mode workspaces). All three were fixed together with a bounded BFS, each verified load-bearing by reverting it and watching the gate fail. Four findings — favourites hub counts, the document-search status derivation, the 401 session-expiry path, the record-path duplicate notice — were already fixed independently. The Therapy Compass retry-waiter finding was corrected to NOT a live defect: `retryWaitersRef` is genuinely unscoped but no caller observes it. The seven Codex follow-up SHAs remain unreachable and were never pushed; the PR #1316 review threads are the durable source. Archived by the 2026-07-30 triage pass. Source: PR #1316 review sweep | 2026-07-30 | | #104 | rec | Worker's triple image read is deliberate, not debt | NOT DEBT — archived so a fourth audit does not re-file it. The 2026-07-28 latency audit listed L4-2 (`worker/main.ts` reads each extracted image up to 3x per document — hash, caption on cache miss, upload) as "CONFIRMED with no fix evidence", carried forward from the 2026-07-01 audit's L11. **That was wrong.** The 2026-07-01 disposition table already recorded it as a deliberate peak-memory trade-off, and the rationale is documented in place at `worker/main.ts:866-869`: holding every extracted image Buffer for a document with hundreds of multi-MB page images would multiply the worker's peak memory, and disk I/O is the cheaper resource for a background pipeline. The three reads (`:872`, `:1034`, `:1129`) are real but accepted. This row carried no next action, so it is archived rather than left open — revisit only if ingestion throughput becomes a measured complaint AND a bounded-buffer design is proposed. **Stop:** do not re-file this as debt. Source: `docs/audit/repo-audit-2026-07-01.md` L11 + disposition table | 2026-07-30 | diff --git a/railway.app.json b/railway.app.json index 732181438e..4c2367b9fc 100644 --- a/railway.app.json +++ b/railway.app.json @@ -19,6 +19,7 @@ "/src/**", "/scripts/check-client-bundle-secrets.mjs", "/scripts/check-node-engine.cjs", + "/scripts/check-upload-limit-parity.mjs", "/scripts/guard-next-build.mjs", "/scripts/install-git-hooks.mjs", "/scripts/run-heavy.mjs" diff --git a/scripts/ci-change-scope.mjs b/scripts/ci-change-scope.mjs index 9dab65f3f1..cd72d08340 100644 --- a/scripts/ci-change-scope.mjs +++ b/scripts/ci-change-scope.mjs @@ -200,7 +200,7 @@ const containerPatterns = [ "railway.worker.json", "tests/stubs/server-only.ts", /^worker\/.+/, - /^scripts\/(check-node-engine|guard-next-build|build-worker|run-heavy|check-client-bundle-secrets|install-git-hooks)\.(?:cjs|mjs)$/, + /^scripts\/(check-node-engine|check-upload-limit-parity|guard-next-build|build-worker|run-heavy|check-client-bundle-secrets|install-git-hooks)\.(?:cjs|mjs)$/, ]; const sourcePatterns = ["data", "src", "tests", "scripts", "worker", "playwright", "public", "supabase"]; @@ -217,7 +217,7 @@ const buildPatterns = [ "package.json", "package-lock.json", "scripts/check-bundle-budget.mjs", - /^scripts\/(check-node-engine|guard-next-build|dev-free-port|ensure-local-server)\.(?:cjs|mjs)$/, + /^scripts\/(check-node-engine|check-upload-limit-parity|guard-next-build|dev-free-port|ensure-local-server)\.(?:cjs|mjs)$/, ]; const staticConfigPatterns = [ @@ -736,6 +736,12 @@ function selfTest() { source_changed: true, build_changed: true, }); + assertScope("upload-limit-parity-input", ["scripts/check-upload-limit-parity.mjs"], { + source_changed: true, + coverage_changed: true, + container_changed: true, + build_changed: true, + }); assertScope( "container", [ @@ -749,6 +755,7 @@ function selfTest() { "scripts/build-worker.mjs", "scripts/run-heavy.mjs", "scripts/check-client-bundle-secrets.mjs", + "scripts/check-upload-limit-parity.mjs", "scripts/install-git-hooks.mjs", "tests/stubs/server-only.ts", "tsconfig.json", diff --git a/tests/railway-config.test.ts b/tests/railway-config.test.ts index 2345cc3e3b..cf26b4af58 100644 --- a/tests/railway-config.test.ts +++ b/tests/railway-config.test.ts @@ -71,6 +71,7 @@ describe("Railway config as code", () => { "scripts/run-heavy.mjs", "scripts/guard-next-build.mjs", "scripts/check-client-bundle-secrets.mjs", + "scripts/check-upload-limit-parity.mjs", ])("deploys the app for runtime input %s", (filePath) => { expect(triggersDeploy(app, filePath)).toBe(true); });