From d6f190207f101c38e074cbae5fc2507a76781f6a Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Thu, 30 Jul 2026 22:52:57 +0800 Subject: [PATCH 1/3] test(ui): cover component state transitions --- docs/outstanding-issues.md | 2 +- .../document-search-record-fault.dom.test.tsx | 52 +++++++++++ tests/mode-action-popup.dom.test.tsx | 91 +++++++++++++++++++ 3 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 tests/mode-action-popup.dom.test.tsx diff --git a/docs/outstanding-issues.md b/docs/outstanding-issues.md index 447970d839..d652400446 100644 --- a/docs/outstanding-issues.md +++ b/docs/outstanding-issues.md @@ -141,7 +141,6 @@ removed after current-main verification; it is not missing recommended work. | #103 | P2 | issue | Wide table-facts trigram index missing from `schema.sql` | **Outcome:** the migration chain and `schema.sql` agree on `document_table_facts` trigram indexes. `supabase/migrations/20260714190000_document_table_facts_trgm_idx.sql` creates a wide 5-column trigram index that is **absent from `supabase/schema.sql`**, so local replay and the live database can diverge. Distinct from #102: different owner and verification path. **Next:** confirm whether the wide index exists live, then take one of exactly two routes — **retained:** mirror `document_table_facts_text_trgm_idx` into `supabase/schema.sql` beside the narrow one and regenerate `drift-manifest.json`; **redundant:** drop it through a new forward migration, never by deleting `20260714190000`. **`drift-allowlist.json` is NOT a third option** (PR #1377 review): its own header scopes it to _"Known live-vs-`schema.sql` divergence"_, so it can silence a live drift finding but cannot reconcile the migration chain with the mirror — a fresh `supabase db reset` still runs `20260714190000` and creates the index while `schema.sql` still omits it, leaving this row's stated outcome unmet. **No offline gate catches this today:** the migration↔`schema.sql` parity test (`tests/drift-detection.test.ts:59-68`) only asserts one migration's `schema_drift_snapshot` function definition, not an index inventory — which is why this sits open rather than red in CI, and why a replay-to-schema inventory comparison is the check that would have caught it. Note the narrow `document_table_facts_title_row_param_trgm_idx` (`schema.sql:6425`) is the one the effective RPC expression (`:6726`) actually matches, so the wide index may be genuinely redundant — do not drop it without live scan evidence, per the monitored-not-auto-fixed index policy. | `docs/audit/latency-audit-2026-07-28.md` limitations; `npm run check:drift` | 2026-07-29 | | #105 | P3 | task | Verify the `#017`-exempt client latency wins in a browser | **Outcome:** the two zero-payload client fixes are confirmed in a real browser. `#017` gates _payload_ decisions (#012/#013/#016 are all byte-count items); a `loading` fallback ships zero bytes and a resource hint ships ~60, so neither can be justified or refuted by a Lighthouse number — that is why these were not held behind #017. **Implementation shipped 2026-07-29; browser verification still PENDING:** 10 of 11 `ssr:false` dashboard surfaces had NO `loading` fallback and rendered nothing between HTML arrival and chunk execution — all now use the shared `LoadingPanel` (`role="status"` + accessible label); Supabase `preconnect`/`dns-prefetch` added, since `AuthProvider` awaits a cross-origin `getUser()` on mount that every auth-gated fetch queues behind and there were no resource hints anywhere in `src/`. Shipped with `verify:cheap` + `verify:pr-local` only. **Next:** run `npm run verify:ui` once the heavy-run lock is free, and confirm the preconnect appears in `` on a live page. **Stop:** the two sidebar dialogs are intentionally excluded — they mount on open, so a fallback would render into a closed dialog. | `docs/audit/latency-audit-2026-07-28.md` L3-4/L3-5; `src/components/clinical-dashboard/clinical-dashboard-lazy.tsx` | 2026-07-29 | | #106 | P2 | rec | Ingestion worker and indexing agent are verified by grepping their own source | **Outcome:** the ingestion worker and indexing agent are verified by executing code, not by asserting on their own source text. **Detail:** measured 2026-07-29 via `npm run test:coverage` — `worker/main.ts` (2,015 lines) and `supabase/functions/indexing-v3-agent/index.ts` (1,966 lines) each report **0% executed lines**; no test imports either module. Both are covered only by `readFileSync` + `toContain` assertions in `worker-safe-logging.test.ts`, `worker-visual-capture.test.ts` and `document-metadata-merge.test.ts`, which pass whenever a string is present and break on harmless refactors; `document-metadata-merge.test.ts` additionally reimplements the SQL deep-merge in TypeScript and tests the reimplementation rather than the worker. Area totals: `worker/` 18.6% lines, `supabase/functions/` 4.5%. **Next:** continue the extraction pattern that already works here — `indexing-v3-agent/behavior.ts` (167 lines, 96%) and `ingestion-worker/auth.ts` (30 lines, 90%) — pulling the highest-risk decision points out of `worker/main.ts` (job claim/retry, generation commit, failure classification) into importable modules with executing tests, retiring the matching source-text assertion as each lands. Roughly cost-neutral: each extracted test replaces a grep assertion. **Stop:** do not try to make the 2,000-line entrypoint importable in one pass; extract incrementally and keep each step green. | session 2026-07-29 test-coverage analysis | 2026-07-29 | -| #107 | P2 | rec | Component state matrices are the largest untested surface | **Outcome:** loading / empty / error / disabled states on interactive components are covered by executing tests, not only by E2E happy paths. **Detail:** measured 2026-07-29 — production components (excluding mockups) sit at **38.2% lines / 22.8% branch** across 12,602 lines, with **83 of 208 files at zero executed lines**; there are 51 `.dom.test.tsx` files against 195 components. Playwright does visit these routes, so they are smoke-covered, but branch coverage is where the state matrix lives and smoke journeys rarely reach it. Worst by uncovered lines: `global-search-shell.tsx` (7%), `mode-action-popup.tsx` (21%), `answer-content.tsx` (27%), `document-search-results.tsx` (32%), `universal-search-command-surface.tsx` (39%), `master-search-header.tsx` (43%). A concrete first target with clinical meaning: `calculator-ui.tsx` now covers all exported scoring logic, but `seedCheckboxDefaults`, `toggleCheckboxAnswer` and `selectOptionAnswer` stay uncovered because they are module-private and only reachable through React event handlers — `seedCheckboxDefaults` is what makes an all-negative CAGE / SAD PERSONS screen read as a valid 0 rather than incomplete, so a regression there is a false-negative risk. **Next:** treat as a per-PR convention rather than a backfill push — `docs/testing.md` already prescribes the state matrix, so the gap is enforcement. Start with `global-search-shell.tsx`, which `docs/search-chrome-behaviour.md` treats as a contract surface. Keep additions in the jsdom tier (measured ~0.54s per file) instead of new Playwright journeys (~231 production journeys already run serially at `workers: 1` against a 45-minute CI budget). **Stop:** do not chase the coverage percentage by backfilling low-risk components; the re-ratcheted broad floor in `vitest.config.mts` holds the line. | session 2026-07-29 test-coverage analysis | 2026-07-29 | | #110 | P3 | task | Design-system project token manifest lags its stylesheet | **Outcome:** the claude.ai/design token panel matches the shipped stylesheet. **Detail:** PR #1375 pushed a recompiled `_ds_bundle.css` (Clinical Sky, `--e0`–`--e4`, 4px radius grid, `--tracking-eyebrow`/`--leading-display`/`--leading-prose`) plus the four changed guideline docs to project `08d6f126`, but `_ds_manifest.json` is converter-generated and still advertises `--text-4xs: 0.5rem`, the old `--radius-lg/xl/2xl` values, and `--tw-leading`/`--tw-tracking` entries scoped to the retired `.leading-[…]` / `.tracking-[0.08em]` utilities. Rendering is correct; only the token inventory lags. Hand-editing was rejected — `kind`/`scope`/`annotation` are converter heuristics and a wrong panel is worse than a stale one. **Next:** in a session with the `/design-sync` skill, `npm ci`, then `npm install --prefix .ds-sync --no-save --package-lock=false esbuild ts-morph @types/react @tailwindcss/cli geist`, read `.design-sync/NOTES.md`, and run `resync.mjs --remote` so bundle and manifest regenerate together. **Stop:** do not hand-author `_ds_manifest.json`; the converter is not a published npm package and ships with the skill. | PR #1375; `.design-sync/NOTES.md`; project `08d6f126` (`_ds_needs_recompile` marker present) | 2026-07-29 | | #121 | P3 | issue | Container Playwright browser build lags the pinned client | **Outcome:** browser gates run in remote sessions without hand-patching. **Evidence 2026-07-30:** the repo's Playwright client resolves headless-shell build `1234`; the container image provides `1194` at `/opt/pw-browsers`, so every browser test fails at launch. Worked around in-session by symlinking `chromium_headless_shell-1234/chrome-headless-shell-linux64/chrome-headless-shell` to the `1194` `headless_shell` binary plus its sibling resources — container-local, nothing committed, and it disappears with the session. `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1` means the mismatch cannot self-heal. **Next:** decide whether the image pins the browser build or the repo pins a client matching the image; until then any remote session claiming browser proof must state which it used. | `docs/testing.md`; container `/opt/pw-browsers` | 2026-07-30 | | #122 | P2 | issue | `ci/circleci: verify` fails on every branch and its log needs operator access | **Outcome:** the CircleCI status is trustworthy signal again, or it stops reporting. **Evidence 2026-07-30:** `ci/circleci: verify` was `failure` on every open PR sampled — #1396, #1407, #1405, and #1400, which is a **docs-only** `AGENTS.md` change — plus #1403's head. It is sharply bounded in time: #1393's head **passed** at build 638 (03:57), and builds 645 (04:09) onward all failed. The job's entire contents were mirrored locally on PR #1396's exact tip and every part is green — `format:check` clean, `lint` exit 0, `typecheck` exit 0, `npm run test` `432 passed (432)` / `4473 passed \| 4 skipped`, and the PyMuPDF-gated `tests/pdf-extractor.test.ts` (the repo's only `process.env.CI`-gated tests) `6 passed (6)` under a locally built `PyMuPDF==1.28.0` venv with `PYTHON_BIN` set exactly as `.circleci/config.yml` does. So the failure is in the job's **environment**, not repo code. Around 40 builds fired in ~40 minutes across 8 open PRs in that window, so credit/quota exhaustion is the leading hypothesis — **explicitly unverified**: the CircleCI project is private and no CircleCI token is available to any agent session, and `api/v1.1/project/gh/BigSimmo/Database/` returns `Build not found` unauthenticated. **Next:** an operator opens one failing build and reads the failing step; if it is quota, either raise it or remove the CircleCI status so it stops masking real reds. **Stop:** do not chase this from a PR branch — it is not branch-specific, and no agent can read the log. Do not go looking for a CircleCI token. | `.circleci/config.yml`; PR #1396 session 2026-07-30 | 2026-07-30 | @@ -174,6 +173,7 @@ Move resolved rows here with the resolution date and a one-line outcome. Keep th | ID | Type | Summary | Outcome | Resolved | | ---- | ----- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | +| #107 | rec | Component state matrices are the largest untested surface | RESOLVED 2026-07-30. The state-matrix convention is enforced through executing jsdom coverage on two previously weak, high-branch interactive surfaces rather than a low-value percentage backfill. `DocumentSearchResultsPanel` now proves loading → settled-empty transition, empty-query home actions, unavailable/error reporting, registry loading/error/unauthorized states, and successful governed results. `ModeActionPopup` now proves closed → open → action-close, keyboard entry/navigation/Escape focus restoration, and disabled mode selection. Together with the existing `docs/testing.md` per-PR state-matrix requirement, the re-ratcheted broad component coverage floor, and the source-preview lifecycle suite, this closes the recommendation without adding serial Playwright journeys or chasing low-risk components. | 2026-07-30 | | #095 | issue | `PR required` reports failure for concurrency-cancelled jobs | RESOLVED 2026-07-30. The `pr-required` aggregate now distinguishes a cancelled job from a failed one. `require_success` / `require_skipped_or_success` are thin wrappers over one `record()` collector that reads **each job's own `result`** and appends to a `failures` or `cancellations` array; both arrays are filled before anything is reported. **Genuine failures win:** every failure is emitted as its own `::error::` and a concurrent cancellation is demoted to a `::warning::`, so a run that is cancelled AND broken cannot read as an excuse (refinement reported by Codex on PR #1409). Cancelled with nothing failing stays **RED**, and the message states the two possibilities rather than asserting supersession: it points the reader at a newer `PR required` run on the PR's current head SHA, and says that if there is none the run was cancelled by hand and must be re-run rather than merged past. It deliberately does NOT read the workflow-level cancelled status function — an earlier revision passed that through an `env:` value, which is invalid because GitHub allows those functions only in `if:` conditions, so the whole file failed to parse, ran as `.github/workflows/ci.yml` instead of `CI`, and created zero jobs; valid YAML but invalid Actions schema, so prettier and every local gate passed it. **The tempting fix was rejected as unsafe:** treating `cancelled` as neutral, or skipping the aggregate via a not-cancelled condition, would make the red disappear, but GitHub counts a SKIPPED required check as PASSING, so a hand-cancelled run on the current head would become mergeable with nothing verified — `if: always()` is therefore deliberate. Guarded by ten cases in `tests/ci-cache-safety.test.ts` that EXECUTE the extracted aggregate script under synthetic job results rather than grepping the YAML. **Corrected in review (Codex, PR #1428):** the first version of this record described a shared `cancelled_error` helper that never existed and claimed the error names the newest run; both were carried over from an obsolete sentence in the open row and neither matched the shipped implementation. Source: PR #1316 runs 30340972329 / 30341225585; PR #1409 | 2026-07-30 | | #096 | task | PR #1316 review follow-ups — adoption-gate coverage closed | RESOLVED 2026-07-30. Every sub-item is dispositioned. The band adoption gate's root-path gap closed on PR #1394 — root and href-less modes now resolve to `src/app/(search-app)/page.tsx` — and closing it surfaced two further defects in the same gate the original finding did not name: the hand-rolled walk was capped at two import hops where the root route's real chain is four, and it followed neither `layout.tsx` (where that route's band actually comes from) nor `dynamic(() => import(...))` (how the dashboard code-splits its mode workspaces). All three were fixed together with a bounded BFS, each verified load-bearing by reverting it and watching the gate fail. Four findings — favourites hub counts, the document-search status derivation, the 401 session-expiry path, the record-path duplicate notice — were already fixed independently. The Therapy Compass retry-waiter finding was corrected to NOT a live defect: `retryWaitersRef` is genuinely unscoped but no caller observes it. The seven Codex follow-up SHAs remain unreachable and were never pushed; the PR #1316 review threads are the durable source. Archived by the 2026-07-30 triage pass. Source: PR #1316 review sweep | 2026-07-30 | | #104 | rec | Worker's triple image read is deliberate, not debt | NOT DEBT — archived so a fourth audit does not re-file it. The 2026-07-28 latency audit listed L4-2 (`worker/main.ts` reads each extracted image up to 3x per document — hash, caption on cache miss, upload) as "CONFIRMED with no fix evidence", carried forward from the 2026-07-01 audit's L11. **That was wrong.** The 2026-07-01 disposition table already recorded it as a deliberate peak-memory trade-off, and the rationale is documented in place at `worker/main.ts:866-869`: holding every extracted image Buffer for a document with hundreds of multi-MB page images would multiply the worker's peak memory, and disk I/O is the cheaper resource for a background pipeline. The three reads (`:872`, `:1034`, `:1129`) are real but accepted. This row carried no next action, so it is archived rather than left open — revisit only if ingestion throughput becomes a measured complaint AND a bounded-buffer design is proposed. **Stop:** do not re-file this as debt. Source: `docs/audit/repo-audit-2026-07-01.md` L11 + disposition table | 2026-07-30 | diff --git a/tests/document-search-record-fault.dom.test.tsx b/tests/document-search-record-fault.dom.test.tsx index 8b22e78783..a8f70c1250 100644 --- a/tests/document-search-record-fault.dom.test.tsx +++ b/tests/document-search-record-fault.dom.test.tsx @@ -1,4 +1,5 @@ import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; import { describe, expect, it, vi } from "vitest"; import { DocumentSearchResultsPanel } from "@/components/clinical-dashboard/document-search-results"; @@ -123,3 +124,54 @@ describe("document search record path fault reporting", () => { expect(screen.getByRole("button", { name: `Answer from ${lithiumMatch.title}` })).toBeInTheDocument(); }); }); + +describe("document search state matrix", () => { + const documentProps = { + ...baseProps, + showRecordMatches: false, + recordMatches: [], + }; + + it("announces loading and replaces it with the empty result after the request settles", () => { + const { rerender } = render(); + + const loadingLabel = screen.getByText("Finding matching documents"); + expect(loadingLabel.closest('[role="status"]')).toBeInTheDocument(); + expect(screen.queryByText("No matching documents")).not.toBeInTheDocument(); + + rerender(); + expect(screen.queryByText("Finding matching documents")).not.toBeInTheDocument(); + expect(screen.getByText("No matching documents")).toBeInTheDocument(); + }); + + it("renders the document home for an empty query and wires every escape action", async () => { + const user = userEvent.setup(); + const onOpenRecentDocuments = vi.fn(); + const onOpenLibrary = vi.fn(); + const onOpenSourcePdf = vi.fn(); + render( + , + ); + + expect(screen.getByTestId("document-search-empty-state")).toBeInTheDocument(); + await user.click(screen.getByRole("button", { name: /Recent documents/i })); + await user.click(screen.getByRole("button", { name: /Browse sources/i })); + await user.click(screen.getByRole("button", { name: /Open a source PDF/i })); + expect(onOpenRecentDocuments).toHaveBeenCalledTimes(1); + expect(onOpenLibrary).toHaveBeenCalledTimes(1); + expect(onOpenSourcePdf).toHaveBeenCalledTimes(1); + }); + + it("reports an unavailable document search alongside the empty-result guidance", () => { + render(); + + expect(screen.getByRole("alert")).toBeInTheDocument(); + expect(screen.getByText(/No matching documents/)).toBeInTheDocument(); + }); +}); diff --git a/tests/mode-action-popup.dom.test.tsx b/tests/mode-action-popup.dom.test.tsx new file mode 100644 index 0000000000..92d74192d7 --- /dev/null +++ b/tests/mode-action-popup.dom.test.tsx @@ -0,0 +1,91 @@ +import { useState } from "react"; + +import { render, screen, waitFor } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { Search, UploadCloud } from "lucide-react"; +import { describe, expect, it, vi } from "vitest"; + +import { + ModeActionPopup, + modeActionItemsFor, + type ModeActionModeOption, +} from "@/components/clinical-dashboard/mode-action-popup"; + +const modeOptions: ModeActionModeOption[] = [ + { id: "documents", label: "Documents", icon: Search }, + { id: "upload", label: "Upload", icon: UploadCloud, disabled: true }, +]; + +function Harness({ onAction = vi.fn(), onModeSelect = vi.fn() }) { + const [open, setOpen] = useState(false); + + return ( + + ); +} + +describe("ModeActionPopup state transitions", () => { + it("starts closed, opens its action menu, and closes after an action", async () => { + const user = userEvent.setup(); + const onAction = vi.fn(); + render(); + + const trigger = screen.getByRole("button", { name: "Open document actions" }); + expect(trigger).toHaveAttribute("aria-expanded", "false"); + expect(screen.queryByRole("menu", { name: "Documents" })).not.toBeInTheDocument(); + + await user.click(trigger); + expect(trigger).toHaveAttribute("aria-expanded", "true"); + expect(screen.getByRole("menu", { name: "Documents" })).toBeInTheDocument(); + + await user.click(screen.getByRole("menuitem", { name: "Upload PDF" })); + expect(onAction).toHaveBeenCalledWith("documents-upload"); + expect(screen.queryByRole("menu", { name: "Documents" })).not.toBeInTheDocument(); + expect(trigger).toHaveAttribute("aria-expanded", "false"); + }); + + it("opens from the keyboard and moves focus through the action list", async () => { + const user = userEvent.setup(); + render(); + + const trigger = screen.getByRole("button", { name: "Open document actions" }); + trigger.focus(); + await user.keyboard("{ArrowDown}"); + + const first = screen.getByRole("menuitem", { name: "Upload PDF" }); + await waitFor(() => expect(first).toHaveFocus()); + await user.keyboard("{End}"); + expect(screen.getByRole("menuitem", { name: "Open source PDF" })).toHaveFocus(); + await user.keyboard("{Escape}"); + expect(screen.queryByRole("menu", { name: "Documents" })).not.toBeInTheDocument(); + await waitFor(() => expect(trigger).toHaveFocus()); + }); + + it("exposes disabled modes but never selects them", async () => { + const user = userEvent.setup(); + const onModeSelect = vi.fn(); + render(); + + await user.click(screen.getByRole("button", { name: "Open document actions" })); + const modeTrigger = screen.getByRole("button", { name: "Documents" }); + await user.click(modeTrigger); + + expect(screen.getByRole("menu", { name: "Choose search mode" })).toBeInTheDocument(); + expect(screen.getByRole("menuitemradio", { name: "Documents" })).toHaveAttribute("aria-checked", "true"); + const disabledMode = screen.getByRole("menuitemradio", { name: "Upload" }); + expect(disabledMode).toBeDisabled(); + await user.click(disabledMode); + expect(onModeSelect).not.toHaveBeenCalled(); + }); +}); From 482728dd9803184230e8a8ed7e9883b5231a0fa0 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Fri, 31 Jul 2026 01:31:59 +0800 Subject: [PATCH 2/3] test(ui): cover enabled mode selection --- tests/mode-action-popup.dom.test.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/mode-action-popup.dom.test.tsx b/tests/mode-action-popup.dom.test.tsx index 92d74192d7..d9dcad1193 100644 --- a/tests/mode-action-popup.dom.test.tsx +++ b/tests/mode-action-popup.dom.test.tsx @@ -13,6 +13,7 @@ import { const modeOptions: ModeActionModeOption[] = [ { id: "documents", label: "Documents", icon: Search }, + { id: "answer", label: "Answer", icon: Search }, { id: "upload", label: "Upload", icon: UploadCloud, disabled: true }, ]; @@ -72,7 +73,7 @@ describe("ModeActionPopup state transitions", () => { await waitFor(() => expect(trigger).toHaveFocus()); }); - it("exposes disabled modes but never selects them", async () => { + it("selects enabled modes and exposes disabled modes without selecting them", async () => { const user = userEvent.setup(); const onModeSelect = vi.fn(); render(); @@ -87,5 +88,10 @@ describe("ModeActionPopup state transitions", () => { expect(disabledMode).toBeDisabled(); await user.click(disabledMode); expect(onModeSelect).not.toHaveBeenCalled(); + + await user.click(screen.getByRole("menuitemradio", { name: "Answer" })); + expect(onModeSelect).toHaveBeenCalledWith("answer"); + expect(screen.queryByRole("menu", { name: "Choose search mode" })).not.toBeInTheDocument(); + await waitFor(() => expect(modeTrigger).toHaveFocus()); }); }); From a727fa5f4357fecb2fdf24afd4f53dd1c59f1aae Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Fri, 31 Jul 2026 02:13:33 +0800 Subject: [PATCH 3/3] docs: record PR #1469 review --- docs/branch-review-ledger.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index 52016f8894..ff3bef69f2 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -252,3 +252,4 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie | 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 | 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 | 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 |