Skip to content

Clinical White / Aegean Graphite theme + Geist Mono codes - #112

Merged
BigSimmo merged 1 commit into
mainfrom
claude/lucid-hypatia-dfe6fd
Jul 1, 2026
Merged

Clinical White / Aegean Graphite theme + Geist Mono codes#112
BigSimmo merged 1 commit into
mainfrom
claude/lucid-hypatia-dfe6fd

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Summary

Permanent Clinical White / Aegean Graphite direction: role-split colour system, true-white canvas, de-glassed light mode, and Geist Mono for clinical code/ID tokens.

  • Graphite --command = primary actions (New chat, CTAs, FAB)
  • Aegean --clinical-accent = clinical identity (selected · evidence · send · focus)
  • Green --success = status only
  • De-blued neutral ramp → true-neutral gray; content canvas #FFFFFF + --surface-chrome
  • Light mode de-glassed (flat + hairline + one shadow; glass kept for overlays); dark mode keeps black polish
  • font-mono bound to Geist Mono, applied to citation indices, page/chunk coordinates, index version; tabular metadata

Clinical governance preflight

Presentation-only. No changes to ingestion, answer generation, retrieval/ranking, source rendering logic, document access, privacy, production env, or clinical output. Only colour tokens, materials, and typography classes changed.

Verification

  • npm run typecheck passes; git diff --check clean
  • Dev server serves 200, 0 console errors; light/dark desktop + mobile screenshots confirm the direction
  • Contrast: Aegean-on-white ≈5.8:1, command ≈16:1, semantics ≥4.5:1
  • Live DOM probe confirms font-mono → Geist Mono
  • Not run this pass: verify:ui / verify:release (full Playwright + build); ESLint (binary absent in worktree)

Docs updated: docs/redesign/ design-direction, decision-log D11, changelog.

🤖 Generated with Claude Code

Split the overloaded --primary accent into role tokens: graphite --command
for primary actions, Aegean --clinical-accent for clinical identity
(selected/evidence/send/focus), and green --success for status only.
De-blue the neutral ramp to true-neutral gray, set a true-white content
canvas with --surface-chrome for rails/header, and de-glass light-mode
materials (flat + hairline + one shadow; glass kept for overlays). Dark
mode keeps its black polish with a brightened Aegean accent.

Bind Tailwind font-mono to the loaded Geist Mono and apply it to clinical
code/ID tokens (citation indices, page/chunk coordinates, index version);
metadata rows use tabular figures. Fix stale light theme-color to #ffffff.

Presentation-only: no changes to ingestion, answer generation, retrieval/
ranking, document access, privacy, production env, or clinical output logic.

Updated docs/redesign (design-direction, decision-log D11, changelog).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@BigSimmo
BigSimmo merged commit 69e0402 into main Jul 1, 2026
4 checks passed
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
…dered

Codex is right that the walker reports adoption for a route that keeps
its results import but stops rendering it; reducing services/page.tsx to
<div /> with imports retained keeps the gate green.

Recorded rather than fixed here, for two reasons. It is pre-existing —
the previous two-hop walker had no render check either — and it is not a
live risk: the same edit fails npm run lint with five no-unused-vars
warnings under --max-warnings 0, so the composite static gate catches
exactly the constructed scenario. The genuinely uncaught shape needs an
import referenced somewhere non-rendering, which is deliberate rather
than a slip.

Tightening it properly means tracking which bindings appear in JSX
element position or as the default export, since a re-export mounts with
no JSX at all. That is a third expansion of this walker in one PR, and
the second one introduced a worse hole than it closed, so it belongs in
its own change with its own review.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
…gaps

#112 (P2): verify:phone-chrome exited 0 while its own output ended
"13 failed". All 13 failed at browser launch, so zero assertions ran and the
gate still returned success -- the green-when-broken case AGENTS.md warns
about, in the gate that is meant to be the proof.

#113 (P3): the container's Playwright browsers are build 1194 while the
repo's client resolves 1234, so browser gates cannot run in a remote session
without hand-patching. Worked around in-session with symlinks under
/opt/pw-browsers; nothing committed, and it vanishes with the session.

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
Whole-table conflict in docs/outstanding-issues.md — main advanced 44
commits and gained rows while this PR sat open. Resolved by rebuilding
from main's current file and re-applying this branch's three changes,
not by taking either side: settling a whole-table conflict by picking a
side is the row-loss failure ledger #112 exists to make loud.

