Skip to content

perf: lazy-load heavy components, memoize SourceImage, optimize lucide-react - #133

Merged
BigSimmo merged 1 commit into
mainfrom
bigsimmo-performance-review
Jul 2, 2026
Merged

perf: lazy-load heavy components, memoize SourceImage, optimize lucide-react#133
BigSimmo merged 1 commit into
mainfrom
bigsimmo-performance-review

Conversation

@BigSimmo

Copy link
Copy Markdown
Owner

Performance improvements

  • Add optimizePackageImports for lucide-react - tree-shakes 40+ icon barrel imports at build time
  • Wrap ClinicalDashboard (~306 KB) with next/dynamic + ssr:false - defers bundle until after initial paint
  • Wrap DocumentViewer (~121 KB) with next/dynamic + ssr:false - same rationale
  • Memoize SourceImage with React.memo - prevents unnecessary re-renders and signed-URL fetches
  • Add src/app/loading.tsx and src/app/documents/[id]/loading.tsx - skeleton spinners during route navigation

No business logic changed. All changes are additive or wrapping existing behaviour.

…e-react
- Add optimizePackageImports for lucide-react to next.config.ts
- Wrap ClinicalDashboard with dynamic() + ssr:false in app/page.tsx
- Wrap DocumentViewer with dynamic() + ssr:false in documents/[id]/page.tsx
- Add route loading skeletons for root and document viewer routes
- Wrap SourceImage with React.memo to prevent spurious re-renders
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@BigSimmo
BigSimmo merged commit 7fa9897 into mainJul 2, 2026
1 of 2 checks passed
BigSimmo added a commit that referenced this pull request Jul 2, 2026
Revert "perf: lazy-load heavy components, memoize SourceImage, optimize lucide-react" (#133)
BigSimmo added a commit that referenced this pull request Jul 2, 2026
…tore runtime on / and /documents/[id]
PR #133 placed next/dynamic with { ssr: false } directly in the server
components src/app/page.tsx and src/app/documents/[id]/page.tsx. The App
Router forbids that ('ssr: false is not allowed with next/dynamic in
Server Components'), so the home page failed to compile and every route
500'd in dev; CI never caught it because the verify job does not build
or boot the app.
Fix preserves #133's lazy-load intent: the dynamic(ssr:false) calls move
into 'use client' wrappers (clinical-dashboard-lazy.tsx,
document-viewer-lazy.tsx) that the server pages import.
Verified: ui-smoke chromium 29/29 passed against a cold .next build;
typecheck and prettier clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
BigSimmo added a commit that referenced this pull request Jul 2, 2026
…e client-wrapper fix
Main reverted the #133 perf work wholesale, so the pages are back to
direct imports; drop the now-orphaned lazy client wrappers. If #133 is
re-landed, dynamic(ssr:false) must live in 'use client' wrappers (see
this branch's history at d1f2de4 for the working pattern).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
BigSimmo added a commit that referenced this pull request Jul 2, 2026
fix: restore green typecheck and runtime on main (PR #131 type migration + PR #133 ssr:false)
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
Sixth conflict today, and the first that auto-merged *wrongly*: git's text
merge concatenated both tables, duplicating all 63 open rows. PR #1421 had
landed on main using #128/#129/#130 — the exact id collision #112 describes —
so both sides had those ids with different content and the merge kept both.
`npm run check:outstanding-issues` caught it and stated the correct resolution
verbatim: renumber the incoming rows above the marker and bump it, rather than
taking one side wholesale and dropping the other's rows. Done exactly that —
main's table is authoritative, this branch's four rows renumber to
#131/#132/#133/#134, marker to 135. Verified both sides' rows survive:
main's #128-#130 and mine are all present and distinct.
Worth noting main's new #129 (`update-branch` API does not honour the
`merge=ledger` driver) is the server-side twin of my #134 (the driver is absent
wherever `npm install` was skipped). Same root cause from two directions.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY
BigSimmo added a commit that referenced this pull request Jul 30, 2026
…indings (#1424)
* docs(ledger): record PR #1400 closeout and capture three unrecorded findings
Documentation only — two ledger files, no code.
**Review closeout for PR #1400** appended with `ledger:append` (never
hand-written), recording the 17 findings fixed, the verification behind each,
and the post-merge check that all 8 commits are ancestors of main with the 4
changed files byte-identical.
**Three findings from that session that nothing else records:**
- `#125` — `@codex fix` produced 11 commits across a branch named `work`,
none fetchable, the same finding rewritten four times. It reads as success
while the branch is unchanged, which is the actual hazard.
- `#126` — both client-side push guards are inert for agent pushes:
`gh` absent makes the auto-merge sentinel fail open, and `core.hooksPath`
is set only by a local install. They protect the environment least likely to
need them.
- `#127` — this ledger's fixed-width padding makes one row's edit re-pad all
59, so it conflicts on nearly every main advance; each conflict silently
stopped all CI on #1400 via `#116`. Records that `merge=union` is the wrong
fix, with the evidence.
CircleCI was deliberately not filed — already captured as `#122`. Checked
before writing rather than after.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY
* docs(issues): correct unsafe pull_request_target advice in #129
Review caught a real problem in the guidance I filed, not in code: #129's
next-action suggested moving *both* push guards server-side into a
`pull_request_target` job. That context carries secrets and a write token, and
a format check must execute PR-head code — including the dynamic
`prettier.config.*` this very PR taught the guard to load. That is the classic
privileged-context vector, and `.github/workflows/pr-policy.yml` already avoids
it deliberately by checking out only `github.workflow_sha`.
Corrected, and the row now records why the whole idea was unnecessary:
formatting is already enforced server-side by `Static PR checks` running
`format:check` on ordinary `pull_request` CI, so the guard's only unique value
is failing fast before the push. Only the metadata-only auto-merge sentinel
could safely live in a target job.
Bad advice in a durable ledger is worse than no advice — someone would have
acted on it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY
* fix(issues): repair the duplicated table from the sixth main merge
Sixth conflict today, and the first that auto-merged *wrongly*: git's text
merge concatenated both tables, duplicating all 63 open rows. PR #1421 had
landed on main using #128/#129/#130 — the exact id collision #112 describes —
so both sides had those ids with different content and the merge kept both.
`npm run check:outstanding-issues` caught it and stated the correct resolution
verbatim: renumber the incoming rows above the marker and bump it, rather than
taking one side wholesale and dropping the other's rows. Done exactly that —
main's table is authoritative, this branch's four rows renumber to
#131/#132/#133/#134, marker to 135. Verified both sides' rows survive:
main's #128-#130 and mine are all present and distinct.
Worth noting main's new #129 (`update-branch` API does not honour the
`merge=ledger` driver) is the server-side twin of my #134 (the driver is absent
wherever `npm install` was skipped). Same root cause from two directions.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY
* docs: record PR 1424 review
---------
Co-authored-by: Claude <noreply@anthropic.com>
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
…ocation
CI caught what I did not: `static-pr` failed on `check:outstanding-issues` with
#131-#134 duplicated and two `issues:next-id` markers.
Cause: main's PR #1424 allocated #131-#134 for its own findings at the same time
this branch held #131-#135, and `merge=union` did what union does — kept both
sides under the same ids. That is #112's documented limit: union preserves
concurrent appends but cannot allocate unique ids, so the structural gate is the
only thing that catches it.
My error was pushing without re-running that gate. The previous push resolved a
`docs/branch-review-ledger.md` conflict, and I validated only that file before
pushing to win the race against main — but the same merge also touched
`docs/outstanding-issues.md`. `verify:cheap` would have caught it locally.
Main's rows keep #131-#134 (already merged and referenced elsewhere); this
branch's five renumber to #136-#140, one marker at 141, and the cold-cache
cross-reference in process-hardening follows its row.
Two of main's new rows also make a planned addition here redundant: #134 is the
absent ledger merge driver and #133 is the outstanding-issues merge churn — both
hit during this branch's work, both already captured upstream, so nothing new is
filed for them.
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
The union merge duplicated the whole open and archive tables again (two header
rows, every id twice) because main restructured the file while this branch held
rows in it. Same resolution as before and for the same reason: rebuild on main's
canonical file rather than hand-editing a doubled table, then re-apply this
branch's five rows.
Main is now at next-id=135, so they land as #135-#139 with the marker at 140.
None of the five is duplicated upstream — checked by summary before re-applying.
This is the third renumber of the same five rows in one PR. That is not a
mistake being repeated, it is #133 ("outstanding-issues conflicts on nearly
every main advance") happening: any branch that holds rows in this file
re-collides every time main lands one. Worth weighing whether captures should
land in their own PR ahead of the work rather than riding along with it.
BigSimmo added a commit that referenced this pull request Jul 30, 2026
…t did (#1427)
* test(phone-scroll): prove the drag delivered before asserting the chrome hid
CI run 30518866604 failed `ui-phone-scroll.spec.ts:423` on
expect(getByTestId('universal-header-collapse'))
.toHaveAttribute('data-scroll-hidden', 'true') // received ""
after the full 10s auto-retry, and the classifier recorded it as "needs
investigation". The assertion was right; the scroll never happened.
`dragScrollBy` moved the scroller with `scrollTop +=`, which clamps silently
at the end of the range, and returned nothing. When a page lays out shorter
than the test assumed — content still settling under full-suite CI load — a
720px request delivers a fraction of that, the chrome correctly stays visible
because document-detail chrome only hides past `scrollTop > 120`, and the
failure surfaces ten seconds later looking like a product regression. The
helper also resolved the scroll owner once up front, so a mid-drag layout
change left it pushing an element that had stopped scrolling.
- `dragScrollBy` now re-resolves the owner each step and returns the distance
actually travelled.
- `dragScrollUntilHidden` waits for the remaining downward runway (a condition
wait, not a settle sleep), drags, and fails naming the shortfall if the drag
could not cross the threshold. Used at the four sites that assert a hide
immediately after a fixed-distance drag.
- `addPhoneScrollRunway` waits for its 1600px filler to reach layout instead of
sleeping 50ms. All 14 call sites already depend on that runway existing.
Every assertion is byte-identical: a genuinely stuck header still fails exactly
as before, once the drag is proven to have happened. No `.first()` was added
(#93's stop rule) and no tolerance was relaxed.
* ci: shard Production UI across three runners
Measured on 2026-07-30 from the Actions API, two full UI-scope PR runs
(30520443076, 30519912667): `Production UI` took 15m26-16m31 of a 16.8-18.6
minute run — 83-89% of wall clock — while every other job finished by minute 4
and then waited. Playwright itself reported `339 passed (13.5m)`; the balance is
the isolated production build.
That single job is also where the churn cost lands: 42% of PR runs in the
sampled window were cancelled (25 of 60 completed), almost all superseded
mid-Production-UI.
Sharding is across runners, not workers. `workers: 1`, `fullyParallel: false`
and `retries: 0` are unchanged inside each shard, so determinism is identical
and per-runner load falls — which matters because #93's duplicate page root is
load-dependent. `run-playwright.mjs` already forwards argv to `playwright test`,
so `--shard` needed no runner change.
The shard count is measured, not chosen. `fullyParallel: false` makes a spec
file indivisible, so shard sizes are lumpy and more shards is not monotonically
faster. Over the 340 required chromium tests:
N=3 -> 121/106/113 largest 121
N=4 -> 121/106/96/17 largest 121 (same critical path, one more runner)
N=6 -> 65/56/106/5/91/17 largest 106
N=5 -> 121/106/0/96/17 and N=8 -> two empty shards
N=4 buys nothing over N=3, and any N with an empty shard would go red because
`test:e2e:pr` deliberately omits `--pass-with-no-tests`. Expected critical path
~15.5 -> ~7 min, assuming per-test cost is roughly uniform.
`fail-fast: false` so a failing shard cannot cancel its siblings and re-create
the cancelled-vs-failed ambiguity #95 removed. Artifact names are shard-scoped
because upload-artifact runs with `overwrite: false`. Branch protection requires
only the `pr-required` aggregate, and `needs` on a matrix job yields the roll-up
of all shards, so the aggregate is unchanged.
Also adds `restore-keys` to both Playwright browser caches: without a prefix
fallback a lockfile bump forced a cold browser download in every UI job at once,
now three times over.
* ci: bound the codex auto-resolve jobs and serialise the visual config
Two inconsistencies found while mapping the pipeline, neither load-bearing but
both silent:
- `codex-autofix-review-comments.yml` was the only workflow in the repo with no
`timeout-minutes` on either job, so both inherited GitHub's 360-minute default
for work that reads PR metadata and posts one comment.
- `playwright.visual.config.ts` set neither `workers` nor `fullyParallel`, so it
inherited Playwright's default `workers = 50% of CPUs`. The production config
pins both to serial deliberately; the visual lane was quietly opting out of
the anti-flake posture the rest of the suite is configured for.
* chore(gates): pin the documented gate count to the real chain
Both numbers were wrong. `CLAUDE.md` said 24 static/consistency gates against an
actual 25 — `check:assets` landed before that line was written, so it was wrong
at authoring — and the `gates` skill said "check 2 of 26" against an actual 28.
A stale count is not cosmetic here. The skill's whole point at that line is that
`verify:cheap` stops at the first failure and everything after it never ran; an
agent that believes the chain is 26 long cannot say how much a mid-chain failure
skipped.
`check:gate-manifest` already derives the real count from
`verify:cheap:internal`, so it now asserts the documented numbers against it.
The assertions fail closed: if the anchor phrasing disappears, the guard reports
a lost anchor rather than passing on a document it no longer checks.
Mutation-proven: reverting the skill to "26" fails with
".claude/skills/gates/SKILL.md says 26 where the chain has 28".
* docs(issues): capture the CI review's deferred findings
Five items from the CI/testing review that should not be changed blind:
- #125 `ui_changed` matches all of `src/app`, so an API-only diff pays the
15-minute UI gate. Narrowing it can hide a real regression, so it needs a
decision plus a compensating check rather than a quieter filter.
- #126 the Playwright build writes to a per-run distDir, so Next's build cache
is cold every run (~2 min, now ~29% of the sharded critical path). Fixing it
means suppressing the runner's documented always-cleanup, which must not ship
without executing the runner.
- #127 the advisory UI lane spends ~3 min per UI PR on 5 mockup tests; there are
currently zero `@quarantine` tests for it to cover.
- #128 CI Triage is complete and self-tested but inert pending a repo variable.
- #129 four `changes` outputs are computed and consumed by nothing, and
`coverage_changed` fires on any non-doc file.
* docs(ledger): record the ci-testing-review pass at this HEAD
* ci: re-measure the shard split on the merged tree and refresh stale gate counts
The merge changed both numbers this branch had recorded.
Shard balance, re-measured against 342 required chromium tests (was 340):
N=3 -> 121/111/110 largest 121
N=4 -> 121/106/98/17 largest 121
N=3 remains correct — one 121-test spec group bounds both, so N=4 spends an
extra runner for the same critical path. The re-measure command is now in the
workflow comment so the next person does not have to rediscover it.
Gate counts: merging main added `check:gitleaks-pinned` and
`check:pr-mergeability` to `verify:cheap:internal`, so the documented counts
went stale the moment the merge landed — 25 -> 27 static, 28 -> 30 total. The
guard added earlier in this branch caught it immediately rather than letting the
docs drift again, which is the whole reason it exists.
Also records the `ui-critical-fast` interaction: the UI critical path is now that
15-test fail-fast job plus the slowest shard, not the full 13.5-minute suite, so
neither of this branch's pre-merge timings can be read on its own.
* docs(issues): rebuild the ledger after a union-merge duplication
The `merge=union` driver on `docs/outstanding-issues.md` preserves concurrent
appends, but when both sides restructure the same region it concatenates them
wholesale. Merging the latest main did exactly that: every open row appeared
twice and both `issues:next-id` markers survived — 66 duplicate-id errors from
`check:outstanding-issues`, which is precisely the failure that gate exists to
catch (#112).
Resolved by rebuilding on main's canonical file rather than by hand-editing the
duplicated table: reset to `origin/main`, then re-apply this branch's five
captured rows at #131-#135 (main had advanced its allocation to #130 while this
branch was open, so the earlier #128-#132 numbering collided again) and
re-apply the #127 narrowing note. Marker bumped to 136.
Union merge cannot allocate unique ids; only the structural gate can catch when
it has produced an invalid file. It did.
* ci: record the measured shard result, correcting the predicted one
First real run of the sharded shape (CI 30530618838, all green, whole run
13m39 against a 16.8-18.6 min unsharded baseline):
ui-critical-fast 15 tests 3m14
Production UI (1) 121 tests 9m36
Production UI (2) 111 tests 6m54
Production UI (3) 110 tests 6m20
The prediction was wrong by ~40%. ~6.8 min was expected for the largest shard
from 121/342 tests x 13.5 min; 9m36 happened. Per-test cost is not uniform —
111 tests took 6m54 while 121 took 9m36 — so a count-balanced split understates
the slowest shard whenever the slow specs land in one group. `--shard` can only
balance by count; balancing by duration would mean splitting the slow spec files
themselves.
The win is real but smaller than claimed, and the workflow comment and
process-hardening now carry the measured numbers plus the reason the arithmetic
misleads, so the next person re-measures instead of re-deriving.
Also merges origin/main. The ledger conflict was GitHub-visible only: that file
carries merge=union locally, which GitHub does not honour (#129). Resolved by
keeping the one genuinely new record and dropping three that main already had
elsewhere in the file — append-only forbids dropping a record that exists once,
not keeping a second copy. Superseding record appended for this HEAD, since the
prior one asserted a root cause that #127's trace evidence refutes.
* docs(issues): renumber this branch's rows above main's concurrent allocation
CI caught what I did not: `static-pr` failed on `check:outstanding-issues` with
#131-#134 duplicated and two `issues:next-id` markers.
Cause: main's PR #1424 allocated #131-#134 for its own findings at the same time
this branch held #131-#135, and `merge=union` did what union does — kept both
sides under the same ids. That is #112's documented limit: union preserves
concurrent appends but cannot allocate unique ids, so the structural gate is the
only thing that catches it.
My error was pushing without re-running that gate. The previous push resolved a
`docs/branch-review-ledger.md` conflict, and I validated only that file before
pushing to win the race against main — but the same merge also touched
`docs/outstanding-issues.md`. `verify:cheap` would have caught it locally.
Main's rows keep #131-#134 (already merged and referenced elsewhere); this
branch's five renumber to #136-#140, one marker at 141, and the cold-cache
cross-reference in process-hardening follows its row.
Two of main's new rows also make a planned addition here redundant: #134 is the
absent ledger merge driver and #133 is the outstanding-issues merge churn — both
hit during this branch's work, both already captured upstream, so nothing new is
filed for them.
* docs(issues): rebuild against main's current id allocation
The union merge duplicated the whole open and archive tables again (two header
rows, every id twice) because main restructured the file while this branch held
rows in it. Same resolution as before and for the same reason: rebuild on main's
canonical file rather than hand-editing a doubled table, then re-apply this
branch's five rows.
Main is now at next-id=135, so they land as #135-#139 with the marker at 140.
None of the five is duplicated upstream — checked by summary before re-applying.
This is the third renumber of the same five rows in one PR. That is not a
mistake being repeated, it is #133 ("outstanding-issues conflicts on nearly
every main advance") happening: any branch that holds rows in this file
re-collides every time main lands one. Worth weighing whether captures should
land in their own PR ahead of the work rather than riding along with it.
* docs: record PR 1427 review
---------
Co-authored-by: Claude <noreply@anthropic.com>
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
Addresses the Codex P2 on this PR and fixes my own mistake in the first attempt.
The correction itself is unchanged in substance: `documents_status_id_idx` is
canary-gated, not ordering-safe, because `rag-candidate-sources.ts:482` pairs
`.eq("status","indexed")` with an unordered `.limit(12)` and `(status, id)`
serves that equality. The reasoning stays in the runbook, which is the
authority; the ledger row now just points at it.
What changed is the shape. My first version added prose to #102's Detail cell,
which is the widest cell in that column — so Prettier repadded every row and the
diff became 63 insertions / 63 deletions. Row #133 records that this exact
whole-table behaviour has already caused mechanical conflicts that silently
stopped all CI, and it is very likely how the original correction was lost
between #1423 and main in the first place.
Three attempts established the rule empirically, since my first two hypotheses
were both wrong: growing the cell reflows (68 lines), *shrinking* it also
reflows (68 lines, because the column width tracks this cell), and trailing
whitespace padding does not help because Prettier trims it. The replacement is
therefore exactly the same length as the text it replaces — 97 characters — and
the diff is now 1 insertion / 1 deletion with Prettier reporting the file
unchanged.
Verified on an untouched row: before this, #100's Detail cell lost exactly one
padding space (3533 -> 3532 chars), which is what proved the column width, not
my cell's content, was driving the churn.
Gates: outstanding-issues guard 137 rows / unique ids; branch-review-ledger 117
live + 1206 archived, no duplicates; prettier clean. No SQL applied.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01361jh3eYVjJCzXWjAhdZiF
BigSimmo added a commit that referenced this pull request Jul 30, 2026
* fix(ledger): remove merge=union from the issues ledger, per its own #133
Ledger #133 already recorded union as the wrong driver for this file —
"two sides each bumping the marker produce two `next-id` lines, corrupting
the file silently where a conflict would fail loudly" — but `.gitattributes`
still set it and `check-outstanding-issues.mjs` *required* it, so the repo's
own tested conclusion was contradicted by its own config.
PR #1430 confirmed the cost at scale: four merges in one session, each
reporting success while duplicating the entire open-items table
(`#59 appears 2 times (lines 101, 166)` and so on for every row), each
needing a manual rebuild from origin/main. Union also makes `git merge-tree`
report a clean tree, so the pre-merge conflict check cannot warn.
Unlike docs/branch-review-ledger.md — which keeps its custom `merge=ledger`
driver, union plus exact-row dedupe — this file allocates IDs by
read-modify-write. Concurrent appends therefore need manual renumbering
whatever the driver does (hit twice on 2026-07-30: #125 and #135 collisions),
so union bought nothing and only hid the overlap. Default 3-way merge
conflicts honestly instead.
The gate's attribute check is inverted rather than deleted, so a driver
reappearing here is a red gate. AGENTS.md, docs/process-hardening.md,
.claude/skills/issues/SKILL.md and docs/scripts-index.md are updated to
match, and #133's driver half is marked resolved with its still-open half
(fixed-width padding making every row edit one hunk) left intact.
Verified: reintroducing `docs/outstanding-issues.md merge=union` fails the
gate with "must have NO merge driver (found merge=union)", and removing it
passes with "no merge driver" — the gate bites, not just passes.
verify:cheap exit 0: Test Files 434 passed (434), Tests 4563 passed |
4 skipped (4567). Whole-tree prettier clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XrPbbfU9yWuEjEVypCr4ZQ
* fix(gate): reject `-merge` too, not just a named driver
Codex review is right: the new check accepted `unset` alongside
`unspecified`, and those are not the same state. Per gitattributes, an
Unspecified `merge` attribute is the documented default 3-way text merge —
the contract this PR establishes — while Unset (`-merge`) takes the current
branch's version and declares the merge conflicted, so every two-sided edit
becomes a manual resolution. A global or future attributes file could
therefore have violated the contract with the gate still printing "no merge
driver".
Reproduced before fixing: appending `docs/outstanding-issues.md -merge` made
`git check-attr` report `merge: unset` and the guard passed. It now fails
with a message naming the Unset/Unspecified distinction and telling the
reader to drop the negated attribute rather than add one.
The acceptance decision moves into an exported `mergeAttributeProblem` so
the distinction is unit-tested rather than only reasoned about, with four
cases in tests/repo-hygiene.test.ts: `unspecified` accepted; `unset`,
`union`/`ledger`, and an empty reading all rejected. The empty case matters
because an unparsed check-attr output would otherwise make the whole check
vacuous.
Verified: with `-merge` present the gate fails on the new message; with it
removed it passes "no merge driver". repo-hygiene 47 passed (47).
verify:cheap exit 0 — Test Files 435 passed (435), Tests 4508 passed |
4 skipped (4512). Whole-tree prettier clean. (Test total differs from this
branch's earlier run because it now carries main's #1423/#1427/#1438; this
commit adds four.)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XrPbbfU9yWuEjEVypCr4ZQ
---------
Co-authored-by: Claude <noreply@anthropic.com>
BigSimmo added a commit that referenced this pull request Jul 30, 2026
…#1440)
* docs(issues): re-apply #102's canary-gated correction lost to a merge
Codex raised this as a P2 on PR #1423: with the runbook corrected, ledger #102
still told an operator the `(status,id)` use was ordering-safe, so the two
operator entry points contradicted each other. A reply on that thread claimed
the fix landed in 2bdc245. It did not reach `main`.
Verified by content rather than by SHA, which matters here: #1423 was
squash-merged, so `git merge-base --is-ancestor` returns NO for every original
commit and proves nothing either way. Reading `docs/outstanding-issues.md` at
`origin/main` (0310c6a) shows the retracted sentence still present, while the
runbook correction and the test change from the same PR both landed.
Most likely cause, and it is a documented hazard: #1428 ("archive five
completed ledger rows") touched this same file on `main`, and #112 records that
`docs/outstanding-issues.md` conflicts present as ordinary content conflicts a
hurried resolution can settle by dropping one side. Union merge has since been
added to this file, but it would not have saved this case — both sides edited
the same sentence.
The row now mirrors the runbook's classification and names the runbook as the
authority if the two ever diverge again, so a future reader has a tie-breaker
rather than two equal-looking claims.
Gates: verify:cheap exit 0, Test Files 434 passed (434), Tests 4563 passed | 4
skipped. Outstanding-issues guard, branch-review-ledger guard, docs:check-links,
docs:check-scripts, prettier all pass. No SQL applied; no index created.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01361jh3eYVjJCzXWjAhdZiF
* docs(issues): correct #102 within the existing table width
Addresses the Codex P2 on this PR and fixes my own mistake in the first attempt.
The correction itself is unchanged in substance: `documents_status_id_idx` is
canary-gated, not ordering-safe, because `rag-candidate-sources.ts:482` pairs
`.eq("status","indexed")` with an unordered `.limit(12)` and `(status, id)`
serves that equality. The reasoning stays in the runbook, which is the
authority; the ledger row now just points at it.
What changed is the shape. My first version added prose to #102's Detail cell,
which is the widest cell in that column — so Prettier repadded every row and the
diff became 63 insertions / 63 deletions. Row #133 records that this exact
whole-table behaviour has already caused mechanical conflicts that silently
stopped all CI, and it is very likely how the original correction was lost
between #1423 and main in the first place.
Three attempts established the rule empirically, since my first two hypotheses
were both wrong: growing the cell reflows (68 lines), *shrinking* it also
reflows (68 lines, because the column width tracks this cell), and trailing
whitespace padding does not help because Prettier trims it. The replacement is
therefore exactly the same length as the text it replaces — 97 characters — and
the diff is now 1 insertion / 1 deletion with Prettier reporting the file
unchanged.
Verified on an untouched row: before this, #100's Detail cell lost exactly one
padding space (3533 -> 3532 chars), which is what proved the column width, not
my cell's content, was driving the churn.
Gates: outstanding-issues guard 137 rows / unique ids; branch-review-ledger 117
live + 1206 archived, no duplicates; prettier clean. No SQL applied.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01361jh3eYVjJCzXWjAhdZiF
* docs: record issue correction review
---------
Co-authored-by: Claude <noreply@anthropic.com>
BigSimmo added a commit that referenced this pull request Jul 30, 2026
* issues: close#140 as a duplicate of #133, resolved by #1444#140 was opened mid-session for the union-driver damage before I noticed
#133 had already recorded the same finding, earlier and with the same
conclusion. Two open rows described one condition, and PR #1444 has since
removed that condition: `merge=union` is gone from `.gitattributes`,
`check:outstanding-issues` now requires an unspecified `merge` attribute,
and regression tests cover `union`, `-merge` and an unparsed reading.
Moved to the archive table rather than deleted, pointing readers at #133 —
whose still-open half is the real conflict-frequency cause: fixed-width
column padding makes any one-row edit re-pad every row, so git sees the
whole table as one hunk. The surviving evidence (four merges on PR #1430
each reporting success while duplicating the entire open-items table) lives
there too.
Verified: check:outstanding-issues 138 rows, 66 open / 72 archived (was
67/71 — moved, not copied), unique ids, next-id=141, no merge driver;
docs:check-links 1361 references resolve; prettier clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XrPbbfU9yWuEjEVypCr4ZQ
* docs: record duplicate issue review
---------
Co-authored-by: Claude <noreply@anthropic.com>
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
Resolves the docs/outstanding-issues.md conflict with PR #1453. That file
deliberately carries no merge driver (#133), so overlapping appends conflict
loudly rather than being silently concatenated.
Resolved as the issues skill requires: rebuilt the file from origin/main and
re-applied only the two rows this branch owns (the #86 in-place update and the
new #145), so none of #1453's rows were dropped. Verified #140-#144 all still
present and #144's cell content byte-identical to main. Re-checked that #145 was
still free on main before reusing the id — main's next-id marker was untouched at
145, so there was no id collision to reallocate around.
docs/branch-review-ledger.md auto-resolved through its merge=ledger driver.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGEBHp4Seoh1jK1vGTNtYS
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
Dispatched live-web-vitals.yml against psychiatry.tools (run 30548662649,
5 routes x 3 samples). #17 has been the gate on seven latency findings for
weeks with no evidence behind it. It now has evidence, and it is a breach.
Mobile medians against LCP<2500ms / CLS<0.1:
root 4308ms 0.023
therapy-compass 4716ms 0.142
documents-search 3676ms 0.220
dsm 3639ms 0.363
forms 3786ms 0.212
Desktop passes everywhere (LCP 625-694ms, CLS 0.016-0.097), which is worth
noting because desktop-only checking would have concluded the opposite.
The verdict is gradeable rather than noisy: every LCP sample range sits wholly
above 2500ms, so the straddle rule #114 added does not fire. That distinction is
the whole point of #1407's sampling work — a single run per cell could not have
told a real breach from variance.
Applying the rule as written before the numbers were read: any breach makes only
the breaching routes' findings actionable, and NOTHING becomes WONTFIX. That is
the opposite of what a favourable sample would have produced, which is exactly
why the rule was written first.
CLS 0.363 on /dsm is the worst single number and is visible layout shift, not a
byte-count problem — so it is not addressed by the payload findings #17 gates.
Recorded honestly as one step short of complete: this reads the summariser's
emitted table, not the raw Lighthouse JSON (artifact 8762211043, 30-day
retention). The row itself asks for that cross-check before recording a verdict,
most of all a PASS; this is a breach, so the risk of the table flattering the
result is lower, but the check is still outstanding. INP is absent because
Lighthouse cannot measure it in lab conditions.
Diff stays 1 line: #17's Detail cell is 2184 chars against the column's 3268
budget, so nothing repads (see #133).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01361jh3eYVjJCzXWjAhdZiF
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
The merge of origin into this branch hit exactly the damage #133/#140
describe: merge=union concatenated both sides of the ledger rather than
merging it.
Two collisions, both repaired without dropping either side's rows:
- Another agent had already allocated #141-#144 on main for different
items while this branch used #141-#143. The incoming rows renumber, per
the ledger rule, so the capture becomes #145 (adopt a consolidated
answer-home notice block), #146 (answer mode ships no verify-before-use
caveat) and #147 (verify:pr-local exits 0 when its build step refuses to
run). Their cross-references were updated to match, and the two
duplicated next-id markers collapse to one at 148.
- #140 appeared in both tables: it was closed on main as a duplicate of
#133 (PR #1444) while this branch still carried it open. The resolution
is honoured — the stale open row goes, the archive row stays.
check:outstanding-issues: 145 rows (72 open, 73 archived), unique ids,
next-id=148 above the highest, no merge driver.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NPyFcMfn1jMmphr6AqiWBg
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
The three captured rows are dropped from docs/outstanding-issues.md, leaving
it byte-identical to origin/main. They will be re-landed as their own
single-file change once this PR merges.
AGENTS.md recommends bundling append-only ledger rows because they are
normally zero-risk, but that assumes a quiet file. Right now it is the
hottest file in the repo: bundling them here cost three ID collisions and
three full CI restarts in about thirty minutes (main took #141-#144, then
#145, then #146, while this branch needed #145-#149 in turn). #133 already
records that this file conflicts on nearly every main advance.
The mockups diff itself touches four uncontended files and has not conflicted
once today, so removing the ledger rows takes this PR out of a race it has no
reason to be in. No content is lost: the row text is preserved verbatim and
re-applied against a fresh main with clean ids.
check:outstanding-issues: 144 rows (70 open, 74 archived), unique ids,
next-id=147 above the highest, no merge driver.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NPyFcMfn1jMmphr6AqiWBg
BigSimmo added a commit that referenced this pull request Jul 30, 2026
The id this branch allocated was taken by main three times running (#135 ->
#141 -> #145 -> #147), and the third merge conflicted as one hunk covering the
entire open-items table, so main's table was taken wholesale and the branch's
deltas re-applied by script.
Two further findings: the GitHub Update-branch button auto-merged this file into
duplicate #141 rows with the marker left below main's highest id, a head that
would have failed check:outstanding-issues; and removing merge=union did not
reduce collision frequency, it converted silent duplication into loud conflicts.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
Fifth consecutive genuine conflict on docs/outstanding-issues.md,
confirmed with git merge-tree before acting.
Main's d8b034c (PR #1441) deleted three rows from the Open items table
and archived none of them: #85, which that PR genuinely resolved by
adding check-upload-limit-parity.mjs; #119, a duplicate of #122; and
#105, which is open and unresolved — its LoadingPanel half is still
unverified. This resolution mirrors main on #85 and #119, which were
dispositionable, and keeps #105, which was not.
#105 survived only because this resolution was done row by row and then
diffed with column padding normalised away. Taking either side wholesale
would have lost it silently, which is what AGENTS.md forbids for this
file and what appears to have happened upstream.
Filed as #148: check:outstanding-issues validates duplicate ids, ids in
both tables, stale markers and malformed rows, but never compares
against the previous revision, so a row that simply disappears is
invisible to it in verify:cheap and static-pr alike. The fix is a
deletion check against the merge base, not a union merge driver — #133
removed that driver deliberately and reinstating it would bring back the
duplicate-row damage it was removed to stop.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01361jh3eYVjJCzXWjAhdZiF
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
Resolves the docs/outstanding-issues.md conflict against #1441 and #1470. That
file deliberately carries no merge driver (#133), so overlapping edits conflict
loudly rather than being silently concatenated.
Resolved by the prescribed recipe: rebuilt the file from origin/main and
re-applied only this branch's own change (the #86 row's "Hydration SHIPPED
(#101)" edit). Verified the result has an identical row count and an identical
id set to origin/main, so #1470's closures were preserved and nothing was
dropped; the only content delta against main is that one row.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGEBHp4Seoh1jK1vGTNtYS
BigSimmo added a commit that referenced this pull request Jul 30, 2026
…ation, restore #105 after an upstream deletion (#1459)
* docs(issues): record #105's preconnect verification in a browser
The preconnect half of #105 is verified; the LoadingPanel half is not, and the
row now says which is which rather than carrying one PENDING for both.
Worth recording how it was verified, because the obvious check silently proves
nothing: locally NEXT_PUBLIC_SUPABASE_URL is unset, so supabaseOrigin() returns
null and the layout renders no link at all. Loading the app and finding no
preconnect would have looked like a failure and been an absent fixture. The
check needs a placeholder origin (no real network call — the point is React's
hoisting, not Supabase connectivity).
With that set, both the SSR HTML and the live browser DOM show preconnect and
dns-prefetch in <head> with zero stray preconnect in <body>, so React 19 does
hoist them out of the body where they are authored.
survives the hoist, which matters: without it supabase-js's CORS fetches open a
second connection and the hint buys nothing.
The remaining half needs a different technique. A LoadingPanel fallback only
renders while a lazy chunk is in flight, so it needs a throttled-network browser
check rather than verify:ui, which would race past it.
Gates: outstanding-issues guard 142 rows / unique ids; prettier clean; the edit
is a 1-line diff because it stays inside the Detail column's existing width
(1133 chars against a 3268 budget) — see #133 for why that matters in this file.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01361jh3eYVjJCzXWjAhdZiF
* docs(issues): record #17's live Web-Vitals verdict — mobile breaches
Dispatched live-web-vitals.yml against psychiatry.tools (run 30548662649,
5 routes x 3 samples). #17 has been the gate on seven latency findings for
weeks with no evidence behind it. It now has evidence, and it is a breach.
Mobile medians against LCP<2500ms / CLS<0.1:
root 4308ms 0.023
therapy-compass 4716ms 0.142
documents-search 3676ms 0.220
dsm 3639ms 0.363
forms 3786ms 0.212
Desktop passes everywhere (LCP 625-694ms, CLS 0.016-0.097), which is worth
noting because desktop-only checking would have concluded the opposite.
The verdict is gradeable rather than noisy: every LCP sample range sits wholly
above 2500ms, so the straddle rule #114 added does not fire. That distinction is
the whole point of #1407's sampling work — a single run per cell could not have
told a real breach from variance.
Applying the rule as written before the numbers were read: any breach makes only
the breaching routes' findings actionable, and NOTHING becomes WONTFIX. That is
the opposite of what a favourable sample would have produced, which is exactly
why the rule was written first.
CLS 0.363 on /dsm is the worst single number and is visible layout shift, not a
byte-count problem — so it is not addressed by the payload findings #17 gates.
Recorded honestly as one step short of complete: this reads the summariser's
emitted table, not the raw Lighthouse JSON (artifact 8762211043, 30-day
retention). The row itself asks for that cross-check before recording a verdict,
most of all a PASS; this is a breach, so the risk of the table flattering the
result is lower, but the check is still outstanding. INP is absent because
Lighthouse cannot measure it in lab conditions.
Diff stays 1 line: #17's Detail cell is 2184 chars against the column's 3268
budget, so nothing repads (see #133).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01361jh3eYVjJCzXWjAhdZiF
* docs(issues): withdraw the #105 LoadingPanel verification — it matched the wrong component
The claim that `LoadingPanel` was verified present in the SSR response HTML
does not hold, so #105 is reopened rather than archived.
The evidence was `role="status" aria-label="Loading"` appearing in the
initial HTML of `/`, `/dsm` and `/forms`. Those hits are real, but that
exact string has exactly one renderer in `src/` — `ModeHomePageSkeleton`
(`src/components/mode-home-page-skeleton.tsx:8`). `LoadingPanel` never
emits a bare "Loading" label; it renders `aria-label={label}`, always a
specific string such as "Loading differentials". Re-checked per route
against a running server, `/`, `/dsm`, `/forms`, `/differentials` and
`/favourites` return zero `aria-label="Loading <something>"` matches.
Codex's mechanism finding on this PR stands and is not what failed: the
installed Next 16 loader does set `hasSuspenseBoundary` when a `loading`
element is supplied, and `BailoutToCSR` throws on the server, so a mounted
`ssr:false` surface emits its fallback into the response HTML. What was
missing is that this only fires for a surface mounted during the initial
render, and none of the eleven in `clinical-dashboard-lazy.tsx` are —
every one sits behind interaction state (`ClinicalDashboard.tsx:3666-4070`).
So neither a cold-load grep nor the throttled check the row originally
prescribed can observe them; that needs a driven browser session.
The reopened row and its queue entry both record the withdrawn claim and
carry an explicit stop rule against re-closing on a cold-load grep. The
preconnect half remains verified and is marked so, to avoid redoing it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01361jh3eYVjJCzXWjAhdZiF
* docs(issues): rank #17's mobile findings — CLS reproduces exactly offline
#17 asked for the mobile breach to be ranked by measured contribution.
Done, and the measurement turned up something that changes what the work
costs.
Ran the local offline production Lighthouse harness over the same five
routes the live dispatch used. The mobile CLS numbers do not merely
correlate with production — they match run 30548662649 to three decimals
on all four locally measurable routes (0.023 / 0.142 / 0.220 / 0.363),
and the desktop range matches at both endpoints (0.016-0.097). /forms
did not measure locally (Lighthouse NO_NAVSTART, its own "run again"
transient); live it was 0.212.
So CLS on these routes is deterministic layout structure, not network or
production data. The CLS half of #17 is debuggable and gate-able locally
at zero provider cost, and #17's recorded premise that production vitals
need Supabase secrets is stale — run-lighthouse-budget.mjs builds and
serves an offline production app precisely to sidestep that. Its earlier
"dev-mode CLS is excellent at 0.00-0.04" note was measuring dev, which
does not reproduce production.
LCP does NOT reproduce and must not be read from local runs: 2014-2051 ms
local 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 and live — which corroborates #117.
Filed as #147 with the ranking (/dsm 0.363 worst, then /documents/search
0.220, /forms 0.212, /therapy-compass 0.142, / 0.023 passing) and the
next step: Lighthouse's layout-shift-elements audit returned zero items
on every route, so element attribution needs a PerformanceObserver on
layout-shift against the same offline build.
Two reproduction traps recorded with it: the harness reads CHROME_PATH
but nothing in this container sets it, so chrome-launcher fails on every
route; and a truncated `progress` package in the npx cache broke
Lighthouse startup entirely. No budget baseline was committed — the
grader correctly refused this run as incomplete evidence.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01361jh3eYVjJCzXWjAhdZiF
* docs(review): record PR 1459 final reconciliation
---------
Co-authored-by: Claude <noreply@anthropic.com>
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
Second docs/outstanding-issues.md conflict, this time against #1459. That file
carries no merge driver by design (#133), so any overlapping edit conflicts.
Resolved by the same prescribed recipe: rebuilt from origin/main and re-applied
only this branch's own #86 "Hydration SHIPPED (#101)" edit. Verified identical
row count (144) and identical id set to origin/main, so #1459's ranking change,
withdrawn verification and restored row are all preserved; the only content
delta against main is that one row.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGEBHp4Seoh1jK1vGTNtYS
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
Third docs/outstanding-issues.md conflict, this time against #1462, #1467 and
#1482. That file carries no merge driver by design (#133), so any overlapping
edit conflicts; main is landing issue-ledger commits continuously.
Resolved by the same prescribed recipe: rebuilt from origin/main and re-applied
only this branch's own #86 "Hydration SHIPPED (#101)" edit. Verified identical
row count (146) and identical id set to origin/main, so the archived rows from
all three of those PRs are preserved and nothing was dropped.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGEBHp4Seoh1jK1vGTNtYS
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
Fourth docs/outstanding-issues.md conflict. Same cause and same prescribed
resolution: that file has no merge driver by design (#133), main is landing
issue-ledger commits continuously, so every sync collides on it.
Rebuilt from origin/main and re-applied only this branch's own #86 "Hydration
SHIPPED (#101)" edit. Verified identical row count (146) and identical id set to
origin/main before committing, so no other session's rows were dropped.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGEBHp4Seoh1jK1vGTNtYS
BigSimmo added a commit that referenced this pull request Jul 30, 2026
…equisite (#1465)
* issues: record fresh #133 evidence and the un-pad fix's Prettier prerequisite
#133 tracks ledger conflict frequency after `merge=union` was removed. Two
things learned today that the row did not yet capture.
Removal did not reduce the pain. PR #1451 conflicted on
`docs/outstanding-issues.md`; its session resolved the conflict by renumbering a
colliding row, and `git merge-tree` showed the branch conflicting again minutes
later, because four further `main` commits each touched the table. Both sides had
concurrently allocated `#141` from the same marker, so a duplicate id reached a
pushed tip and failed `check:outstanding-issues` there independently of the
conflict — the read-modify-write allocation race this row already predicts,
observed rather than theorised.
The row's proposed fix ("stop padding this table") also has an unstated
prerequisite: Prettier enforces padded markdown tables under `docs/`. Verified by
checking byte-identical ragged content in a Prettier-ignored path (passes) and
under `docs/` (fails), so the first result alone would have been a false green.
Un-padding therefore needs `docs/outstanding-issues.md` added to
`.prettierignore`, exactly as its sibling `docs/branch-review-ledger.md` already
is at line 23.
Evidence only — no behaviour change, and deliberately not the un-pad itself:
that rewrites every open row and would conflict with every in-flight ledger edit,
so it wants a quiet queue.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs: record PR 1465 review
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
A real conflict, as expected: this branch reformats every row of
docs/outstanding-issues.md, so any main advance that touches the table
collides with it. Grafting rows is the wrong resolution for a whole-file
transformation, so main's content is taken wholesale and the transformation
re-applied on top — un-pad every row, then rewrite #133, which main still
carried in its pre-#1479 form.
That also keeps main's own ledger movement intact: 146 rows, 58 open and 88
archived, where this branch previously saw 70/74. Those are main's
archivals, not losses from this resolution.
Verified after resolving: check:outstanding-issues 146 rows (58 open, 88
archived), unique ids, next-id=149, no merge driver; docs:check-links 1414
references resolve; whole-tree prettier clean with the file ignored; zero
padded rows remain.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XrPbbfU9yWuEjEVypCr4ZQ
BigSimmo added a commit that referenced this pull request Jul 30, 2026
)
#133 asked to "stop padding this table (Prettier will still render it
readably)". Measuring it showed the fix was infeasible as written, because
Prettier is what pads the table: stripping the padding and running
`prettier --write` restored the file byte-for-byte identical to the
original. Un-padding therefore requires prettier-ignoring the file, which
this does — following the precedent already set for
docs/branch-review-ledger.md, which is ignored for the same reason.
Nothing structural is lost. check:outstanding-issues gates row shape, ids,
the next-id marker and the merge attribute far more strictly than column
alignment ever did, and it is required in verify:cheap and CI static-pr.
The mechanism is also narrower than #133 claimed, and the row is corrected
rather than left overstating it. "A single row's edit re-pads all 59 open
rows" holds only when the edit raises a column's *maximum* width; an edit
inside the existing maxima is 2 changed lines either way. Measured on the
real file:
lengthen a Detail cell padded 2 lines un-padded 2 lines
widen a Summary past max padded 144 lines un-padded 2 lines
That distinction is the point rather than a caveat: appending a new row is
precisely the max-raising operation, and appending is what agents do to this
file constantly, so the worst case was also the common case. A 144-line hunk
conflicts with anything else touching the table, and each such conflict
stops all CI on the PR until resolved (#116).
The one-time reformat is 178 rows. It will conflict with any open PR that
touches this file, so merge it when the queue is quiet rather than mid-sweep.
Verified: check:outstanding-issues 144 rows (70 open, 74 archived), unique
ids, next-id=147, no merge driver; docs:check-links 1407 references resolve;
whole-tree prettier clean with the file now ignored.
Not caused by this change: verify:cheap exits 1 on
tests/installed-lock-parity.test.ts ("expected 10000000 to be less than or
equal to 40000"). It fails identically on clean main with none of these
changes applied, so it is pre-existing and left untouched rather than
absorbed here. Everything else passed: 436 passed (437) files.
Claude-Session: https://claude.ai/code/session_01XrPbbfU9yWuEjEVypCr4ZQ
Co-authored-by: Claude <noreply@anthropic.com>
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
…onflict loop
Third consecutive real conflict blocking this PR's CI, always the same file,
and the fix is to stop touching it rather than to resolve it a fourth time.
main's newest commit is `fix(ledger): stop Prettier padding the issues table,
closing #133 (#1479)` — a whole-file reformat of docs/outstanding-issues.md.
Every row changed shape, so any edit to any row conflicts. That file is also
touched by nearly every main PR (row appends, archival moves), and this branch
is competing with a queue that merges several times an hour.
This PR's entire stake in it was ONE cosmetic line: a note on #146 saying the
cited spec moved to ui-phone-scroll-page-owned.spec.ts in the split. Three
CI-blocking conflicts — each one stopping GitHub building refs/pull/1466/merge
so no pull_request workflow ran at all — is a bad trade for that.
So the file is taken from main verbatim and the note is not re-applied. This
PR's diff no longer contains docs/outstanding-issues.md, which removes its only
remaining contact point with the hottest file in the repo.
Cost, stated rather than hidden: #146 keeps citing the old path. That row
already records that the exact test title is the durable identity because
declaration lines drift, so the stale path misleads nobody who reads it. The
note belongs in a docs-only PR when the ledger is not mid-reformat.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JHLPEV4o1rzipPDqshCSHY
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
Fifth docs/outstanding-issues.md conflict. Applying the default announced to the
user after the fourth: drop the #86 "Hydration SHIPPED (#101)" row from this PR
rather than keep re-resolving it.
That file has no merge driver by design (#133) and main lands issue-ledger
commits continuously, so every sync collided on it — five conflicts, each
costing a full CI cycle, for one documentation line unrelated to the extraction.
This branch now takes origin/main's copy verbatim and no longer modifies the
file at all, making the PR immune to that churn.
Nothing else changes: rag-hydration.ts, rag.ts at 4543, the budget ratchet, the
codebase-index row and the X3 work-order entry all remain. The #86 row will be
recorded in a separate follow-up PR after this merges — the same pattern used
for #1454 via #1461.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGEBHp4Seoh1jK1vGTNtYS
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
main landed its own #133 fix, which strips the Prettier column padding from
the issues ledger. That reformats every row, so the whole table conflicted
rather than just the rows anyone edited — the last and largest instance of
exactly the problem #133 exists to end.
Resolved by taking main's unpadded table wholesale and re-emitting this
branch's three captured rows in the same format (#149 adopt a consolidated
answer-home notice block, #150 answer mode ships no verify-before-use caveat,
#151 verify:pr-local exits 0 when its build step refuses to run). Taking one
side wholesale is safe here only because this branch's sole contribution to
the file is those three rows; main's own rows are unmodified.
check:outstanding-issues: 149 rows (59 open, 90 archived), unique ids,
next-id=152 above the highest, no merge driver, no ids deleted from base
00ddb22 — main's new #148 gate confirming nothing was dropped.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NPyFcMfn1jMmphr6AqiWBg
BigSimmo added a commit that referenced this pull request Jul 31, 2026
* issues: capture the unreadable-CI token, at-risk worktree work, and the unpushed hook fix
Three findings from the 2026-07-30 organisation session that were recorded
nowhere durable:
- #149 the session GitHub PAT lacks Checks: Read, so no agent can confirm a PR
is green. The endpoint that does work returns an empty result rather than an
error, so it reads like an absence of checks rather than an absence of
permission.
- #150 four worktrees on already-merged branches hold uncommitted work that
exists in no branch and no PR, the largest being +395/-200 across 19 files
including CI config.
- #151 the pre-commit fail-open for #143 lives only on a never-pushed local
branch, which is also 17 behind main and conflicts on the file whose count
sentence main's new docs:update generator now owns.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(ledger): record the session-followup capture review for PR #1490
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(ledger): record #143/#151/#149 reconciliation for PR #1490
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
* docs(ledger): supersede PR #1490 reconciliation after remote sync
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
* issues: record the worktree snapshots and redirect #151 to PR #1494#150 — the four at-risk worktrees were snapshotted onto their own already-merged
branches (748ef018f, 5dbd9f965, b7eae51a4, d949859c3), so the work survives a
worktree reclaim. All four are clean now. None is pushed or reviewed; the next
action is per-snapshot promote-or-reset.
#151 — the never-pushed branch is superseded rather than salvageable: its script
and hook reached main by other routes, so the fail-open guard was applied to
main's committed hook in PR #1494 instead.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs: remove credential metadata and correct audit dates
* docs: consolidate session follow-up findings
* docs: record consolidated follow-up review
* issues: record that #101 hydration shipped
PR #1463 merged as dba7356, so #86's "Next X3 unit — rag-hydration.ts" is
now stale. The row records the extraction as shipped and keeps the corrected
boundary: hydration re-homed only two of prepareCoverageGateResults's five
rag.ts-only dependencies, so it did not unblock that function — exactly as the
Codex review on PR #1461 predicted.
This row was deliberately dropped from #1463 itself (commit 6290d02) after
docs/outstanding-issues.md conflicted on five consecutive main syncs. Recording
it separately here is the same pattern used for #1454 via #1461.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGEBHp4Seoh1jK1vGTNtYS
* docs(ledger): record the landed X3 hydration review
Appended with npm run ledger:append (never hand-written), keyed to the squash
commit dba7356 so ledger:lookup can resolve it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGEBHp4Seoh1jK1vGTNtYS
* docs: fix the #101 mislabel and key the ledger row to a resolvable ref
Both defects were raised by Codex on PR #1495 and both are real; verified
against the files before accepting.
1. #101 is NOT this extraction. docs/outstanding-issues.md:138 shows #101 is
"Canary-gated retrieval parallelisation candidates" (P3, rec) — a separate,
still-open recommendation gated on a live canary pair. Calling the hydration
extraction "#101" marked that unrelated work as shipped and could have caused
the live-evaluation work to be skipped. The label came from the original task
brief and was propagated without checking it against the ledger. Both the
#86 row and the X3 work-order entry now identify the change as the X3
hydration unit (PR #1463) instead. #101's own row is untouched and still open.
2. The ledger row did not resolve. `npm run ledger:lookup --
dba7356` returned NOT REVIEWED, because the
ref cell held only the slash-form branch token and that branch no longer
resolves locally, so the throttling record could not prevent a repeat review.
Appended a superseding record keyed to the landed SHA; the same lookup now
returns ALREADY REVIEWED. The original row is retained, per the ledger's
append-only rule.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GGEBHp4Seoh1jK1vGTNtYS
* docs: record consolidated PR reviews
* docs: record ingestion recovery review
* docs(visual): document the platform-scoped baseline layout and how to seed it
`playwright.visual.config.ts` records snapshots under
`__screenshots__/{platform}/`, so a baseline taken on Windows lands in `win32/`
and is never consulted by the `ubuntu-24.04` CI job, which reads `linux/`.
Nothing said so, and committing `win32/` images looks like protection while
providing none.
Records the constraint, names the CI artifact as the supported recorder for
`linux/` baselines, and notes that comparison stays advisory until the jobs come
off `continue-on-error`. Also creates the tracked directory `.gitignore` already
claims exists, which sets `ui_changed=true` (`scripts/ci-change-scope.mjs`) so
the visual job can run and produce that first artifact.
No baselines are added here — they cannot be produced on this platform.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs: correct visual baseline adoption steps
* docs: record visual baseline guidance review
* fix(ui): repair mockup accent token references
* docs: record token-reference repair review
* docs: archive advisory UI scoping task
* docs: record advisory UI closure review
* issues: archive #151 after #1494 and mark #143 fully resolved
PR #1494 landed the fail-open guard on main, so close the open salvage
row and update the #143 archive from PARTIAL to resolved across #1442
and #1494. Also carries the merge of origin/main that cleared the
GitHub DIRTY mergeability state.
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
* docs(ledger): record PR #1490 main-sync and #151 closeout
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
* docs(ledger): record #1496 id-collision renumber for PR #1490
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
* issues: record the withdrawn live-region finding as #151 so it is not re-filed
Archive-only row. There is no defect and no work to do — the row exists purely
as a guard rail against repeating a misreading that already happened once.
search-results-header-band.tsx sets aria-live={faulted ? "off" : "polite"} on
its count/status span, which reads like a silenced failure announcement. It is
not: the band mounts a separate fault panel with role="alert" carrying the
failure title, body and Retry, and the mute is deliberate so the two do not both
speak. The reasoning is in a comment directly above the attribute, and
tests/search-results-header-band.dom.test.tsx pins it with singular role queries
that throw on duplicates.
During session 2026-07-30 (PR #1481) this was filed as a real P2 defect on the
strength of the attribute alone, and the proposed fix — escalating the count span
to role="alert"/aria-live="assertive" — would have produced a duplicate
announcement and a red test, making it worse than no change. Codex caught it.
An earlier withdrawal row was then lost to the squash that merged #1481, which
is the row-deletion shape #148 now guards against.
Also records that the mockup's escalation is correct in the mockup and must not
be ported: search-refine-adaptive-mockups.tsx has no fault panel, so there the
count span is the only announcement channel.
#148 needed no work — the merge-base deletion check landed on main
independently, and its output now reports the base it compared against.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JdPa3mHCX5ZQZZvU5GHU3r
* docs(rag): record refuted lexical probe collapse (#98)
* issues: capture the residual id-allocation hazard as #151#133 is resolved: #1444 removed merge=union and #1479 excluded the ledger from
Prettier, which together fixed conflict frequency. Neither changes id
allocation, which is still read-modify-write against the next-id marker, so
concurrent branches still claim the same number.
Measured on PR #1451: one row was renumbered #135 -> #141 -> #145 -> #147 ->
#149 across four sync cycles. The sharper finding is that GitHub's Update-branch
button resolved one such collision into duplicate #141 rows with the marker left
below main's highest id — git reported success and only
check:outstanding-issues caught it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(issues): attribute the mobile CLS breach — a 128px reserve round trip
#147 asked which elements shift. Driving Chromium against the same
offline production build with a PerformanceObserver on layout-shift
(Lighthouse mobile emulation, reading entry.sources[].node) gives one
dominant cause on all four breaching routes: the entire main content
region moves down 128px and straight back up 128px within 15-60ms. Both
moves score, so it is pure cost with zero net movement — 100% of
/documents/search's 0.220 and about 75% of /dsm's.
The shifting element is the max-sm:pt-[var(--phone-overlay-chrome-h)]
wrapper around <main>. A MutationObserver timeline on the root style
attribute pins the mechanism rather than inferring it: the property goes
CSS seed -> 200px -> 72px, and the 200px is written when the header
stack ALREADY measures 72px (t=1552ms reserve=200px stack=72, corrected
at t=1612ms). usePhoneOverlayChromeReserve reads stack.offsetHeight
while the stack is transiently tall, publishes a value that is stale by
the time it lands, and its ResizeObserver then corrects it.
The CSS seed at globals.css:375 is correct for the settled stack, which
corrects the mechanism recorded on the now-archived #130 — that framed
the defect as the seed under-reserving by 0-8px. Measured, the driver is
a 128px transient over-reserve written by the hook, not the seed. / is
the control: it never writes the property and is the one clean route.
Variance is stated rather than smoothed: /dsm measured 0.363 and 0.219
across two runs, and this harness has no network throttling so /forms
and /therapy-compass run high locally. Only /dsm, /documents/search and
/ reproduced the live dispatch exactly.
Also recorded: attaching a MutationObserver to document.documentElement
inside a Playwright addInitScript throws before the document element
exists, silently killing the CLS observer and reporting a uniform
CLS=0.000 — a false clean bill that voided one run of this harness.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01361jh3eYVjJCzXWjAhdZiF
* docs(ledger): record the #151 capture review for PR #1506
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(review): clarify snapshot branch state
* docs(ledger): record PR #1490 main sync after snapshot wording
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
* docs: archive rendered style contract task
* docs: record style contract closure review
* docs: record synced style contract review
* docs: record post-121 style closure review
* docs: normalize style review ledger after sync
* docs: record post-1490 style closure review
* docs: record consolidated PR 1490 review
* docs: record replacement consolidation review
* docs: record reconciled consolidation review
* docs: record post-1511 consolidation review
* docs: normalize PR 1510 ledger after main sync
* docs: record PR 1510 post-sync review
* docs: correct false #98 canary evidence and NOTES triage
Remove the incorrect probe-collapse canary attribution from #98 and
point the unread --med-accent-soft note at #157 without breaking the
seven-token TOKENS_MISSING accounting.
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
* docs(ledger): record PR #1510 evidence-correction review
Supersede the prior approve-with-no-findings row after correcting the
false #98 canary attribution and NOTES triage drift.
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
* docs: keep concurrency note inside issue table
* docs: record post-1513 consolidation review
* docs: address CodeRabbit notes on PR #1510
Fix the computed-value-time wording in design-sync notes, give #33 a
unique recommended-queue order, and drop the duplicated #98 Done block.
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
* docs(ledger): record PR #1510 CodeRabbit fix review
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
BigSimmo pushed a commit that referenced this pull request Aug 12, 2026
docs/outstanding-issues.md #170 conflicted because both branches rewrote that
row's Detail cell — the file deliberately carries no merge driver (union was
tried and removed, #133) so overlapping edits fail loudly rather than
concatenate. Neither side was a superset: main uniquely explained the closed
one-of-N/many-of-N defect and the "unlike #1847" stop nuance, this branch
uniquely carried the formulation facet work. Resolved by taking main's file and
re-applying a combined row through npm run issues:update rather than
hand-editing or taking one side wholesale.
result-filter-control.tsx auto-merged cleanly and both changes survive: PR
#1857's two aria-label fixes (the "All8" concatenation) and this branch's
exported ResultFilterFacetChips plus the narrowed builder return type.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011btGFwWKYFWDs5McQkqz9J
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@BigSimmo