diff --git a/.github/workflows/ci-triage.yml b/.github/workflows/ci-triage.yml index c42ac8a5ea..de74d1bf17 100644 --- a/.github/workflows/ci-triage.yml +++ b/.github/workflows/ci-triage.yml @@ -7,10 +7,9 @@ # every open PR — this has cost debugging time before). # - needs investigation: everything else. # -# SHIPPED INERT: this event-triggered workflow does nothing until the repo variable -# CI_TRIAGE_ENABLED == "true". It never runs PR-authored code — it only reads job -# metadata via the trusted default-branch checkout, and -# posts a comment with the built-in token. +# Enabled by default. Set repo variable CI_TRIAGE_ENABLED=false to disable. +# It never runs PR-authored code — it only reads job metadata via the trusted +# default-branch checkout, and posts a comment with the built-in token. name: CI Triage on: @@ -32,7 +31,7 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 if: > - vars.CI_TRIAGE_ENABLED == 'true' && + vars.CI_TRIAGE_ENABLED != 'false' && github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.event == 'pull_request' steps: diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index af59f08424..12b8c1893f 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -171,17 +171,14 @@ 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 #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 #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-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-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 | 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 | @@ -190,7 +187,12 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-07-30 | PR #1446 / claude/ci-testing-review-2l8klp | 8be4f703d5729b4aa10e73ee8fbc77e03f400b8b | ci-testing-review-capture | Withdraws an invalid inference from the earlier records for this PR, on a correct Codex finding. Those rows argued that because the sibling documentScrollTop assertion did not fail, the scroll position held and scroll-restoration causes were ruled out. Playwright aborts a test at the first failing expect, so once anchorTop threw, documentScrollTop NEVER EXECUTED - its absence from the output shows nothing. The #142 row now says so and the class is not ruled out. The capture itself stands: the Services viewport-anchor failure is real, intermittent on byte-identical code (pass/pass/fail/pass-on-rerun), and distinct from #127. Separately CodeRabbit flagged :973 vs :1133 as inconsistent and then withdrew it: :973 is the test declaration and :1133 the thrown assertion, both reported by Playwright, and declaration lines drift (898 / 973 / 1041 across three tree states) which is why the exact title is the durable identity. | check:outstanding-issues PASS (140 rows, unique ids, next-id=143). Lesson: reasoning from an assertion that never ran is the same verified-vs-assumed error this session already hit twice in the other direction. | | 2026-07-30 | claude/x3-rag-coverage-gate-qx9j7d (PR #1454, squashed as 102bb1f) | 102bb1f5edf09e666d1be5934ff5dfb2aa5abcf0 | X3/#086 evidence coverage gate extraction from rag.ts into rag-coverage-gate.ts | clean and landed — byte-identical move verified against pre-merge main, rag.ts 5030->4780, budget ratcheted to 4780, no back-edge, public re-export preserved; squash captured 100% of branch content, nothing orphaned | workflow:rag-lab, focused vitest 81/81, check:maintainability-budgets 4780/4780, check:rag:fixtures 36 golden, eval:rag:offline 567/567, typecheck, lint, check:knip, format:check, verify:cheap 4569 passed, npm test 4569 passed, verify:pr-local build+bundle-scan, post-merge npm test on main 4574 passed | | 2026-07-30 | PR #1432 | 74adc5aa3f8a4dad659c7a40490288ef8efcb82e | Playwright browser preflight and phone-sheet focus repair | APPROVE after current-main sync: browser-project resolution fails closed, phone-sheet focus is stable, and no stale issue-ledger state remains. | 3 focused files 45 passed; phone-chrome dry-run; installed-lock parity; docs and ledger guards; formatting | +| 2026-07-30 | codex/outstanding-local-batch-final | 330d964a04406a9e123c674409f167746f7b9a28 | outstanding local task batch merge readiness | Reviewed changed scope; fixed the env-file bypass in the upload-limit parity guard. No unresolved findings. | Focused Vitest: 7 files, 125 tests passed; exact-head verify:cheap static gates and lint passed; typecheck/full unit pending coordinator availability. | +| 2026-07-30 | codex/outstanding-local-batch-final | 46ebd3f13a3e8b843026dd7d3d4024440970d7ae | upload-limit env regression type correction | Reviewed the test-only ProcessEnv annotation; no unresolved finding. | Focused test and typecheck awaiting repository coordinator; prior exact-head static gates and lint passed. | +| 2026-07-30 | codex/outstanding-local-batch-final | 7b63c28ca6ff9ab2f3599197ee6811292958e2c2 | final upload env fixture correction | Reviewed the contextual ProcessEnv construction after hosted readonly-property failure; no unresolved finding. | Prior hosted Build, Unit coverage, Production UI critical, containers and lint passed; exact-head typecheck rerun pending. | | 2026-07-30 | PR-1470 | 1932e81ece9361c08607d2ef01ad653a7df0ac8d | PR #1470 full diff vs origin/main | PASS after repair: #013 remains open and measurement-gated | check:outstanding-issues passed; docs:check-links 1408 passed; Prettier passed; git diff --check | +| 2026-07-30 | codex/outstanding-local-batch-final | 112ac9ba71f78df6e8d05d0e3fa2e3adf6ba4705 | PR #1480 Docker upload-limit review finding | FIXED P1: the Docker build now receives both server and browser limits, and container CI proves a matched lowered 50 MB pair. | check:upload-limits and check:github-actions passed; focused/typecheck/container rerun pending exact head. | +| 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-1441 | c298432cffd2a1aee1b96edda9d32deb31be7f00 | PR #1441 upload-limit parity and issue-ledger closures | upload limit guard is fail-closed and safely wired; archived rows retain their dispositions; no findings | upload parity self-test/runtime pass; issue, ledger, gate-manifest, and docs-script guards pass | | 2026-07-30 | PR #1441 | d8bd22192ce974d4d2340ff26959ee41480218e9 | PR readiness: issue ledger, upload parity, CircleCI cleanup | FIXED: review found the Docker build lacked MAX_UPLOAD_MB input and open issue #119 still requested obsolete CircleCI investigation; both are repaired, with no remaining P0-P2 findings in scope. | upload parity default and 50/50 pass; 50/40 mismatch fails; outstanding-issues, branch-review-ledger, and gate-manifest guards pass | | 2026-07-30 | PR #1441 | 0b17e849406a03b87af20e627da6500a7cd03c2e | PR readiness: issue ledger, upload parity, CircleCI cleanup | FIXED: review repaired Docker build-time server parity, archived stale CircleCI row #119, and made the #095 aggregate harness portable; no remaining P0-P2 findings in scope. | verify:pr-local PASS on parent code tree 727ed55a7: 435 files, 4570 passed, build 1694 pages, client scan pass, RAG 36 cases/21 suites; latest-main docs, issue, review-ledger, and upload guards pass | @@ -202,22 +204,19 @@ 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/outstanding-local-batch-final | 43de3c910ea1a361458586cfb0e5861e8e2d5ee6 | post-main reconciliation merge readiness | APPROVE: retained main's stronger #1441 upload guard, removed the duplicate checker/test, and preserved the six non-overlapping fixes; no unresolved findings. | Upload parity self-test/runtime, GitHub Actions, docs scripts, review ledger, outstanding issues, and diff checks pass; parent exact-head hosted suite fully green; final hosted rerun 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 | -| 2026-07-30 | codex/moderate-batch-20260730 | 1addcece5a2b7122c5898584830109f617421a3a | document accordion, auth-safe catalogue refetch, comparison contract, operator preflight | P1 late identity response race fixed; no remaining findings | verify:cheap static through owner-scope; lint; typecheck; full Vitest; Chromium UI; production-readiness | -| 2026-07-30 | pr/1467 | 6b84090a7c4a57a19521a820bf4c488090fb6062 | docs: close rejected Playwright cache proposal | approved; measured rejection archived on current main | check:outstanding-issues; check:branch-review-ledger; docs inventory/links/scripts; Prettier; diff-check | | 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 | 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 | pr/1467 | fc7abe7f7e7ecb97dc7896c16b5553256da3ad80 | docs: close rejected Playwright cache proposal | approved after current-main reconciliation; archive entry preserved | issue/ledger guards; docs inventory/links/scripts; Prettier; diff-check | -| 2026-07-30 | pr/1476 | 79822031e696cd3906ce01284ec9736938c40a74 | docs: record ESLint 10 ecosystem blocker | approved; blocker matches installed peer ranges and current main | runtime/install parity; issue/ledger; docs inventory/links/scripts; Prettier; diff-check | -| 2026-07-30 | codex/reopen-issue-105 | b94a8f5a693cc44e8aaa0fe3ec5bb65a7c313a3b | Correct #105 status after PR #1482 | No findings; restores the withdrawn verification evidence and leaves the task open | outstanding issues PASS 146 rows 69 open 77 archived next-id 149; docs links and scripts PASS | -| 2026-07-30 | codex/reopen-issue-105 | 65635235c91527c57d33dd8311d062d28ccff6d9 | PR #1483 current-main reconciliation | No findings; #105 remains open and main's #136 archival is preserved | issues PASS 146 rows 68 open 78 archived next-id 149; ledger PASS 161 live 1206 archived | | 2026-07-30 | 0b01c56fe539598279b9393db5e207bc78fa41c9 | 0b01c56fe539598279b9393db5e207bc78fa41c9 | branch-cleanup-deletion-pending | redundant clean detached head already on origin/main; removal deferred by primary-dirty lease | clean status; merge-base ancestor of origin/main; no open PR | | 2026-07-30 | 018673ff5cadadbd799815cea8d742de28922754 | 018673ff5cadadbd799815cea8d742de28922754 | branch-cleanup-deletion-pending | redundant clean detached review base already on origin/main; removal deferred by primary-dirty lease | clean status; merge-base ancestor of origin/main; no open PR | | 2026-07-30 | codex/review-pr1438 | f13c261ee96405dc338db184ec74009bcd3699a3 | branch-cleanup-deletion-pending | redundant exact head merged in PR 1438; removal deferred by primary-dirty lease | clean status; GitHub merged exact head; zero cherry-pick-unique commits | @@ -240,46 +239,52 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-07-30 | codex/review-pr1445 | 483a1c6190dfbd1a5895ef2c419a73f0f2162f05 | branch-cleanup-deletion-pending | redundant exact head merged in PR 1445; removal deferred by primary-dirty lease | clean status; GitHub merged exact head; no active process | | 2026-07-30 | PR #1462 | 5146ae94e226a6e55968d80ecefa53c7cd5df9c3 | bounded inactive-work cleanup documentation | APPROVE after fix: both cleanup batches remain deferred behind the primary-checkout lease, and the resume instruction now names the executable repository command. | outstanding-issues guard; ledger guard; diff review; one review finding fixed | | 2026-07-30 | codex/organize-inactive-20260730 | e7b248e215714fbf823c784857f521f89d86fa3d | PR #1462 changed-scope review | PASS - no P0-P2 findings; exact-lock formatter resolution fails closed | guard-push self-test and focused contracts previously green; issues, ledger, docs, diff-check; hosted full unit pending | -| 2026-07-30 | pr/1483 | 76393b9a0c6603e2551898c89a33396f52949da3 | docs: reopen issue 105 after withdrawn verification | approved; restores pending LoadingPanel verification without disturbing PR 1462 | runtime/install parity; issue/ledger; docs inventory/links/scripts; Prettier; diff-check | +| 2026-07-30 | pr/1467 | 6b84090a7c4a57a19521a820bf4c488090fb6062 | docs: close rejected Playwright cache proposal | approved; measured rejection archived on current main | check:outstanding-issues; check:branch-review-ledger; docs inventory/links/scripts; Prettier; diff-check | +| 2026-07-30 | pr/1467 | fc7abe7f7e7ecb97dc7896c16b5553256da3ad80 | docs: close rejected Playwright cache proposal | approved after current-main reconciliation; archive entry preserved | issue/ledger guards; docs inventory/links/scripts; Prettier; diff-check | | 2026-07-30 | PR-1473 | a2b2820c13a47425cfc0ea751e57ee35e9bd1105 | PR #1473 full diff vs origin/main | PASS after review repair: governance refusal and error-state contracts are consistent | outstanding-issues guard passed; docs links 1412 passed; docs index passed; Prettier passed; git diff --check | +| 2026-07-30 | codex/reopen-issue-105 | b94a8f5a693cc44e8aaa0fe3ec5bb65a7c313a3b | Correct #105 status after PR #1482 | No findings; restores the withdrawn verification evidence and leaves the task open | outstanding issues PASS 146 rows 69 open 77 archived next-id 149; docs links and scripts PASS | +| 2026-07-30 | codex/reopen-issue-105 | 65635235c91527c57d33dd8311d062d28ccff6d9 | PR #1483 current-main reconciliation | No findings; #105 remains open and main's #136 archival is preserved | issues PASS 146 rows 68 open 78 archived next-id 149; ledger PASS 161 live 1206 archived | +| 2026-07-30 | pr/1483 | 76393b9a0c6603e2551898c89a33396f52949da3 | docs: reopen issue 105 after withdrawn verification | approved; restores pending LoadingPanel verification without disturbing PR 1462 | runtime/install parity; issue/ledger; docs inventory/links/scripts; Prettier; diff-check | | 2026-07-30 | pr/1483 | a84fa60eebdbe7a00193c268b401f7abd3cc554e | docs: reopen issue 105 after withdrawn verification | approved after PR 1473 sync; issue 105 remains correctly open | issue/ledger; docs inventory/links/scripts; Prettier; diff-check | +| 2026-07-30 | pr/1476 | 79822031e696cd3906ce01284ec9736938c40a74 | docs: record ESLint 10 ecosystem blocker | approved; blocker matches installed peer ranges and current main | runtime/install parity; issue/ledger; docs inventory/links/scripts; Prettier; diff-check | | 2026-07-30 | pr/1476 | 0fd5a3cdba612d30cfd75ea997177f6e29c34bd3 | docs: record ESLint 10 ecosystem blocker | approved after PR 1483 sync; ESLint blocker and issue 105 correction preserved | issue/ledger; docs inventory/links/scripts; Prettier; diff-check | | 2026-07-30 | pr/1465 | 4e34d97bb9eb5122b9d8f8e54c42793c727f5085 | issues: record fresh #133 evidence | approved; duplicate-ID race and Prettier prerequisite accurately recorded | issue/ledger; docs inventory/links; Prettier; diff-check | | 2026-07-30 | PR #1477 | 26d713922006c1af8187994edfa76669dc14cd46 | PR #1477 fork-safe Codex autofix routing | Fixed fork routing to the PR head repository, added fail-closed metadata handling, reconciled current main, and found no remaining actionable defects. | check:codex-autofix-workflow; check:github-actions; check:pr-policy; check:outstanding-issues; check:branch-review-ledger; docs:check-inventory; docs:check-links; docs:check-scripts; typecheck; focused Vitest 53 passed; Prettier | | 2026-07-30 | PR #1477 | 20f795da2d9d0adafa6cb3117429ab3665129c0d | PR #1477 fork-safe Codex autofix routing | Refreshed onto current main after #1465; issue and ledger reconciliation remained clean and no new actionable defects were introduced. | check:outstanding-issues; check:branch-review-ledger; check:codex-autofix-workflow; focused Vitest 53 passed | -| 2026-07-30 | codex/outstanding-local-batch-final | 330d964a04406a9e123c674409f167746f7b9a28 | outstanding local task batch merge readiness | Reviewed changed scope; fixed the env-file bypass in the upload-limit parity guard. No unresolved findings. | Focused Vitest: 7 files, 125 tests passed; exact-head verify:cheap static gates and lint passed; typecheck/full unit pending coordinator availability. | -| 2026-07-30 | codex/outstanding-local-batch-final | 46ebd3f13a3e8b843026dd7d3d4024440970d7ae | upload-limit env regression type correction | Reviewed the test-only ProcessEnv annotation; no unresolved finding. | Focused test and typecheck awaiting repository coordinator; prior exact-head static gates and lint passed. | -| 2026-07-30 | codex/outstanding-local-batch-final | 7b63c28ca6ff9ab2f3599197ee6811292958e2c2 | final upload env fixture correction | Reviewed the contextual ProcessEnv construction after hosted readonly-property failure; no unresolved finding. | Prior hosted Build, Unit coverage, Production UI critical, containers and lint passed; exact-head typecheck rerun pending. | -| 2026-07-30 | codex/outstanding-local-batch-final | 112ac9ba71f78df6e8d05d0e3fa2e3adf6ba4705 | PR #1480 Docker upload-limit review finding | FIXED P1: the Docker build now receives both server and browser limits, and container CI proves a matched lowered 50 MB pair. | check:upload-limits and check:github-actions passed; focused/typecheck/container rerun pending exact head. | -| 2026-07-30 | codex/outstanding-local-batch-final | 43de3c910ea1a361458586cfb0e5861e8e2d5ee6 | post-main reconciliation merge readiness | APPROVE: retained main's stronger #1441 upload guard, removed the duplicate checker/test, and preserved the six non-overlapping fixes; no unresolved findings. | Upload parity self-test/runtime, GitHub Actions, docs scripts, review ledger, outstanding issues, and diff checks pass; parent exact-head hosted suite fully green; final hosted rerun pending. | | 2026-07-30 | PR #1480 | 6c1e76f53aee87be8408cebc295744fbdce05367 | PR #1480 bounded outstanding reliability fixes | Fixed both review findings: documented the dark accent role and added partial favourites retry without hiding valid counts; no other actionable defects found. | focused Vitest 119 passed; docs index; issue and ledger guards; Actions and Codex workflow guards; Prettier; diff check; typecheck coordinator-blocked | | 2026-07-30 | codex/close-pr1480-issues | bf8ac88b024642eb45d1fead86f4ee30fce3f98d | archive PR 1480 issue resolutions | approved: five resolved rows moved intact to archive | check:outstanding-issues; prettier check; diff check | | 2026-07-30 | codex/close-issue-127 | 9bbb8486d399ed31b9bf43364579f466a4e66c67 | archive issue 127 after post-fix runs | approved: close condition satisfied with no post-fix recurrence | check:outstanding-issues; prettier check; diff check | | 2026-07-30 | codex/close-issue-127 | d5fd28f75b404046f13507aa3705d55898d7669c | review finding wording correction | approved: causal wording now matches PR 1427 implementation | check:outstanding-issues; prettier check; diff check | | 2026-07-30 | PR-1469 | 02108d5424f8a3ab50f45808a6cc3cbd872e7555 | PR #1469 component state matrix coverage | PASS after current-main sync; tests execute enabled and disabled popup transitions plus document search loading, empty, and fault states | focused Vitest 2 files, 10 tests passed; outstanding-issues and branch-review-ledger guards passed; no unresolved review threads | | 2026-07-30 | claude/global-search-mockups-mrgmzl | e79e499839e56bff66aecc37d1c915ac3127e995 | prlanded | merged and verified by content | verify:cheap exit 0 (437 files, 4576 passed); verify:pr-local exit 0; CI pr-required green on a6f2281; squash e79e499 content diff vs branch tip empty; late aria-live/role=alert commit confirmed present on main | +| 2026-07-30 | codex/close-issue-105 | 09950abc8cf2d23455a6cbab3521bdec921ef272 | archive issue 105 after driven browser proof | approved: specific lazy fallback observed in driven desktop and phone Chromium | browser chunk-delay proof; check:outstanding-issues; prettier check; diff check | | 2026-07-30 | PR-1475 | 6de5c321beac55860cc4b6fc7d26ef5a7e088f38 | PR #1475 ingestion behavioral extraction | PASS after current-main reconciliation; extracted decisions preserve entrypoint behavior and replace the matching source-grep assertion with executable coverage | focused Vitest 3 files, 27 tests passed; typecheck passed; outstanding-issues and branch-review-ledger guards passed; provider-backed ingestion not run | | 2026-07-30 | PR-1458 | 8c1975b178c67e4c54acffc395d85e38c43d39f5 | PR #1458 superseded root-gate reconciliation | PASS: retained only unique documentation corrections after PR #1480 landed the stronger tracked-root gate; archived resolved shared-hook issue #143 | docs index and links passed; outstanding-issues and branch-review-ledger guards passed; diff check passed | -| 2026-07-30 | codex/close-issue-105 | 09950abc8cf2d23455a6cbab3521bdec921ef272 | archive issue 105 after driven browser proof | approved: specific lazy fallback observed in driven desktop and phone Chromium | browser chunk-delay proof; check:outstanding-issues; prettier check; diff check | | 2026-07-30 | PR-1448 | 8ece7f345e93170c6bd242701eaff05f5504d98b | PR #1448 authenticated live workflow | PASS after review repair: protected-main-only checkout, explicit bounded mutations, scoped secrets, and static dispatch confirmation; no live provider workflow dispatched | GitHub Actions and PR-policy guards passed; focused Vitest 3 passed; docs links and scripts, issue and ledger guards, Prettier and diff checks passed | +| 2026-07-30 | claude/capture-session-followups | bbc5d4625adcbdc32aee2f9b4fb4b0d4365d0e99 | outstanding-issues capture: unreadable CI token, at-risk worktree work, unpushed hook fix | PR #1490 opened. Ledger-only: adds #149 (PAT lacks Checks: Read so no PR verdict is readable; the working status endpoint returns total:0 rather than erroring), #150 (four already-merged worktrees hold uncommitted work existing in no branch or PR, largest +395/-200 over 19 files incl CI config), #151 (the #143 pre-commit fail-open d2fd16d54 lives only on a never-pushed branch, 17 behind main, conflicting on the file main's docs:update generator now owns). Also records that PR #1458 is superseded by #1480 and should be closed after owner confirmation | check:outstanding-issues 149 rows 60 open unique ids next-id=152; docs:check-links 1415 refs resolve; docs:check-index 49 roots/modules/routes; prettier clean | | 2026-07-30 | codex/outstanding-deletion-guard | da1bed4bcb05f2b975823c76bab0913278cfaea6 | issue 148 deletion guard | approved: no P0-P2 findings; base comparison is fail-closed in CI and preserves archive moves | verify:cheap; deletion self-test; unreadable-base proof; CI scope; GitHub Actions pin guard | -| 2026-07-30 | codex/ingestion-fixes-current-main-20260731 | fe68a0a817213ef33ddeee35b45034656986d089 | ingestion fixes replacement release readiness | ready after fixing unreachable partial-batch handling and invalid recovery owner lookup | 4 focused files 183 tests passed; typecheck passed; production-readiness READY; git diff --check passed | +| 2026-07-30 | claude/capture-session-followups | a026c0bfe70f0e9fe290abbdd3660f4c458e4115 | PR #1490 #143/#151/#149 reconciliation | corrected archived #143 fail-open claim; #151 owns remaining half; #149 separates Checks:Read from missing-gh; merged main #1491 | check:outstanding-issues; docs:check-links | +| 2026-07-30 | claude/capture-session-followups | f18dc1fb25f4687006be897f2c11a4bb1f583f41 | PR #1490 #143/#151/#149 reconciliation | reconciled after parallel remote main-sync; #143 corrected; #151 owns fail-open; #149 separates Checks vs missing-gh | check:outstanding-issues; docs:check-links | | 2026-07-30 | codex/sync-ci-anti-churn | 4f99c6d6dbcd4d2c16d5ec58183003c64d989ac8 | issue 145 anti-churn guidance | approved: guidance now covers both pushes and sync mutations without weakening cancellation | check:outstanding-issues; prettier AGENTS; diff check | | 2026-07-30 | PR-1492 | a50640970a4e4197c64fba7239aeae073445fed9 | PR #1492 branch-sync churn review | FIXED P2: exact-head queued or in-progress workflows now block automated branch updates; Run PR guidance matches the executable guard | focused Vitest 1 file, 8 tests passed; Prettier passed; sync dry-run passed on 19 open PRs; diff check passed; no provider-backed application checks run | +| 2026-07-30 | codex/ingestion-fixes-current-main-20260731 | fe68a0a817213ef33ddeee35b45034656986d089 | ingestion fixes replacement release readiness | ready after fixing unreachable partial-batch handling and invalid recovery owner lookup | 4 focused files 183 tests passed; typecheck passed; production-readiness READY; git diff --check passed | | 2026-07-30 | codex/archive-advisory-ui-scope | c8d50c7ac275212cbebf5c53fe859d863e800bbf | archive issue 137 after current-main verification | approved: implementation and fail-open self-tests remain green on current main | check:ci-scope; check:gate-manifest; check:outstanding-issues; diff check | | 2026-07-30 | PR-1494 | 807a3a09f5afc12e8db4f9158abe09d9c7b336c9 | PR #1494 pre-commit fail-open review | FIXED P2: legacy worktrees may skip a genuinely absent generator, while a staged deletion or rename now fails closed | docs-inventory Vitest 5 passed; shell syntax passed; Prettier test check passed; diff check passed | | 2026-07-30 | claude/x3-rag-coverage-gate-qx9j7d (PR #1463, squashed as dba7356f) | dba7356fc8dc926d951d6de6f019d5b8e000be21 | X3/#101 per-request hydration extraction from rag.ts into rag-hydration.ts | clean and landed — byte-identical move verified against pre-merge main, rag.ts 4780->4543, budget ratcheted to 4543, no back-edge (cluster referenced zero rag.ts-local symbols), both public re-exports preserved; squash captured 100% of branch content | typecheck, lint, check:knip, check:maintainability-budgets 4543/4543, focused vitest 83/83 incl rag-query-concurrency, eval:rag:offline 572/572 36 golden, format:check, verify:cheap, verify:pr-local build+bundle-scan, post-merge content verification on main | | 2026-07-30 | dba7356fc8dc926d951d6de6f019d5b8e000be21 | dba7356fc8dc926d951d6de6f019d5b8e000be21 | X3 hydration unit: per-request hydration extraction from rag.ts into rag-hydration.ts (PR #1463) | clean and landed — byte-identical move verified against pre-merge main, rag.ts 4780->4543, budget ratcheted to 4543, no back-edge, both public re-exports preserved. Supersedes the earlier row for this HEAD, which was keyed only to the slash-form branch token and so returned NOT REVIEWED on a landed-SHA lookup; it also mislabelled the unit as #101, which is the unrelated open canary-gated retrieval-parallelisation recommendation | typecheck, lint, check:knip, check:maintainability-budgets 4543/4543, focused vitest 83/83, eval:rag:offline 572/572 36 golden, format:check, verify:cheap 442 files 4625 passed, verify:pr-local, post-merge content verification on main | +| 2026-07-30 | claude/capture-session-followups | 4a041fcd2ac8f12e4ebb0ab68e0151722db65bcf | PR #1490 main sync + #151 close | merged origin/main (clean tree; GitHub DIRTY was ledger-driver staleness); archived #151 via #1494; #143 fully resolved; review threads already addressed | check:outstanding-issues; docs:check-links; merge-tree clean | +| 2026-07-30 | claude/capture-session-followups | adc4e2e86edce33849ec9c8080b8f0be86155734 | PR #1490 main sync after #1496 id collision | merged c8e53d57; kept main #149/#150; archived #151 via #1494; renumbered this PR's open rows to #152/#153; #143 fully resolved | check:outstanding-issues; docs:check-links; merge-tree clean | +| 2026-07-30 | PR-1433 | e7a8102620b5b4847894b3df21f438304ea581bd | PR #1433 document result cards and action menu final review | fixed clipped menu, clipboard fallback focus loss, and inherited action typography; no remaining findings | DOM Vitest 4/4; focused Chromium 1/1; typecheck, Prettier, and diff checks pass | +| 2026-07-30 | PR #1474 | 098186866932394d2cc17983e566ae6c44b063b4 | PR #1474 full diff vs origin/main | approved | verify:cheap; eval:rag:offline; live canary 30578169116 -> 30579534353 | | 2026-07-30 | codex/coverage-scope-policy | 94f97cdb1d0543724de408f19e79d64e61c8b31a | issue 139 coverage scope policy | approved: workflow coverage breadth is deliberate and test-pinned; docs-like skills remain static-only | check:ci-scope; check:gate-manifest; check:outstanding-issues; prettier; diff check | | 2026-07-30 | codex/coverage-scope-policy | 4da2a003bc2254507662d1b8b6e9768e94371abd | issue 139 coverage scope policy post-sync | approved: late main sync preserves deliberate workflow coverage and static-only skill policy | check:ci-scope; check:outstanding-issues; check:branch-review-ledger; diff check | | 2026-07-30 | codex/archive-completed-ci-tasks | 5c902f422ceee78ef68132900fda734c1d5bc1f8 | archive issues 133 and 135 | approved: both rows were already resolved on current main and focused guards prove their contracts | check:ci-scope; check:outstanding-issues; check:branch-review-ledger; diff check | | 2026-07-30 | codex/next-local-task | 3e6d6d69c15fc056773657e15879ba2283fa2899 | archive issues 129 and 132 | approved: documented constraints satisfy both explicit outcomes without overstating client-side enforcement | guard:push:self-test; focused vitest 24/24; check:github-actions; check:outstanding-issues; diff check | -| 2026-07-30 | PR #1474 | 098186866932394d2cc17983e566ae6c44b063b4 | PR #1474 full diff vs origin/main | approved | verify:cheap; eval:rag:offline; live canary 30578169116 -> 30579534353 | -| 2026-07-30 | PR-1433 | e7a8102620b5b4847894b3df21f438304ea581bd | PR #1433 document result cards and action menu final review | fixed clipped menu, clipboard fallback focus loss, and inherited action typography; no remaining findings | DOM Vitest 4/4; focused Chromium 1/1; typecheck, Prettier, and diff checks pass | | 2026-07-30 | claude/design-visual-baselines | b57432facb7ded1e9605d1076e0d8c9d661efa2c | open PR changed-scope review | APPROVE after fix: platform-scoped baseline guidance matches the candidate-path and AWAITING_BASELINE adoption contract. | Prettier PASS; docs:check-links PASS; check:ci-scope PASS; review thread resolved; exact-head visual CI required | | 2026-07-30 | pr/1431 | 74e10087eb20a81279fb56d18f28a2475d895fab | docs: visual baseline platform layout | approved; candidate adoption and Linux baseline guidance match implementation | runtime/install parity; ledger; CI scope; docs inventory/links; Prettier; diff-check | | 2026-07-30 | pr/1431 | b4848aa92e890193a4a41744b611746673f3b058 | docs: visual baseline platform layout | approved after remote-head reconciliation; guidance unchanged | ledger; CI scope; docs inventory/links; Prettier; diff-check | | 2026-07-30 | pr/1431 | 897de9b1b7fc243006c1a71e67a6333681272ac6 | docs: visual baseline platform layout | approved after PR 1462 base sync; visual guidance unchanged | ledger; CI scope; docs inventory; Prettier; diff-check | +| 2026-07-30 | claude/capture-session-followups | 7954c044dd16e0669d417e09d6b6192a4df0e72d | PR #1490 main sync | merged origin/main 9af15e1f (clean tree; GitHub DIRTY was merge=ledger staleness); kept #152/#153 and clarified #153 snapshot wording; #151/#143 remain archived | check:outstanding-issues; docs:check-links; merge-tree clean | | 2026-07-30 | codex/ledger-next-20260730 | 268b201a1dbaed7cca6dff4a146b0319a5275216 | issue ledger closures, favourites partial-source status, CI and ledger guards | FIXED. No remaining P0-P2 findings. Reconciled current main row by row, retained current-main #105 and #136 dispositions, rejected the unsafe Playwright cache, and fixed favourites partial-source masking plus the indexed-search hydration race. | format PASS; static gates, lint, typecheck PASS; unit 4597 PASS, 3 SKIP, 1 stale donor failure repaired by exact-lock dependency; brace cap direct PASS; focused Chromium 1 PASS; production build PASS; ledger guards PASS | | 2026-07-30 | codex/ledger-next-20260730 | 1ee749bd71da45be2d6b9d3eb4913331696996a6 | issue ledger closures, favourites partial-source status, CI and ledger guards | FIXED. Supersedes the prior review after cleanly merging current main. No remaining P0-P2 findings; current-main #079 was retained, verified closures remained archived, and no product behavior changed during sync. | merge reconciliation + ledger:dedupe PASS; outstanding and branch ledger guards PASS; whole-tree format PASS; prior static, lint, typecheck, unit, build, RAG fixture, and focused Chromium evidence retained | | 2026-07-30 | codex/ledger-next-20260730 | ee66a39b63fd7e39448ab13a5a5b72441f5321be | issue ledger closures, favourites partial-source status, CI and ledger guards | FIXED. Supersedes prior reviews after merging current main answer-delivery design. No remaining P0-P2 findings; current-main #100 governance text was retained exactly, verified closures remained archived, and the sync added documentation only. | merge reconciliation + ledger:dedupe PASS; outstanding and branch ledger guards PASS; prior format, static, lint, typecheck, unit, build, RAG fixture, and focused Chromium evidence retained | @@ -314,12 +319,6 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-07-30 | PR-1507 | 12e5c8c977a873a7b900596fdc310a1a78d863f0 | PR #1507 final current-main review | APPROVE; architecture-specific container lookup and immutable-root fail-closed fallback are preserved after current-main reconciliation; no remaining P0-P2 findings. | focused Vitest 2 files / 40 tests PASS; tsc --noEmit PASS; issue/ledger/format/diff guards PASS | | 2026-07-30 | PR-1507 | 12e5c8c977a873a7b900596fdc310a1a78d863f0 | PR #1507 current-main merge and ledger normalization | APPROVED — no findings after current-main sync; feature diff unchanged and ledger reduced to three unique append-only review rows. | focused Vitest 2 files/40 tests PASS; outstanding-issues PASS; branch-review-ledger PASS; diff check PASS; merge-tree f8f88bd79706c2fb36637014a25e93af6e08eb99 | | 2026-07-30 | PR-1507 | 5e22b89f7bdb73335d12a0cf4091915615b20dd7 | PR #1507 remote ancestry reconciliation | APPROVED — identical-tree remote merge ancestry reconciled without content change; no remaining findings. | focused Vitest 2 files/40 tests PASS on identical tree; issue and ledger guards PASS; diff check PASS; merge-tree d6594063a4aa2c5f8b7a9ec72c1c41c94e6937fa | -| 2026-07-30 | claude/capture-session-followups | bbc5d4625adcbdc32aee2f9b4fb4b0d4365d0e99 | outstanding-issues capture: unreadable CI token, at-risk worktree work, unpushed hook fix | PR #1490 opened. Ledger-only: adds #149 (PAT lacks Checks: Read so no PR verdict is readable; the working status endpoint returns total:0 rather than erroring), #150 (four already-merged worktrees hold uncommitted work existing in no branch or PR, largest +395/-200 over 19 files incl CI config), #151 (the #143 pre-commit fail-open d2fd16d54 lives only on a never-pushed branch, 17 behind main, conflicting on the file main's docs:update generator now owns). Also records that PR #1458 is superseded by #1480 and should be closed after owner confirmation | check:outstanding-issues 149 rows 60 open unique ids next-id=152; docs:check-links 1415 refs resolve; docs:check-index 49 roots/modules/routes; prettier clean | -| 2026-07-30 | claude/capture-session-followups | a026c0bfe70f0e9fe290abbdd3660f4c458e4115 | PR #1490 #143/#151/#149 reconciliation | corrected archived #143 fail-open claim; #151 owns remaining half; #149 separates Checks:Read from missing-gh; merged main #1491 | check:outstanding-issues; docs:check-links | -| 2026-07-30 | claude/capture-session-followups | f18dc1fb25f4687006be897f2c11a4bb1f583f41 | PR #1490 #143/#151/#149 reconciliation | reconciled after parallel remote main-sync; #143 corrected; #151 owns fail-open; #149 separates Checks vs missing-gh | check:outstanding-issues; docs:check-links | -| 2026-07-30 | claude/capture-session-followups | 4a041fcd2ac8f12e4ebb0ab68e0151722db65bcf | PR #1490 main sync + #151 close | merged origin/main (clean tree; GitHub DIRTY was ledger-driver staleness); archived #151 via #1494; #143 fully resolved; review threads already addressed | check:outstanding-issues; docs:check-links; merge-tree clean | -| 2026-07-30 | claude/capture-session-followups | adc4e2e86edce33849ec9c8080b8f0be86155734 | PR #1490 main sync after #1496 id collision | merged c8e53d57; kept main #149/#150; archived #151 via #1494; renumbered this PR's open rows to #152/#153; #143 fully resolved | check:outstanding-issues; docs:check-links; merge-tree clean | -| 2026-07-30 | claude/capture-session-followups | 7954c044dd16e0669d417e09d6b6192a4df0e72d | PR #1490 main sync | merged origin/main 9af15e1f (clean tree; GitHub DIRTY was merge=ledger staleness); kept #152/#153 and clarified #153 snapshot wording; #151/#143 remain archived | check:outstanding-issues; docs:check-links; merge-tree clean | | 2026-07-30 | claude/capture-session-followups | 6bd0c3f85743c5406d49474bb7a92956fa44c0d2 | PR #1490 merge conflict | merged origin/main; resolved outstanding-issues against #1508 IDs; kept pre-snapshot wording | check:outstanding-issues,docs:check-links | | 2026-07-30 | claude/capture-session-followups | bdd27597e9b9d72d56940cd9a55c8000f9bbe1fc | PR #1490 merge conflict | merged origin/main; resolved outstanding-issues against #1508 IDs; kept pre-snapshot wording | check:outstanding-issues,docs:check-links | | 2026-07-30 | claude/capture-session-followups | e47c9d410a2eaaffd73af9e41dc57113f8cc9ef1 | PR #1490 merge conflict | merged origin/main; resolved outstanding-issues against #1508 IDs; kept pre-snapshot wording | check:outstanding-issues,docs:check-links | @@ -330,7 +329,6 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-07-31 | claude/root-dir-coverage-gate-v2 | 398660144d93aeefc2e5649c156948a68925cb64 | docs:check-index repo-root coverage, stale script counts, ledger correction | MERGED as PR #1458 (squash 907fd9f4a). Root-directory coverage pass for docs:check-index, red-then-green proven (flagged .cursor/.design-sync/.vscode, then 49 entries vs 31). Main landed an equivalent pass independently in #1480, so the two overlapped; no duplication reached main. Row not recorded at the time - appended retrospectively | verify:cheap exit 0, 435 test files / 4574 tests pass; codebase-index-coverage 10/10 incl 4 new root cases; eslint clean; docs gates green; prettier clean | | 2026-07-31 | claude/pre-commit-fail-open | 7b96a09b8500adc917cf5549b1c61142b2244b39 | pre-commit hook fail-open when the inventory script is absent | MERGED as PR #1494 (squash 387c3b653). Resolves ledger #153: core.hooksPath is absolute to the primary checkout, so the hook ran in worktrees lacking scripts/update-docs-inventory.mjs and aborted with MODULE_NOT_FOUND. Guard drops the inventory task and re-checks the all-tasks-empty exit; grep carries \|\| true because set -e treats a fully-filtering grep as failure | isolated-repo probe with the script genuinely absent: prints skipping inventory sync, commit succeeds; sh -n clean; no-op when the script is present; prettier does not parse shell so format:check skips it | | 2026-07-31 | claude/ledger-relanding | 30ec06964e4235d9f0b4bb782f357e6b4fb59430 | re-land the three session findings lost when PR #1490 was closed | MERGED as PR #1508 (squash 7b551abc4). Ledger-only: #151 corrects the claim that CI is unreadable (PAT has Actions:read though not Checks:read), #152 re-lands the at-risk worktree inventory with the four preservation snapshots, #153 archives the hook fix. Verified landed by content on main, not by PR state or row id | CI, PR Policy, PR mergeability, SAST, Secret Scan all completed/success via the Actions API; check:outstanding-issues 151 rows 45 open unique ids next-id=154; docs:check-links 1414 refs; prettier clean | -| 2026-07-31 | codex/moderate-batch-20260730 | d582c49fe3a2f01bad179d06f84484754b639458 | PR #1485 accordion/catalogues | APPROVE after Bugbot/CodeRabbit triage; fixed differential LRU soft-success on Retry and credential/error pulses; no open review threads; merge-tree clean vs main | vitest catalog DOM 12/12; check:outstanding-issues; merge-tree clean; Bugbot: no cursor[bot] threads; CodeRabbit threads resolved | | 2026-07-30 | PR-1490 | 0a44df55532fcea3cf3b8cad28526ff8805d803b | PR #1490 consolidated session follow-ups | reviewed; consolidated accurate provider-token, preserved-worktree, install-parity, CodeRabbit, hook, and physical-device findings; resolved concurrent documentation conflict without lost rows | check:outstanding-issues pass; check:branch-review-ledger pass; docs:check-links pass; git diff --check pass | | 2026-07-30 | PR-1492 | 4fdc4ba99f94a369702c747b104fa4eaf48cb53e | PR #1492 exact-head branch-sync anti-churn review | approved after P2 repair; current helper fails closed on Actions lookup errors and defers only behind branches with queued or running exact-head CI; operator guidance and tests match | focused Vitest 9 tests passed on reviewed implementation; hosted static checks passed; exact-head coverage in progress at review; merge-tree audit clean | | 2026-07-30 | PR-1495 | 99c62cf3bd6f2a47d13b6602d54de1f8f73123e1 | PR #1495 hydration documentation correction | approved after correcting unrelated issue #101 label and appending a resolvable landed-SHA hydration review record; content consolidated into PR #1490 | outstanding-issues and ledger guards previously passed; documentation-only diff reviewed; no provider checks required | @@ -347,5 +345,9 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 2026-07-31 | PR-1510 | eed59358ffdb588c3015ef317de4587d14ea00cf | PR #1510 reopen-ready evidence correction | FIXED: removed false #098 canary attribution; NOTES #154->#157 and restored 7/4/3 token accounting; mockup tokens unchanged | check:outstanding-issues PASS; check:branch-review-ledger PASS; check:design-system-contract PASS; format:changed PASS; canary ancestry vs origin/main/work verified | | 2026-07-31 | PR-1510 | 61d25fd7727c2345fabb9631d604b1632bc0df6d | post-1513 concurrency-note reconciliation | no actionable findings; preserved main 155, renumbered withdrawn guard to 158, and advanced next-id to 159 | outstanding-issues, branch-review-ledger, design-system-contract, changed-format, diff-check | | 2026-07-31 | PR-1510 | 2e8821c77fcadaa283d8a0033b1a6af815458d79 | PR #1510 CodeRabbit + evidence reopen-ready | FIXED: CodeRabbit computed-value-time wording, unique #033 queue order, deduped #098 Done block; prior false canary attribution already corrected | check:outstanding-issues PASS; format:changed PASS; contains origin/main | +| 2026-07-31 | cursor/ci-followups-093-138-1bf5 | 299698480cb120483ea16895b9265ad2abf5d595 | closed-PR reopen prep | ready-for-reopen; merge-clean vs origin/main after resolving outstanding-issues; no open review threads; no P0-P2 findings; PR left CLOSED | check:outstanding-issues,check:ci-triage,check:github-actions,merge-tree-clean | +| 2026-07-30 | codex/moderate-batch-20260730 | 1addcece5a2b7122c5898584830109f617421a3a | document accordion, auth-safe catalogue refetch, comparison contract, operator preflight | P1 late identity response race fixed; no remaining findings | verify:cheap static through owner-scope; lint; typecheck; full Vitest; Chromium UI; production-readiness | +| 2026-07-31 | codex/moderate-batch-20260730 | d582c49fe3a2f01bad179d06f84484754b639458 | PR #1485 accordion/catalogues | APPROVE after Bugbot/CodeRabbit triage; fixed differential LRU soft-success on Retry and credential/error pulses; no open review threads; merge-tree clean vs main | vitest catalog DOM 12/12; check:outstanding-issues; merge-tree clean; Bugbot: no cursor[bot] threads; CodeRabbit threads resolved | | 2026-07-31 | claude/ci-testing-review-2l8klp | fa304a5332443f544a676bdf35d813797154f87c | PR #1466 reopen-prep | READY: main merged (clean), phoneContract sibling arm fixed+pinned, Codex Cloud origin inspect uses configured URL (insteadOf-safe), prior Codex/Copilot/CodeRabbit threads resolved, no cursor[bot] Bugbot findings, PR left CLOSED | verify:cheap PASS (444 files / 4652 passed, 4 skipped); prettier --check . PASS; check:ci-scope PASS; verify-phone-chrome+codex-cloud-setup+test-runner-safety+playwright-project-isolation 59/59; merge-tree clean before merge; Bugbot none | | 2026-07-31 | PR-1485 | f4f42fbc5b4a73d0037c8c275a358d265727e0fc | post-review document accordion and catalogue sync | APPROVE; post-review changes limited to differential refetch memoization and current-main sync; no remaining findings | installed-lock parity; focused catalogue/document suites 3 files 19 tests PASS; typecheck PASS; issue and review-ledger guards PASS; zero unresolved threads | +| 2026-07-31 | PR-1515 | 239a2ce6d708f8e1a6ac891c997baefec67cd9ab | PR #1515 CI triage and visible Playwright roots | No high-confidence defects; default-enabled trusted CI triage and visible-owner Playwright helper reviewed | check:installed-lock-parity; check:ci-triage; check:github-actions; check:outstanding-issues; check:branch-review-ledger; typecheck | diff --git a/docs/outstanding-issues.md b/docs/outstanding-issues.md index 70deeaec5a..62493354b9 100644 --- a/docs/outstanding-issues.md +++ b/docs/outstanding-issues.md @@ -120,7 +120,6 @@ removed after current-main verification; it is not missing recommended work. | #079 | P3 | task | Disposition retained worktrees in bounded cleanup batches | **Outcome:** the retained reconciliation tail is gradually classified without another disruptive all-worktree sweep. **Next:** after the primary checkout is clean and `npm run check:primary-checkout-lease` allows writes, revalidate and remove the twenty clean redundant candidates recorded on 2026-07-30 with `branch-cleanup-deletion-pending`; then process no more than ten further worktrees per explicitly scheduled pass using current owner/process metadata, open-PR state, exact review-ledger coverage, ancestry, and cherry-pick-aware content proof. **Success:** remove only clean, inactive, bundled worktrees whose content is merged or explicitly rejected; record every disposition and retain recovery evidence. **Stop:** preserve dirty, active, secret-bearing, post-freeze, paused, or ambiguous work and never use reset, force deletion, broad clean, or process killing. | final reconciliation inventory retained 104 independent worktrees; session 2026-07-24; 2026-07-30 bounded review found 20 redundant candidates across two bounded batches but the primary-dirty write lease blocked removal | 2026-07-30 | | #086 | P3 | task | Repository maturity backlog — remaining structural work | **Outcome:** the deferred repository-maturity backlog ships as verified draft PRs, one per structural change. **Canonical runbook:** [`docs/maturity-backlog-workorders.md`](maturity-backlog-workorders.md). **Remaining:** X3 `rag.ts` decomposition (in progress); X7 finish the `src/lib` domain reorg; X6 clinical/retrieval/answer coverage floors; X5 ACL-migration consolidation (provider-gated); L1 archive the retired `backfill:*` one-shots + the dead `ci-change-scope` token; M1 repo-host hardening (maintainer, audit §8). **Shipped:** L4 ledger rotation (#1418 — `ledger:rotate`, live/archive corpus, `merge=ledger`). **X3 progress:** the evidence coverage gate shipped as `src/lib/rag/rag-coverage-gate.ts` (PR #1454, squashed `102bb1f`) — `evaluateEvidenceCoverageGate` + `applyCoverageGateTelemetry` moved byte-identically, `rag.ts` 5,030 → 4,780, budget ratcheted to 4,780, no back-edge, `evaluateEvidenceCoverageGate` still re-exported from `@/lib/rag/rag`. **Hydration unit SHIPPED (X3 hydration; PR #1463, squashed as `dba7356f`):** `src/lib/rag/rag-hydration.ts` now owns the hydration cluster is `createDocumentRankingMetadataCache` / `attachDocumentRankingMetadata` / `withCachedIndexQuality` / `attachIndexQualityMetadata` / `attachPageVisualEvidence` plus the `DocumentRankingMetadataCache` type (byte-identical move; `rag.ts` 4,780 → 4,543, budget ratcheted to 4,543). **It did NOT on its own unblock `prepareCoverageGateResults`**, exactly as the 2026-07-30 Codex finding on PR #1461 predicted (the original claim that it re-homed all five dependencies was wrong, and shipping it confirmed that). That function needs five `rag.ts`-only runtime symbols, and hydration accounts for only two of them (`attachDocumentRankingMetadata`, `attachPageVisualEvidence`). The other three sit outside the cluster and are a separate seam: `selectRankedRetrievalResults` (`rag.ts:1825`, retrieval selection), `applySecondStageRerankIfNeeded` (`rag.ts:679`, second-stage ranking), and `measureSearchPhase` (`rag.ts:1975`, the shared pipeline timing wrapper — 21 references across the file, of which only `metadata_hydration` and `visual_hydration` are hydration phases, so it belongs with the search orchestrator/telemetry, not with hydration). So `prepareCoverageGateResults` can only move after BOTH hydration and that ranking/timing seam are re-homed; it stayed in `rag.ts` for #086 because a back-edge and a signature change were both refused. Verify with a symbol-location plus call-site search before planning the boundary — do not treat hydration alone as sufficient. **Next:** remaining X3 units on user go-ahead. **Stop:** RAG/retrieval items need the flag + go-ahead; X5 is live-DB provider-gated. | `docs/maturity-backlog-workorders.md`; audit §8/§10; session 2026-07-28 | 2026-07-28 | | #090 | P2 | task | Upgrade the eslint ecosystem to clear remaining dev-scoped high advisories | **Outcome:** full `npm audit` reports zero high advisories from the eslint toolchain. **Blocked 2026-07-30:** the stable ecosystem still has no compatible ESLint 10 set. `eslint-config-next@16.2.12` permits ESLint 10 but bundles `eslint-plugin-react@7.37.5`, `eslint-plugin-import@2.32.0`, and `eslint-plugin-jsx-a11y@6.10.2`; each plugin's published peer range still ends at ESLint 9, and the React plugin retains the previously reproduced removed-context-API crash. Keep the Dependabot major hold and ESLint `9.39.5`; do not force an invalid peer graph merely to make the audit report green. **Next:** recheck after those three plugins publish stable ESLint 10 support, then upgrade eslint and the complete plugin/config set together. Residual highs (`@eslint/config-array`, `@eslint/eslintrc`, `eslint`, `eslint-config-next`, `eslint-plugin-import`, `eslint-plugin-jsx-a11y`, plus the advisory's numeric `<=5.0.7` hit on the unused `brace-expansion@1.1.16` / `2.1.2` maintenance lines that still ship an unpatched `main`) cascade from this dev-only toolchain. **Success:** peer-valid install, `npm run lint` clean, `verify:cheap` green, full-audit highs cleared, no rule-config regressions. **Stop:** do not use `npm audit fix --force` or override plugin peer ranges. Production `npm audit --omit=dev` is already clean after the exceljs `archiver@8` / `unzipper@0.12.5` overrides on PR #1314. | stable npm metadata recheck 2026-07-30; session 2026-07-28 brace-expansion triage (PR #1314) | 2026-07-30 | -| #093 | P2 | issue | Next streaming `S:` clone causes Playwright strict-mode violations under CI load | **Outcome:** duplicate-element strict-mode failures stop appearing on loaded CI runs. **Detail:** under full-suite CI load Next.js leaves a hidden duplicate page root in the stream, so a `getByTestId` that is unique locally resolves to 2 elements in CI (seen as `differentials-search-results` on PR #1316, and previously noted on PR #1294 against main). It does not reproduce in isolation, on a single spec, or locally. The documented workaround is to scope the locator to the visible root. **Reproduced locally 2026-07-28** (isolated _production_ build via `run-playwright.mjs`, full `verify:ui`): `ui-tools.spec.ts:563` duplicated `forms-home` and `ui-smoke.spec.ts:3001` duplicated `favourite-row-lithium-monitoring-guideline`; in both, copy 1 is nested under `mobile-composer-reserve-pad`. Both pass when run alone, so it is load/order-dependent, not build-mode dependent — this also corrects an earlier note that CI uses `next dev`; it does not. **Strongest evidence (CI run `30345484316`, 2026-07-28): `ui-overlap.spec.ts:199` on `/` asserted `toHaveCount(1)` successfully and then the same `header#search` locator resolved to 2 a statement later, one of them hidden.** A duplicate that appears _after_ a passing count assertion is a stream/hydration artifact by construction, not a static double mount and not something a CSS or component change can cause. That makes four distinct testids across four specs with the identical shape. **Mitigated, not fixed, on `main` (2026-07-28):** `3a8edb93` rewrapped `gotoHome` in `tests/ui-overlap.spec.ts` to retry count-and-visibility together via `toPass`, so a transient second header no longer trips strict mode there — its own note says "checking count then immediately calling waitFor races that flicker into a strict-mode violation". That hardens one helper; the duplicate root itself is unchanged and other specs remain exposed. **Confirmed pre-existing:** at `631d90d2`, the commit before PR #1316's first commit, that spec already documented "two `header#search` nodes" and "a second transient `header#search` can exist briefly" — so this predates that branch. **Next:** with a full-suite repro now available, bisect the preceding specs to find the state that triggers the second mount, then either scope the shared helpers to the visible root once or fix the mount. **Stop:** do not paper over new occurrences with `.first()` before the duplicate itself is explained. | PR #1316 CI runs; PR #1294 note on main; session 2026-07-28 | 2026-07-28 | | #098 | P2 | task | Offline round-trip budget harness for the hot routes | **Outcome:** per-scenario Supabase round-trip counts are pinned by a test, so an extra round trip on a hot path is a red gate rather than an inference. **Done 2026-07-29:** the measurement gap is closed — `Server-Timing` now covers `auth`/`ratelimit`/`scope` on `/api/answer`, `auth`/`ratelimit`/`search`/`total` on `/api/search`, and `auth`/`ratelimit` on `/api/answer/stream` (previously the route the UI actually calls emitted no header at all). Headers flush before the first SSE frame, so in-stream stages cannot reach a header and must NOT be routed through the governed `progress`/`final` contract. `tests/answer-route-preamble.test.ts` pins admission-before-scope (no scope call while the limiter is pending or after a deny) and the client-disconnect abort signal. **Done 2026-07-30 (PR #1450, `1bff4c78`):** the counting proxy exists and the answer path is budgeted. `tests/helpers/supabase-round-trip-counter.ts` counts on **execution, not construction** — a builder that is never awaited costs zero, one awaited twice costs two — which is the distinction that makes the count mean "requests issued". `tests/rag-round-trip-budget.test.ts` pins two offline answer-path scenarios (a single-source source-only answer, and that trips do not scale with the number of retrieved sources) plus three self-tests of the counter, and is registered in `scripts/fixtures/rag-offline-contract-tests.json` so it runs inside the offline contract rather than only on demand. Verified locally, provider-free: `Test Files 1 passed (1)`, `Tests 5 passed (5)`. Its documented blind spot is worth repeating before anyone cites a budget as total cost: it sees only traffic through the wrapped client, so a trip issued via another client instance, a direct `fetch`, or a provider SDK is invisible to it. **Done 2026-07-30 (search *retrieval core*, not the endpoint):** `tests/search-round-trip-budget.test.ts` pins `searchChunksWithTelemetry` — what `/api/search` calls to retrieve — registered in both the contract fixture and `scripts/rag-offline-contract.mjs`. **Corrected after Codex review on PR #1464:** an earlier version of this row and the test itself claimed to pin `/api/search`. They do not. The route's auth, rate limiting, scope resolution, related-document enrichment and telemetry write are all invisible to this suite, so a round trip added to any of them leaves it green — and the refusal budget below is about *retrieval*, not about an adversarial HTTP request, which still pays the route preamble. **The measured shape is itself the finding:** one search costs **11 round trips** — `rag_aliases` 1, `match_document_chunks_text_v2` **3**, `match_document_table_facts_text_v2` **3**, `get_related_document_metadata_v2` 1, `document_index_quality` 1, `document_images` 2 — so the two text RPCs are each issued three times per search. Pinned by total *and* breakdown, because a refactor swapping one probe for an unrelated query would keep the total at 11 while changing the traffic. Deterministic across three consecutive runs. The refusal budget asserts **zero** Supabase traffic, matching `rag.ts`'s claim that prompt-injection intent is refused before any query issues, and was proven against the broken shape: with a non-refused query it fails on the round-trip assertion (`expected 11 to be +0`), which is why that assertion is ordered ahead of the results assertion. **Note 2026-07-30 (corrected):** a work-branch experiment on `origin/work` (`1f52c704`, reverted in `a0cd00ba`) collapsed both text surfaces offline (budget 11→7) but never reached `main` and was never canaried on those SHAs. Live canaries `30579804611` and `30580564419` ran on unrelated `main` docs commits (`fde68ed4` / `4312a214`) and must not be cited as probe-collapse evidence. Next (b) remains open and still needs a real canary pair before any collapse. **Next:** (a) add the route-level budget this suite does not provide — drive `POST` from `src/app/api/search/route.ts` with counted clients, following the `tests/answer-route-preamble.test.ts` pattern, so a round trip added to the route preamble or post-processing is a red gate; (b) decide whether `match_document_chunks_text_v2` ×3 and `match_document_table_facts_text_v2` ×3 per search are intended or a probe that should be collapsed — a latency question this budget surfaced but does not answer, and one that touches retrieval, so any change needs the usual RAG gate. (c) `scripts/eval-rag-offline.mjs` and `scripts/test-rag-offline.mjs` remain unwired; the offline contract runner is now the de-facto single home for budgets, so either adopt that explicitly here or wire them. | `docs/audit/latency-audit-2026-07-28.md` measurement plan; `src/lib/server-timing.ts`; `src/lib/answer-stream-contract.ts:18-21` | 2026-07-29 | | #099 | P2 | task | Remove the remaining fixed per-request round trips | **Outcome:** the answer path stops paying avoidable per-request Supabase round trips. **Done 2026-07-29:** shared-cache-hit promotion deferred off the response path with its mid-request staleness guard intact and documented (`rag.ts:3234`, `rag-cache.ts`); scope resolution overlapped with the rate-limit RPC, signal threaded so a client disconnect finally cancels its paginated queries (`answer/route.ts`). **REFUTED on PR #1377 review — do not retry:** the same pass also overlapped scope with the rate-limit RPC and aborted it on deny, claiming the limiter could "deny for free". It cannot. With caller-supplied `filters` or explicit ids, scope passes its zero-query early returns (`search-scope.ts:242,253`) into the paginated `documents` loop at `:269`, and an `AbortSignal` cancels the client request without un-executing a statement Postgres already began — so throttled traffic kept burning database capacity while collecting 429s, against `capacity-review.md:106-113`'s first-soft-failure warning. Scope is behind admission again, pinned by `tests/answer-route-preamble.test.ts`. Re-attempting the overlap requires a non-database admission gate ahead of the durable limiter first. **Remaining:** (a) the 8 `setCachedSearch` awaits — deferring changes `throwIfAborted` semantics and widens a real mutation window because the clone happens after an `await`, so each branch needs discharging individually; (b) batch the anonymous subject+global rate-limit pair, which needs a NEW atomic RPC modelled on `consume_summary_rate_limits_atomic` and cannot be called until the operator applies it — `Promise.all` is the WRONG fix because it consumes the global bucket even when the subject bucket already denied; (c) stop the proxy and route handler resolving identity twice per authenticated request — no in-process memo can do this (different `Request` objects), so the proxy must forward unspoofable verified claims via a header it controls. Cross-references #011: halving auth resolutions eases the ~10-connection Auth cap that `capacity-review.md:106-113` calls the first hard failure. | `docs/audit/latency-audit-2026-07-28.md` L1-1/L1-3/L1-4; `src/lib/api-rate-limit.ts:276-282`; `src/proxy.ts:125` | 2026-07-29 | | #100 | P2 | rec | Buffered answer generation has no incremental verified delivery | **Design complete; runtime work remains provider-gated.** [`verified-answer-incremental-delivery-design.md`](verified-answer-incremental-delivery-design.md) records the clinical-governance decision and staged contract: keep the `progress`/`final`/`error` allowlist; disclose bounded, owner-scoped evidence only after the canonical danger-level source-governance refusal permits it, then emit complete answer sections only after each reuses the full production verification boundary; reconcile every preview byte-for-byte with the authoritative `final`; discard all previews on error/cancel/retry; deploy behind separate parse/emission/render flags. Phase 0 contract proof and Phase 1 evidence preview can be developed offline, but visible rollout still needs clinical/browser proof. Phase 2 changes generation architecture and requires explicit approval for answer-quality evals plus a baseline/post live canary pair. **Naive token streaming remains REFUTED:** never re-land `token`, `revising`, provisional prose, or a weaker stream-only verifier. Cross-references #021. | `docs/verified-answer-incremental-delivery-design.md`; `docs/audit/latency-audit-2026-07-28.md` L0-1; `src/lib/answer-stream-contract.ts:18-21` | 2026-07-30 | @@ -130,7 +129,6 @@ removed after current-main verification; it is not missing recommended work. | #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 | | #142 | P3 | task | Four loose dated docs need source and migration edits before they can be filed | **Outcome:** every dated point-in-time doc lives in `docs/audit/` or `docs/archive/` as `docs/README.md` requires, not loose at the `docs/` top level. **Detail:** PR #1436 filed the five that were docs-only moves. These four are referenced from outside `docs/`, so relocating them means editing source, tests and migration SQL comments — a different risk class than a docs tidy, and not worth bundling into one: `capacity-review.md` (`scripts/soak-test.ts`), `tenancy-defense-in-depth-review.md` (`src/lib/owner-scope.ts`, `tests/owner-scope-guard.test.ts`, two migrations, `SECURITY.md`, `.claude/agents/clinical-governance-reviewer.md`), `operator-apply-july8-batch.md` (three migrations plus `supabase/schema.sql`), `scale-readiness-review.md` (one migration). Also note `forward-codify-retrieval-rpcs-workorder.md` is indexed as a completed workorder but live is still ahead of the repo on those RPCs, so archiving it would misrepresent open operator work. **Next:** treat as low priority — the docs are correctly indexed and reachable where they are; only file them if a pass is already editing those migrations. Editing applied migration SQL is subject to `npm run check:migration-role`'s immutability pin. | PR #1436; session 2026-07-30 | 2026-07-30 | -| #138 | P3 | task | CI Triage ships inert pending a repo variable | **Outcome:** a PR red that is really a main-side regression is labelled as such instead of costing an author a debugging session. **Detail:** `.github/workflows/ci-triage.yml` is complete and self-tested (`check:ci-triage` runs in `verify:cheap` and `static-pr`) but every run short-circuits on `vars.CI_TRIAGE_ENABLED == 'true'`, which is unset. Its purpose is the failure mode this doc records repeatedly: CI merges the PR branch with current `main`, so a main regression surfaces on every open PR. **Next:** operator sets the repository variable, then confirm one triage comment posts. Reads job metadata from a trusted default-branch checkout only; never runs PR code. | `.github/workflows/ci-triage.yml`; session 2026-07-30 | 2026-07-30 | | #146 | P2 | issue | `ui-phone-scroll` Services result anchor jumps on viewport shrink under CI load | **Outcome:** the required `Production UI` job stops failing on a test the PR did not touch. **Evidence 2026-07-30 (PR #1427 run `30534158395`, job `90844138237`, shard 1 of 3):** `tests/ui-phone-scroll.spec.ts:973` "Services results keep a continuous browser viewport after shared chrome releases" failed at `:1133` — `afterViewportResize.anchorTop` did not stay close to `hidden.anchorTop` across the viewport shrink. `120 passed (6.5m)`, classified "needs investigation". **Intermittent on unchanged code:** the spec is byte-identical across heads `79dd28f`, `76f80f3` and `17c8cb9`; shard 1 passed, passed, failed, then passed again on re-run — four data points, one failure. **Not #127 and not fixed by #1427:** this head already carried #1427's runway poll and travel assertion, and the failing assertion is result-content anchor stability across a resize, not the chrome hide. #127 is the reduced-motion hide on the document route; this is the Services result canvas. **A narrowing claimed here was WITHDRAWN 2026-07-30 (Codex, PR #1446):** an earlier version of this row argued that the sibling `documentScrollTop` assertion did not fail, so the scroll position must have held. That inference is invalid — Playwright aborts a test at the first failing `expect`, so once the `anchorTop` assertion threw, the `documentScrollTop` assertion never executed. Its absence from the output shows nothing, and scroll-restoration causes are NOT ruled out. **Next:** capture `anchorTop` and `documentScrollTop` either side of the resize from a CI-load run, and check whether the chrome release and the viewport change can interleave. **Stop:** do not add to `tests/flake-ledger.json` — that ledger takes reproduced `@quarantine` entries only, and this reproduces once in four. Do not loosen the `toBeCloseTo` tolerance; the anchor stability is the assertion's whole point. **Two further data points 2026-07-30 (PR #1457):** failed once more on head `c739340` (run `30551018893`, shard 1) with `anchorTop` expected `-138`, received `-7`, difference `131`, `120 passed`; then passed on heads `9da02d9` and `a6f2281` across all three shards with the diff byte-identical. That is six data points, two failures, still shard 1 only — and both failures landed on a PR touching nothing but `src/app/mockups/**` plus one mockup test, which strengthens the unchanged-code reading. The magnitude is worth noting for the capture suggested above: `131` is roughly 2x the 64px viewport shrink, not a sub-pixel drift. | PR #1427 run `30534158395`; session 2026-07-30 | 2026-07-30 | | #147 | P2 | rec | Mobile CLS breaches four routes, and it reproduces exactly offline | **Outcome:** mobile CLS is under 0.1 on every measured route, or each remaining breach has a recorded reason. **Measured 2026-07-30 with the LOCAL OFFLINE production harness** (`CHROME_PATH=/opt/pw-browsers/chromium npm run verify:lighthouse -- --keep`; Lighthouse 12.8.2, Chromium 141.0.7390.37, demo corpus, inert loopback Supabase). Mobile CLS: `/dsm` 0.363, `/documents/search` 0.220, `/therapy-compass` 0.142, `/` 0.023 — `/forms` did not measure locally (Lighthouse `NO_NAVSTART`, its own "run again" transient), but the live dispatch put it at 0.212. Desktop passes everywhere: 0.016–0.097. **The finding that matters is that these reproduce the live production dispatch EXACTLY.** Against run `30548662649` on `psychiatry.tools`, all four locally measurable mobile routes match to three decimals — 0.023 / 0.142 / 0.220 / 0.363 on both — and the desktop range matches at both endpoints, 0.016–0.097. So CLS on these routes is deterministic layout structure, not network, latency, or production data. Three consequences: (a) the CLS half of `#017` is debuggable and gate-able locally at zero provider cost; (b) `#017`'s recorded blocker "prod server hard-requires Supabase secrets" is stale — `scripts/run-lighthouse-budget.mjs` builds and serves an offline production app precisely to sidestep that, and its earlier note that dev-mode CLS looked "excellent at 0.00–0.04" was measuring DEV, which does not reproduce production; (c) re-dispatching the live workflow to re-measure CLS buys nothing. **LCP does NOT reproduce and must not be read from local runs:** local mobile LCP is 2014–2051 ms against 3639–4716 ms live, because the loopback server has no network latency. The LCP _ranking_ does survive — `/therapy-compass` is the outlier both locally (4978 ms, ~2.4x every other route) and live — which corroborates `#117` rather than replacing it. Mobile TBT, local: `/documents/search` 581 ms, `/dsm` 448, `/therapy-compass` 379, `/` 338. **Ranking by measured contribution, which is what `#017` asked for:** 1. `/dsm` CLS 0.363 (3.6x the threshold, the worst single number anywhere); 2. `/documents/search` 0.220; 3. `/forms` 0.212 (live only); 4. `/therapy-compass` 0.142, and separately the sole LCP outlier via `#117`; 5. `/` 0.023, which passes and needs nothing. **ATTRIBUTED 2026-07-30 — one cause dominates, and it is a self-inflicted round trip.** Driving Chromium directly against the same offline production build (Lighthouse mobile emulation: 412x823, DPR 1.75, 4x CPU throttle) with a `PerformanceObserver` on `layout-shift` reading `entry.sources[].node`: on `/dsm`, `/documents/search`, `/forms` and `/therapy-compass` the entire main content region moves **down 128px and straight back up 128px** within 15-60ms. Both moves score, so the round trip is pure cost with zero net movement. It is **100% of `/documents/search`** (0.110 down + 0.110 up = 0.220) and about 75% of `/dsm`. The shifting element is the `max-sm:pt-[var(--phone-overlay-chrome-h)]` wrapper around `
`, i.e. the phone overlay chrome reserve. **Mechanism, pinned by a MutationObserver timeline on the root style attribute rather than inferred:** the property goes CSS seed -> `200px` -> `72px`, and the decisive line is that the 200px is written when the header stack **already measures 72px** — `t=1552ms reserve=200px stack=72`, corrected to `72px` at `t=1612ms`. So `usePhoneOverlayChromeReserve` (`src/components/clinical-dashboard/use-phone-overlay-chrome-reserve.ts`) publishes a **stale** measurement: its `useLayoutEffect` reads `stack.offsetHeight` while the stack is still transiently 200px, and the write lands after the stack has already collapsed to 72px; its `ResizeObserver` then corrects it. The CSS seed at `globals.css:375` (`calc(max(0.5rem, var(--safe-area-top)) + var(--shell-header-h))` = 72px on a zero-inset profile) is **correct for the settled stack** — the seed is not the problem. **This corrects the mechanism recorded on `#130`** (now archived), which framed the defect as the seed under-reserving by `max(0, 0.5rem - inset)`, i.e. 0px on a notched iPhone and 8px elsewhere. Measured, the CLS driver is not an 8px seed shortfall but a 128px transient over-reserve written by the hook. Do not reopen `#130` on this; it is recorded here. **Control that makes the attribution trustworthy:** `/` never writes the property at all (no overlay stack) and is the one clean route at 0.023. **Variance, stated rather than smoothed over:** `/dsm` measured 0.363 (3 shift entries) and 0.219 (2 entries) on two runs — the round trip is the stable core and the third entry is intermittent. This harness has no network throttling, so `/forms` (0.310 local vs 0.212 live) and `/therapy-compass` (0.240 vs 0.142) run high locally; only `/dsm` 0.363, `/documents/search` 0.220 and `/` 0.023 reproduced the live dispatch exactly, and only those three should be treated as production-equivalent. **Next:** stop the hook publishing a measurement it is about to revise — defer the first publish until the stack has settled, or let the `ResizeObserver` be the only writer and trust the seed until it fires. That is a phone-chrome change, so it is governed by `docs/search-chrome-behaviour.md` and needs `npm run verify:phone-chrome` plus a before/after CLS pair from this harness. **Harness trap worth keeping:** attaching a `MutationObserver` to `document.documentElement` inside a Playwright `addInitScript` throws when the document element does not exist yet, which silently takes the CLS observer down with it and reports a uniform `CLS=0.000` across every route — a false clean bill, not a pass. Guard the attach. **Original next step, now done:** attribute the shifts to elements. Lighthouse's `layout-shift-elements` audit returned **zero items on every route** — the `cumulative-layout-shift` audit carries only `debugdata` — so attribution needs a driven Chromium session with a `PerformanceObserver` on `layout-shift`, reading `entry.sources[].node` and `entry.value`, against the same offline production build. Start with `/dsm`. **Gate — `#118` owns it, and this row supplies a constraint it was missing.** `#118` already tracks flipping `lighthouse-budget.json` to `enforce: true` and says not to do it "before `#117` or the baseline pins a known-slow route". These numbers make that concrete: pinning a baseline today would bake CLS 0.363 on `/dsm` in as the accepted value, so the CLS fixes must land first or the gate ratifies the breach. Separately, no baseline could have been committed from this run anyway — the grader correctly refused it as incomplete evidence because `/forms` produced no report, and that refusal was not overridden. **Reproduction trap:** without `CHROME_PATH`, `chrome-launcher` cannot find a browser in this container and every route fails; the harness reads `CHROME_PATH`/`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH` (`run-lighthouse-budget.mjs:291`) but nothing sets either, even though `PLAYWRIGHT_BROWSERS_PATH` is set. Related to `#121`. Also seen: a truncated `progress` package in the npx cache broke Lighthouse startup entirely; clearing the npx cache entry fixed it. **Stop:** do not re-dispatch the live Web-Vitals workflow to re-measure CLS — it is reproducible offline for free. Do not commit a budget baseline from a run with a failed route. Do not treat local LCP numbers as production LCP. | `#017` live run `30548662649`; local `verify:lighthouse` 2026-07-30; `lighthouse-budget.json` | 2026-07-30 | | #149 | P2 | issue | `check:installed-lock-parity` only compares seven top-level packages, so transitive drift passes | **Outcome:** a session cannot run local gates against a `node_modules` that silently disagrees with the lockfile. **Evidence 2026-07-30:** the `SessionStart` hook reported "node_modules matches the lockfile, skipping install" while `brace-expansion` was installed at **1.1.16** and the lockfile pinned **1.1.18** — the CVE-2026-14257 patch. Every local gate run in that window was weaker than it appeared, including several `verify:cheap` runs reported as green during PR #1430/#1444 work. It surfaced only because `tests/installed-lock-parity.test.ts` asserts the patched behaviour directly (`maxLength` honoured); its failure was initially mistaken for a pre-existing repo defect, since it also failed on clean `main` **in the same stale container**. `npm ci --include=dev` fixed it. **CORRECTION 2026-07-30 (PR #1496 review, Codex):** an earlier version of this row said the parity check lives only in `verify:ui` and proposed adding it to `verify:cheap`. **Both were wrong** — `verify:cheap:internal` already runs `check:installed-lock-parity`, so that follow-up was a no-op, and it ran green throughout the stale window. The real gap is its **scope**: `scripts/check-installed-lock-parity.mjs` compares only seven top-level packages (`criticalInstalledPackages` = next, react, react-dom, eslint, playwright, typescript, vitest), so a stale **transitive** dependency is invisible to it. Proved by faking `node_modules/brace-expansion` back to `1.1.16` against the `1.1.18` lockfile pin: `npm run check:installed-lock-parity` **exits 0**. That also explains why the hook and the gate both reported parity while the tree was stale — neither was looking at the package that drifted. **Next:** broaden the check beyond the seven names — validate the full installed tree against the lockfile, or stamp the install with the lockfile hash and compare that — so transitive drift is caught rather than assumed absent. **Stop:** do not treat a green `check:installed-lock-parity` as proof the install is lockfile-current; today it means seven packages match. | `scripts/check-installed-lock-parity.mjs`; `tests/installed-lock-parity.test.ts`; `package.json` | 2026-07-30 | @@ -148,6 +146,8 @@ Move resolved rows here with the resolution date and a one-line outcome. Keep th | ID | Type | Summary | Outcome | Resolved | | ---- | ----- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | +| #093 | issue | Next streaming `S:` clone causes Playwright strict-mode violations under CI load | RESOLVED 2026-07-31: shared `visibleByTestId` scopes page-root/shell testids to the visible DOM owner (not bare `.first()`), applied to the known hotspots in `ui-tools` / `ui-smoke` / `ui-accessibility`. `expectSingleSettledOwner` remains for full-convergence races. Product mount bisect remains optional if a new surface appears. | 2026-07-31 | +| #138 | task | CI Triage ships inert pending a repo variable | RESOLVED 2026-07-31: `ci-triage.yml` is enabled by default (`vars.CI_TRIAGE_ENABLED != 'false'`). Opt out with `CI_TRIAGE_ENABLED=false`. Still trusted default-branch checkout only; never runs PR code. | 2026-07-31 | | #038 | rec | Consolidate shared comparison behavior | Supersedes the earlier 2026-07-30 closed-as-future-principle disposition. Resolved with `docs/comparison-behaviour.md`: one interaction contract now covers selection scope, zero/one/valid/over-limit states, phone entry, background refresh, identity changes, missing values, source context, sharing, and accessibility while explicitly leaving clinical fields, rankings, evidence weighting, and generated prose with each mode. No RAG or comparison-generation behavior changed. | 2026-07-30 | | #065 | task | Complete the paused compact document source-text accordion | Resolved after reconciling only the missing behavior with current `DocumentViewer`: extracted page text and passages are compact nested disclosures; citation/search opens the active passage; manual peers are exclusive; print expands and restores state. Focused Chromium proof passed at 320, 390, and 1280 px with no overflow, plus deep-link/search and print restoration paths. The preserved historical branch was not changed. | 2026-07-30 | | #092 | task | Refetch pulse deferred on auth-backed registries | Supersedes the earlier 2026-07-30 deferred/closed disposition that retained identity-clearing over a refetch pulse. Resolved with identity- and resource-keyed background refresh in registry, medication, and differential catalogues. Same-user credential refreshes retain authorised rows under `refetching`; query, mode, or user identity changes clear synchronously. Focused DOM tests pin same-user preservation and immediate user-change clearing, and existing result surfaces now expose the shared refetch pulse without replacing records with skeletons. | 2026-07-30 | diff --git a/docs/process-hardening.md b/docs/process-hardening.md index 65ec9b83f6..6acfc9aa84 100644 --- a/docs/process-hardening.md +++ b/docs/process-hardening.md @@ -609,7 +609,7 @@ the durable index for the tooling; `docs/operator-backlog.md` tracks the human-o (`INGESTION_AUTOPILOT_APPLY` unset → read-only); flip that repo var to `true` after a clean dry-run to allow real recovery. - **CI failure triage** (`.github/workflows/ci-triage.yml`): on PR CI failure, classifies each failed job - as main-side or needs-investigation. Inert until repo var `CI_TRIAGE_ENABLED=true` (now set). UI jobs use + as main-side or needs-investigation. Enabled by default; set repo var `CI_TRIAGE_ENABLED=false` to disable. UI jobs use their uploaded JUnit classification and trace; job names alone never produce a known-flake verdict. The workflow reads only trusted default-branch job metadata and never runs PR code. - **PR metadata policy** (`.github/workflows/pr-policy.yml`, `scripts/pr-policy.mjs`): ready PRs to `main` diff --git a/docs/testing.md b/docs/testing.md index 4f5e7eabc3..f1a702ee4b 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -94,7 +94,8 @@ The parser walks back over comma-continued selector lines, so a selector list sp **Pixel baselines (`tests/ui-visual-baseline.spec.ts`) — advisory.** Run by `playwright.visual.config.ts`, which also still runs the older attach-only `ui-visual-artifacts.spec.ts`. Three constraints are deliberate: never `fullPage` (under CI load -Next.js leaves a hidden duplicate page root in the stream — ledger #093 — so a whole-page capture can +Next.js can leave a hidden duplicate page root in the stream — ledger #093, mitigated for interactive +tests via `visibleByTestId` in `tests/playwright-settlement.ts` — so a whole-page capture can still contain the layout twice; every target is clipped to a locator), demo mode only (the Playwright runner forces `NEXT_PUBLIC_DEMO_MODE` and offline providers, so content is stable between runs), and motion off with carets hidden. diff --git a/tests/playwright-settlement.ts b/tests/playwright-settlement.ts index a5af1e6e5b..b6fe6d244a 100644 --- a/tests/playwright-settlement.ts +++ b/tests/playwright-settlement.ts @@ -1,4 +1,4 @@ -import { expect, type Locator } from "playwright/test"; +import { expect, type Locator, type Page } from "playwright/test"; /** * Wait for a hydrating/portalling surface to converge to exactly one visible @@ -29,3 +29,17 @@ export async function expectSingleSettledOwner( return locator.first(); } + +/** + * Scope a testid to the visible DOM owner (#093). + * + * Next streaming can leave a hidden duplicate page root in the tree under + * full-suite load. Bare `page.getByTestId(...)` then trips Playwright strict + * mode; bare `.first()` can pin the hidden clone. Prefer this helper (or + * pad-scoping under `mobile-composer-reserve-pad`) for page-root / shell + * surfaces. Use `expectSingleSettledOwner` when the duplicate must fully + * disappear rather than merely be ignored while hidden. + */ +export function visibleByTestId(page: Page, testId: string): Locator { + return page.getByTestId(testId).filter({ visible: true }); +} diff --git a/tests/ui-accessibility.spec.ts b/tests/ui-accessibility.spec.ts index 2654b2952a..e6b6fea5b8 100644 --- a/tests/ui-accessibility.spec.ts +++ b/tests/ui-accessibility.spec.ts @@ -1,6 +1,7 @@ import AxeBuilder from "@axe-core/playwright"; import { expect, test, type Page, type TestInfo } from "playwright/test"; import { stubZeroTouchPoints } from "./helpers/zero-touch"; +import { visibleByTestId } from "./playwright-settlement"; const readySetupChecks = [ { id: "env", label: ".env.local configured", status: "ready", detail: "Test environment ready." }, @@ -459,7 +460,7 @@ test.describe("Clinical KB accessibility coverage", () => { await expect(differentialSubmit).toBeEnabled({ timeout: 2_000 }); }).toPass({ timeout: 30_000 }); await differentialSubmit.click(); - await expect(page.getByTestId("differentials-search-results")).toBeVisible(); + await expect(visibleByTestId(page, "differentials-search-results")).toBeVisible(); const filterSelect = page.getByTestId("differential-result-type-select"); await expect(filterSelect).toBeVisible(); diff --git a/tests/ui-smoke.spec.ts b/tests/ui-smoke.spec.ts index 058aa7a5b1..fdb68bc68e 100644 --- a/tests/ui-smoke.spec.ts +++ b/tests/ui-smoke.spec.ts @@ -8,7 +8,7 @@ import { readPrimaryScrollGeometry, scrollPrimarySurface, } from "./playwright-scroll"; -import { expectSingleSettledOwner } from "./playwright-settlement"; +import { expectSingleSettledOwner, visibleByTestId } from "./playwright-settlement"; import { answerThreadStorageKey } from "../src/lib/answer-thread-storage"; import { documentSummaryQuestion } from "../src/lib/answer-contract"; import { demoAnswer, demoDocuments, demoSummary, getDemoDocument, getDemoDocumentPayload } from "../src/lib/demo-data"; @@ -2938,7 +2938,7 @@ test.describe("Clinical KB UI smoke coverage", () => { await mockDemoApi(page); await gotoApp(page, "/differentials?q=acute+confusion&focus=1&run=1"); - await expect(page.getByTestId("differentials-search-results")).toBeVisible({ timeout: 30_000 }); + await expect(visibleByTestId(page, "differentials-search-results")).toBeVisible({ timeout: 30_000 }); await expect(page.getByRole("button", { name: "Mode Differentials" })).toBeVisible(); await expect(page.getByTestId("differentials-home")).toHaveCount(0); }); @@ -3058,7 +3058,7 @@ test.describe("Clinical KB UI smoke coverage", () => { await expect(page.getByRole("heading", { name: "Favourites command library" })).toBeVisible(); await expect(page.getByTestId("favourites-item-workspace")).toHaveCount(0); - await page.getByTestId("favourite-row-lithium-monitoring-guideline").locator("button[aria-pressed]").click(); + await visibleByTestId(page, "favourite-row-lithium-monitoring-guideline").locator("button[aria-pressed]").click(); const workspace = page.getByTestId("favourites-item-workspace"); await expect(workspace).toBeVisible(); await expect(workspace.getByRole("heading", { name: "Lithium monitoring guideline", level: 3 })).toBeVisible(); diff --git a/tests/ui-tools.spec.ts b/tests/ui-tools.spec.ts index 385f06cb4a..8d4489b270 100644 --- a/tests/ui-tools.spec.ts +++ b/tests/ui-tools.spec.ts @@ -15,7 +15,7 @@ import { readPrimaryScrollGeometry, scrollPrimarySurface, } from "./playwright-scroll"; -import { expectSingleSettledOwner } from "./playwright-settlement"; +import { expectSingleSettledOwner, visibleByTestId } from "./playwright-settlement"; const readySetupChecks = [ { id: "env", label: ".env.local configured", status: "ready", detail: "Test environment ready." }, @@ -568,7 +568,7 @@ test.describe("Clinical KB tools launcher", () => { await formsMode.click(); await expect(page).toHaveURL(/\/forms$/, { timeout: 20_000 }); await expect(page.getByRole("button", { name: "Mode Forms" })).toBeVisible(); - await expect(page.getByTestId("forms-home")).toBeVisible(); + await expect(visibleByTestId(page, "forms-home")).toBeVisible(); await expect(page.getByTestId("form-search-results")).toHaveCount(0); await expect(visibleGlobalSearchInput(page)).toHaveValue(""); await expectNoPageHorizontalOverflow(page); @@ -590,14 +590,14 @@ test.describe("Clinical KB tools launcher", () => { await expect(page).toHaveURL(/\/forms$/); await expect(page.getByRole("button", { name: "Mode Forms" })).toBeVisible(); - await expect(page.getByTestId("forms-home")).toBeVisible(); + await expect(visibleByTestId(page, "forms-home")).toBeVisible(); await expect(page.getByTestId("form-search-results")).toHaveCount(0); await expect(visibleGlobalSearchInput(page)).toHaveCount(1); await expect(visibleGlobalSearchInput(page)).toHaveValue(""); await gotoLauncher(page, "/forms"); await expect(page.getByRole("button", { name: "Mode Forms" })).toBeVisible(); - await expect(page.getByTestId("forms-home")).toBeVisible(); + await expect(visibleByTestId(page, "forms-home")).toBeVisible(); menu = await openAppModeMenu(page, "Forms"); const servicesMode = menu.getByRole("menuitemradio", { name: /^Services\b/ }); @@ -1015,8 +1015,8 @@ test.describe("Clinical KB tools launcher", () => { await expect(page.getByTestId("services-home").getByTestId("global-search-input")).toBeFocused(); await gotoLauncher(page, "/forms?focus=1"); - await expect(page.getByTestId("forms-home").getByTestId("global-search-input")).toBeVisible(); - await expect(page.getByTestId("forms-home").getByTestId("global-search-input")).toBeFocused(); + await expect(visibleByTestId(page, "forms-home").getByTestId("global-search-input")).toBeVisible(); + await expect(visibleByTestId(page, "forms-home").getByTestId("global-search-input")).toBeFocused(); }); test("services mode shows source-backed records in search results", async ({ page }) => { @@ -1398,11 +1398,11 @@ test.describe("Clinical KB tools launcher", () => { await expect(page).toHaveURL(/\/forms$/); await expect(page.getByRole("button", { name: "Mode Forms" })).toBeVisible(); - await expect(page.getByTestId("forms-home")).toBeVisible(); + await expect(visibleByTestId(page, "forms-home")).toBeVisible(); await expect(page.getByRole("heading", { level: 1, name: "Forms" })).toBeVisible(); await expect(page.getByTestId("services-home")).toHaveCount(0); - await expect(page.getByTestId("global-search-input")).toHaveCount(1); - const formsHomeSearch = page.getByTestId("forms-home").getByTestId("global-search-input"); + await expect(visibleByTestId(page, "forms-home").getByTestId("global-search-input")).toHaveCount(1); + const formsHomeSearch = visibleByTestId(page, "forms-home").getByTestId("global-search-input"); await expect(formsHomeSearch).toBeVisible(); const formsSearchBox = await formsHomeSearch.boundingBox(); const formsHeadingBox = await page.getByRole("heading", { level: 1, name: "Forms" }).boundingBox(); @@ -1537,7 +1537,7 @@ test.describe("Clinical KB tools launcher", () => { // Evidence arrived, so the results view renders — ranked from the imported // differentials catalogue with a real query-matched result row. - await expect(page.getByTestId("differentials-search-results")).toBeVisible(); + await expect(visibleByTestId(page, "differentials-search-results")).toBeVisible(); await expect(page.getByTestId("differentials-catalogue-notice")).toBeVisible(); await expect(page.getByText("Catalogue ranking").first()).toBeVisible(); await expect(page.getByRole("link", { name: "Delirium / Acute Confusion / Encephalopathy" }).first()).toBeVisible(); @@ -1594,7 +1594,7 @@ test.describe("Clinical KB tools launcher", () => { await gotoLauncher(page, "/differentials"); await submitDifferentialSearch(page, "acute confusion"); - await expect(page.getByTestId("differentials-search-results")).toBeVisible(); + await expect(visibleByTestId(page, "differentials-search-results")).toBeVisible(); const typeSelect = page.getByTestId("differential-result-type-select"); await expect(typeSelect).toBeVisible(); await expect(typeSelect).toHaveAccessibleName("Filter by result type"); @@ -1695,7 +1695,7 @@ test.describe("Clinical KB tools launcher", () => { await gotoLauncher(page, "/differentials"); await submitDifferentialSearch(page, "acute confusion"); - await expect(page.getByTestId("differentials-search-results")).toBeVisible(); + await expect(visibleByTestId(page, "differentials-search-results")).toBeVisible(); const typeSelect = page.getByTestId("differential-result-type-select"); await expect(typeSelect).toBeVisible(); await expect(typeSelect).toHaveAccessibleName("Filter by result type"); @@ -1824,7 +1824,7 @@ test.describe("Clinical KB tools launcher", () => { const compareAction = page.getByTestId("differentials-compare-selected-mobile"); const dock = page.locator("form.answer-footer-search-dock"); - const scrollport = page.getByTestId("differentials-search-results"); + const scrollport = visibleByTestId(page, "differentials-search-results"); const mainContent = page.locator("#main-content"); await expect(scrollport).toBeVisible(); await expect(page.locator("#differentials-mobile-compare-addon-slot")).toHaveCount(1);