Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
a63acb5
test(phone-scroll): prove the drag delivered before asserting the chr…
claude Jul 30, 2026
5efa73a
ci: shard Production UI across three runners
claude Jul 30, 2026
bcc5ba3
ci: bound the codex auto-resolve jobs and serialise the visual config
claude Jul 30, 2026
da1a44b
chore(gates): pin the documented gate count to the real chain
claude Jul 30, 2026
db8209b
docs(issues): capture the CI review's deferred findings
claude Jul 30, 2026
85271d1
docs(ledger): record the ci-testing-review pass at this HEAD
claude Jul 30, 2026
0021c2a
Merge origin/main into claude/ci-testing-review-2l8klp
claude Jul 30, 2026
aa26535
ci: re-measure the shard split on the merged tree and refresh stale g…
claude Jul 30, 2026
124f0f1
Merge remote-tracking branch 'origin/main' into claude/ci-testing-rev…
claude Jul 30, 2026
79dd28f
docs(issues): rebuild the ledger after a union-merge duplication
claude Jul 30, 2026
b9de34d
Merge remote-tracking branch 'origin/main' into claude/ci-testing-rev…
claude Jul 30, 2026
08c2195
ci: record the measured shard result, correcting the predicted one
claude Jul 30, 2026
76f80f3
Merge remote-tracking branch 'origin/main' into claude/ci-testing-rev…
claude Jul 30, 2026
86c5af9
docs(issues): renumber this branch's rows above main's concurrent all…
claude Jul 30, 2026
2e804d6
Merge remote-tracking branch 'origin/main' into claude/ci-testing-rev…
claude Jul 30, 2026
17c8cb9
docs(issues): rebuild against main's current id allocation
claude Jul 30, 2026
2e2160b
Merge remote-tracking branch 'origin/main' into codex/review-pr1427
BigSimmo Jul 30, 2026
9e660ae
docs: record PR 1427 review
BigSimmo Jul 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/skills/gates/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Check these before believing any result.
for exactly this reason — if installed packages do not match `package-lock.json`, treat any test,
lint, or typecheck result as void until `npm ci` has run. Its own failure message says as much.
- **`verify:cheap` stops at the first failing check.** Everything after that point never ran. Do not
describe the change as broadly verified when the gate died at check 2 of 26.
describe the change as broadly verified when the gate died at check 2 of 30.
- **`format:check` is required in CI but is not part of `verify:cheap`.** A locally green
`verify:cheap` can still fail CI on formatting. Run `npx prettier --write <changed files>` before
pushing — scoped to your files, never `prettier --write .`, which sweeps the whole tree.
Expand Down
5 changes: 5 additions & 0 deletions .github/actions/setup-ui-e2e/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ runs:
with:
path: ~/.cache/ms-playwright
key: playwright-chromium-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
# Without a prefix fallback, any lockfile bump forces a cold browser download in
# every UI job at once. A stale archive is harmless: `playwright install` below
# still fetches whatever the new version needs.
restore-keys: |
playwright-chromium-${{ runner.os }}-

# The browser archive is cached, but apt libraries are runner-local and must be
# installed even on a browser-cache hit.
Expand Down
57 changes: 55 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,9 @@ jobs:
# Fail-fast @critical Chromium smoke on PRs/merge_group before the full
# production suite. Skipped on main/schedule — those run the full job only.
# Keeps merge safety: pr-required still demands the full Production UI job.
#
# Deliberately NOT sharded: it is already the small subset, and sharding it
# would spend runners without shortening the critical path.
ui-critical-fast:
name: Production UI critical
needs: changes
Expand Down Expand Up @@ -456,6 +459,19 @@ jobs:
playwright-report/
if-no-files-found: ignore