Renumbered the new row #117 -> #125. When this branch opened it, the
marker was 117; main's marker is now 125 and #117..#119 were reserved by
other sessions in the meantime, so keeping #117 would have collided with
a row someone else is about to add under that number. Ids are never
reused — renumber the incoming row above the marker and bump it.

Audited row-by-row against origin/main rather than eyeballed:

  main rows: 119   resolved rows: 120
  LOST from main: (none)
  ADDED vs main:  #125
  MOVED table:    #113 open->archive, #114 open->archive
  duplicates:     (none)

check:outstanding-issues: 120 rows (58 open, 62 archived), unique ids,
next-id=126 above the highest. verify:cheap exit 0, Tests 4493 passed |
4 skipped. format:check clean. `c2edda18` still absent from the file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FvU8z73P6TXUXoYBqN5K1P
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
PR #1420 landed its own `#125` while this branch was allocating one —
exactly the unprotected read-modify-write race archived as #112. Both
rows are kept: theirs holds #125, the phone-scroll CI capture moves to
#126, and the marker advances to 127.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XrPbbfU9yWuEjEVypCr4ZQ
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
PR #1418 landed its own `#126` (quarterly ledger rotation) on main while
this branch was carrying one — the same unprotected read-modify-write
race archived as #112, hit for the second time in an hour. Main holds
first claim, so its row keeps #126, the phone-scroll CI capture moves to
#127, and the marker advances to 128. Both rows are kept.

check:outstanding-issues: 125 rows (62 open, 63 archived), unique ids,
next-id=128 above the highest.
check:branch-review-ledger: 90 live + 1206 archived, ledger merge active.

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
* process: cut future PR conflict churn and silent CI gaps

Add outstanding-issues ID/marker/union guards (#112), a read-only
pull_request_target mergeability signal for dirty heads (#116), and an
anti-conflict CI-speed operating procedure that prefers bundling and
format-before-push without weakening required gates or touching active PRs.

Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>

* docs(ledger): record PR #1416 merge-readiness as not ready

Main advanced with #1410 overlapping the outstanding-issues gate; merge-tree
is conflicting. Unique value remains the anti-conflict playbook, #116 signal,
and merge=union.

Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>

* style(issues): format outstanding-issues after main sync

Prettier realigns the archive table after the #116 close and #112 note update.

Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>

* docs(ledger): supersede #1416 merge-readiness as ready

Record the post-sync review: merge-tree clean, unique #116/process value kept,
duplicate #112 checker dropped in favor of #1410.

Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>

* docs(ledger): pin #1416 READY review to final tip SHA

Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>

* fix(test): shrink zip-bomb fixture to stop CI coverage timeout

Unit coverage failed because reject-high-compression-ratio allocated and
deflated 24MB of zeros under the 30s Vitest timeout. 1MB still exceeds the
150:1 admission ratio (~480:1) without the CI flake.

Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>

* fix: refresh mergeability after base advances

* fix: preserve ledger rotations during merges

* fix: resolve issue ledger merge collision

---------

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 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 pushed a commit that referenced this pull request Jul 30, 2026
GitHub reported this PR dirty, but `git merge-tree --write-tree origin/main HEAD`
exited 0: clean. That is the anti-churn case, not a content fight — GitHub's
server-side merge does not read custom merge drivers, which is already recorded
as ledger #127. So the documented remedy applied: merge locally and push.

`git merge origin/main` then produced a CORRUPT tree and it must not be pushed
as-is. `.gitattributes` sets `merge=union` for this file (added by #1418), and
union keeps both sides of every differing line. Prettier pads these tables to
the widest cell, so a single row's edit re-pads every other row — both sides'
copies of all 128 rows are textually distinct, and union kept both. Result:
every row duplicated, both table headers duplicated, 133 insertions.

`npm run check:outstanding-issues` caught it, failing with 128 duplicate-id
errors, both separator rows reported as non-canonical ids, and all five archived
rows "in BOTH the open and archive tables". The gate #112 added is what stopped
a silently doubled ledger from reaching the PR — it failed closed exactly as
designed.

This is the outcome ledger #127 predicted: it records that `merge=union` is the
wrong fix for this file, with evidence, "so nobody re-proposes it". #1418
enabled it anyway. Union is safe for append-only single-line records like
docs/branch-review-ledger.md; it is actively destructive on a width-padded
table, because padding turns every unrelated row into a conflicting line.

Recovered without a destructive reset: the merge commit and both parents are
kept, only its tree was rebuilt — take origin/main's ledger, re-apply the
five-row archive move, reformat. Proven lossless against origin/main rather
than assumed:

  origin/main : 63 open + 65 archived = 128, 0 duplicates
  rebuilt     : 58 open + 70 archived = 128, 0 duplicates
  IDs lost from main: NONE      IDs invented: NONE
  open == main's open minus the five moved: True

Verified: npm run verify:cheap -> EXIT=0; "Test Files 434 passed (434)";
"Tests 4563 passed | 4 skipped (4567)"; "Outstanding-issues guard passed: 128
rows (58 open, 70 archived), unique ids, next-id=131 above the highest, union
merge active". npx prettier --check . -> "All matched files use Prettier code
style!"

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011YdPS2KhKqz2buzsUgmX3c
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
Resolves the conflict that was silently stopping ALL CI on PR #1427: with a real
conflict GitHub cannot build refs/pull/1427/merge, so every `pull_request`
workflow was skipped with no failing check while `pull_request_target` ran. That
is issue #116, and main's new `PR mergeability` check named it.

Conflict resolutions:

- `.github/workflows/ci.yml` — keep BOTH. Main split the UI gate into
  `ui-critical-fast` (@critical fail-fast) which `ui-critical` now `needs:`; the
  shard matrix lands on `ui-critical` only, preserving main's `needs:`/`if:`
  verbatim. `ui-critical-fast` stays unsharded: it is already the small subset,
  so sharding it would spend runners without shortening the critical path.
- `playwright.visual.config.ts` — take main. It already sets
  `fullyParallel: false` / `workers: 1`, so this branch's version of that change
  was redundant and is dropped entirely.
- `docs/outstanding-issues.md` — main allocated 125/126/127 concurrently, the
  exact #112 id race. This branch's five rows renumber to #128-#132, marker to
  133, and the cold-cache cross-reference follows.
- `docs/process-hardening.md` — keep both sections; the CI-timing note now
  records that its numbers predate `ui-critical-fast`.
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
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.
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 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 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 pushed a commit that referenced this pull request Aug 9, 2026
Resolves the duplicate #286 that made the PR un-mergeable. Main's
in-page-nav series claims #286-#288; this branch independently created
its own #286 for the authorizationHeader casing trap. Kept both sides and
renumbered the branch's row to #289, bumping issues:next-id to 290.

The auto-merge silently dropped the branch's #286 detail row rather than
conflicting on it -- only the recommended-queue hunk raised a marker. That
row is restored as #289. This is the silent row-loss mode archive row #112
describes: the guard catches duplicate ids but not a vanished one.

Also addresses review findings on the handover brief:

- Require the Clinical Governance Preflight for Phase 3 regardless of what
  scripts/pr-policy.mjs classifies. AGENTS.md:257 keys the requirement to
  behaviour -- source rendering and document access -- and Phase 3 changes
  both. The classifier not matching src/components/** is the PR #1489 gap
  recorded at pr-policy.mjs:62, not an exemption.
- Resolve the scope contradiction: the brief claimed everything stays in
  src/components/document-viewer/** while Task 3 authorised wiring
  src/app/api/images/signed-urls/route.ts, which is clinical-risk. That is
  now an explicit, discouraged scope exception.
- Correct the signed-URL warning. Both identity bugs are already fixed on
  main (authorizationIdentity() helper, identity in the dedupe key, cache
  write outside the shared promise, tests/auth-signed-url-cache.dom.test.tsx).
  The brief now says so and requires that coverage stay green, rather than
  reading as an open disclosure with a "consider" remedy.
- Drop a literal NUL byte that had landed in the prose, and remove the
  trailing-space code span (MD038).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ER2xPFzPzoS8fAxkgHC8yo
Sign up for free to 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