# Sharded across runners, NOT across workers. Playwright stays `workers: 1` /
# `fullyParallel: false` / `retries: 0` inside each shard, so determinism is
# unchanged and per-runner load goes DOWN rather than up — which matters because
# the duplicate-page-root strict-mode failures (#093) are load-dependent.
#
# Measured 2026-07-30 (before `ui-critical-fast` landed): this job ran 15m26 of
# an 18m36 run — 83% of wall clock — while every other job finished by minute 4.
# Playwright itself reported `339 passed (13.5m)`; the balance is the isolated
# production build.
#
# Branch protection requires only the `pr-required` aggregate, and `needs` on a
# matrix job yields the roll-up of all shards, so the aggregate below needs no
# change and the per-shard job names are free to differ.
ui-critical:
name: Production UI
needs: [changes, ui-critical-fast]
Expand All @@ -468,6 +484,37 @@ jobs:
(needs.ui-critical-fast.result == 'success' || needs.ui-critical-fast.result == 'skipped')
runs-on: ubuntu-24.04
timeout-minutes: 45
strategy:
# One shard's failure must not cancel the others: a cancelled sibling would
# report as `cancelled` and re-create exactly the ambiguity #095 removed.
fail-fast: false
matrix:
# THREE, and the count is measured rather than chosen. `fullyParallel: false`
# makes a spec file the indivisible unit, so shard sizes are lumpy and more
# shards is not monotonically faster. Re-measured 2026-07-30 against this
# merged tree — 342 non-quarantine/non-mockup chromium tests
# (`--list --shard=i/N`):
# N=3 -> 121/111/110 largest 121 (35%)
# N=4 -> 121/106/98/17 largest 121 (35%) — same bound, one more runner
# Earlier on a 340-test tree, N=5 -> 121/106/0/96/17 and N=8 gave two empty
# shards. N=4 buys nothing over N=3 because one 121-test spec group bounds
# both, and any N with an empty shard would go RED: `test:e2e:pr`
# deliberately omits `--pass-with-no-tests` (only the advisory lane has it).
# Re-measure before changing this number, and keep every shard non-empty:
# npm run ensure
# PLAYWRIGHT_BASE_URL=<printed> npx playwright test --project=chromium \
# --grep-invert "@quarantine|@mockup" --shard=i/N --list
#
# MEASURED on the first real sharded run (CI 30530618838, 2026-07-30):
# shard 1 -> 121 tests, 9m36
# shard 2 -> 111 tests, 6m54
# shard 3 -> 110 tests, 6m20
# Per-test cost is NOT uniform — 111 tests took 6m54 while 121 took 9m36 —
# so counting tests UNDERSTATES the largest shard. A count-balanced split is
# the best `--shard` can do; balancing by duration would mean splitting the
# slow spec files themselves. Predicting from test count alone was wrong by
# ~40% here, so trust a measured run over the arithmetic.
shard: [1, 2, 3]
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand All @@ -478,7 +525,7 @@ jobs:
uses: ./.github/actions/setup-ui-e2e

- name: Chromium production journeys
run: npm run test:e2e:pr
run: npm run test:e2e:pr -- --shard=${{ matrix.shard }}/3

- name: Classify exact failed test identities
if: failure()
Expand All @@ -488,7 +535,9 @@ jobs:
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: production-ui-diagnostics-${{ github.run_id }}
# Shard-scoped: upload-artifact v7 runs with `overwrite: false`, so a
# shared name would make the second failing shard fail on upload.
name: production-ui-diagnostics-${{ github.run_id }}-shard${{ matrix.shard }}
path: |
test-results/
playwright-report/
Expand Down Expand Up @@ -877,6 +926,10 @@ jobs:
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
# Prefix fallback so a lockfile bump does not force a cold download of all
# four browsers; `playwright install` below still fetches any missing version.
restore-keys: |
playwright-${{ runner.os }}-

- name: Install Playwright browsers
run: |
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/codex-autofix-review-comments.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ jobs:
request-codex-autoresolve:
name: Request Codex auto-resolve
runs-on: ubuntu-24.04
# Every other workflow in this repo bounds its jobs; without this the GitHub
# default of 360 minutes applies to a job that only reads metadata and posts a
# comment.
timeout-minutes: 10
# Only run after Codex submits a completed review, never on the first inline
# comment mid-review. Approvals/dismissals are handled below (no findings).
if: >
Expand Down Expand Up @@ -293,6 +297,7 @@ jobs:
resolve-codex-thread:
name: Resolve Codex review thread
runs-on: ubuntu-24.04
timeout-minutes: 10
# Marker-driven thread closure only. This is the narrow job that carries
# pull-requests: write, and it acts solely on trusted disposition replies.
if: >
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ Verification pyramid — run the **smallest gate that covers the change**, then
| Gate | What it is |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `npm run test:focused -- --files <paths>` | Source-only iteration. Fails closed for deleted files and test infrastructure — then run `npm run test`. |
| `npm run verify:cheap` | The broad local gate: 24 static/consistency gates + `lint` + `typecheck` + full offline unit suite |
| `npm run verify:cheap` | The broad local gate: 27 static/consistency gates + `lint` + `typecheck` + full offline unit suite |
| `npm run verify:pr-local` | Closest local mirror of the PR gate; adds format and conditional build / client-bundle scan / RAG fixture validation. `-- --dry-run --files <paths>` shows selection without running. |
| `npm run verify:ui` | Chromium production journeys. Run `npm run ensure` first. |
| `npm run verify:phone-chrome` | Phone-chrome changes; selects affected owners/journeys before escalating to `verify:ui` |
Expand Down
Loading
Loading