Skip to content

test: commit reviewed visual-regression baselines - #2753

Merged
Chris0Jeky merged 7 commits into
mainfrom
issue-1363/baseline-census
Sep 6, 2026
Merged

test: commit reviewed visual-regression baselines#2753
Chris0Jeky merged 7 commits into
mainfrom
issue-1363/baseline-census

Conversation

@Chris0Jeky

Copy link
Copy Markdown
Owner

Summary\n- add the reviewed 22-image Chromium visual baseline set under the configured snapshot path\n- stabilize visual captures by hiding per-run shell identity/presence and the session timeout warning\n- correct settings profile masking and document exact-head baseline bootstrap/review/negative-control rules\n\n## Verification\n-

px playwright test --config playwright.visual.config.ts --workers=1 --update-snapshots --reporter=line (22 passed)\n-
px playwright test --config playwright.visual.config.ts --workers=1 --reporter=line (22 passed)\n- deliberate temporary 10px fixture mutation: 1 failed, 7,200 differing pixels, 3 diff artifacts, snapshot restored\n-
pm run typecheck\n-
pm run build\n-
px eslint tests/visual/visual-test-helpers.ts tests/visual/settings-view.visual.spec.ts tests/visual/archive-view.visual.spec.ts\n-
ode scripts/check-docs-governance.mjs\n-
ode scripts/check-golden-principles.mjs\n- git diff --check\n\n## Notes\n- resolved the supplied stale locator to the live ests/visual/*.visual.spec.ts suite and configured snapshot template\n- screenshots were reviewed for layout and per-run value leakage; dynamic identity and profile values are excluded/masked\n- hosted checks and independent review remain pending\n\nRefs #1363

@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.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@Chris0Jeky

Copy link
Copy Markdown
Owner Author

Fresh-context review record (coordinator, 2026-09-06; read-only Opus 5 reviewer; route: the standing D-12 rule for Codex-session PRs).

VERDICT: FIX-FIRST, parked pending one CI fact. HIGH-1 — the 22 baselines were captured with local --update-snapshots on the author's Windows box, while docs/testing/VISUAL_REGRESSION_POLICY.md:57 says only ubuntu-generated baselines may be committed and :128 warns other-OS baselines fail CI on font rendering; the snapshot path template has no platform segment, so one PNG serves both OSes. If the Linux lane rejects them, merging converts a self-bootstrapping green lane into a permanently red one. The coordinator has added the visual label so the extended lane renders the exact head; that run decides this finding. HIGH-2 — the new TESTING_GUIDE block never states the ubuntu-only rule and tells an agent to run npm run test:visual:update locally, which on Windows would overwrite all 22 baselines in place with nothing to warn. MEDIUM-3 — the new [role="alert"][aria-live="assertive"] hide rule also matches ErrorBoundary.vue's fallback, so a crashed view would enshrine a near-blank baseline; scope it to SessionTimeoutWarning. MEDIUM-4 — the policy doc's Dynamic Content list omits the three new hidden selectors and the settings mask. LOWs: the config comment claims a platform segment that does not exist; the corrected settings mask matches five spans (two not per-run) while the comment says four; Last Updated not bumped; the negative control exercised 1 of 22 snapshots.

Disposition: if the labelled run is green, the coordinator fixes HIGH-2, MEDIUM-3 and MEDIUM-4 in-PR and merges; if red, the PR stays open for baselines regenerated from the CI visual-regression-baselines artifact per the policy's bootstrap procedure.

@Chris0Jeky Chris0Jeky added the testing Test coverage, harnesses, regression prevention, and verification pipeline work. label Sep 6, 2026
@Chris0Jeky

Copy link
Copy Markdown
Owner Author

Parked (coordinator, 2026-09-06). The testing-labelled run rendered the committed baselines on ubuntu-latest and Visual Regression failed (run 34031907948, job 101486249644), which confirms HIGH-1: baselines captured on Windows do not match the Linux renderer, exactly as docs/testing/VISUAL_REGRESSION_POLICY.md:128 warns. Not merged. To land this: remove the 22 PNGs, let the lane run once with no baselines (it runs --update-snapshots and uploads the visual-regression-baselines artifact), commit that artifact's PNGs per the policy's bootstrap procedure, and fold in HIGH-2 (the TESTING_GUIDE block must state the ubuntu-only rule and must not tell agents to run test:visual:update locally), MEDIUM-3 (scope the [role="alert"][aria-live="assertive"] hide rule to SessionTimeoutWarning) and MEDIUM-4 (the policy's Dynamic Content list). The advisory Smart CI / Required Gate red on this head is the shadow lane, not a required check.

…egenerates them

The 22 baselines on this branch were captured on Windows. The hosted lane runs
Chromium on ubuntu-latest, where font rasterisation differs, so every image
failed there; the run stopped at the config's CI maxFailures of 5 with 5 failed
and 2 passed, which means the diff artifact only ever covered 5 of the 22.

Removing the directory puts the reusable Visual Regression job back on its
bootstrap path: with no baselines present it runs --update-snapshots and uploads
the generated set as the visual-regression-baselines artifact. That Linux set is
then reviewed and committed on top of this commit, so the images this branch
finally lands are captured by the same platform that verifies them.

This commit is a deliberate intermediate state: with no baselines the suite
cannot detect a regression, so it must not be merged on its own.

Refs #1363
@Chris0Jeky
Chris0Jeky marked this pull request as draft September 6, 2026 18:11
@Chris0Jeky

Copy link
Copy Markdown
Owner Author

Re-capturing the baselines on Linux (2026-09-06)

Diagnosis of the parked state. The 22 baselines on this branch were captured on Windows; the hosted job runs Chromium on ubuntu-latest, where font rasterisation differs, so they cannot pass there. The last run (34031907948) reported 5 failed / 2 passed and stopped — playwright.visual.config.ts sets maxFailures: 5 under CI — so the visual-regression-diffs artifact only ever contained 5 of the 22 images. Patching those five from the artifact would just have exposed the next five.

Remedy in flight. 0dd2e9e7c removes tests/visual/__screenshots__/ entirely, which puts reusable-visual-regression.yml back on its own bootstrap path: with no baselines present it runs --update-snapshots and uploads the generated set as the visual-regression-baselines artifact. That Linux-captured set will be reviewed image by image and committed on top, so the images that finally land are captured by the same platform that verifies them.

The PR is in draft while this is in flight and must not be merged at 0dd2e9e7c: with no baselines the suite passes vacuously and detects nothing. It goes back to ready-for-review only once the reviewed Linux set is committed.

…ux-captured

The first Linux bootstrap of this branch's baselines came back with transient
success toasts burned into four of the 22 images: one on board-empty and on
starter-pack-modal-import, three on card-modal-edit, and an eight-toast stack
across board-populated's header and board-actions row.

Those toasts are raised by the specs' own seeding — one per created board,
column and card — and the toast store removes each after its own duration, so
how many are still on screen when Playwright captures is a function of how fast
the runner got there. Committing them would have made those four baselines flake
on runner speed rather than on any visual change.

hideDynamicContent already hid the session-timeout alert via
[role="alert"][aria-live="assertive"], but ToastContainer and
PaperToastContainer only set those attributes on *error* toasts, so success
toasts were never covered. Both skins tag every toast with data-toast-id, so
that is the selector used here. The stack is position: fixed and
pointer-events: none, so hiding it shifts no page layout, and because the rule
lives in the injected stylesheet rather than a one-shot DOM edit it also covers
toasts raised after the helper runs.

Also documents two things this branch learned the hard way:

- Baselines must come from the hosted Linux lane. Chromium font rasterisation
  differs enough between platforms that the Windows-captured set this branch
  started with failed on every image. The bootstrap-and-review procedure is now
  written down in the policy.
- The visual-regression-diffs artifact is not a repair source: maxFailures is 5
  under CI, so it only ever holds the first five failures.

Refs #1363
22 baselines, generated by the hosted Visual Regression job's own bootstrap path
at a391a95 (run 34052627422, artifact visual-regression-baselines) and
reviewed image by image before landing.

These replace the Windows-captured set this branch started with, which could
never have passed: the job runs Chromium on ubuntu-latest, and font
rasterisation differs enough that every image failed there.

Reviewed for layout and for per-run value leakage. Session identity, presence
and profile values are masked on settings-profile and board-toolbar; the
calendar renders April 2026 from the installed clock rather than the wall clock;
capture-modal-typed is correctly the typed *tab* in its default empty state, not
a composer with text in it. No timestamps, user ids, board ids or other
run-varying values survive in any image.

The toast leak that the first bootstrap exposed is gone: board-empty,
board-populated, card-modal-edit and starter-pack-modal-import are now captured
without the seeding toasts that had covered the board header, the board-actions
row and the card modal's date control.

Refs #1363
@Chris0Jeky

Copy link
Copy Markdown
Owner Author

Re-captured on Linux, reviewed, and committed (d01fc0ec1)

Three commits, in order:

  1. 0dd2e9e7c removed the Windows-captured __screenshots__/, putting the job on its bootstrap path.
  2. a391a95a9 fixed a defect that first bootstrap exposed (below).
  3. d01fc0ec1 commits the 22 reviewed Linux-captured baselines from run 34052627422.

The toast leak, found by looking at the images rather than at the exit code

The first Linux bootstrap succeeded, and its output was not committable. Four of the 22 images had transient success toasts burned into them: one each on board-empty and starter-pack-modal-import, three on card-modal-edit, and an eight-toast stack across board-populated's header and board-actions row.

Those toasts come from the specs' own seeding — one per created board, column and card — and the toast store removes each after its own duration. So how many are on screen at capture time is a function of how fast the runner got there. Committing them would have traded a platform mismatch for a runner-speed flake, which is a worse bug because it is intermittent.

hideDynamicContent already hid [role="alert"][aria-live="assertive"], but ToastContainer.vue and PaperToastContainer.vue set those attributes on error toasts only, so success toasts were never covered. Both skins tag every toast with data-toast-id, so that is now the selector. The stack is position: fixed and pointer-events: none, so hiding it shifts no layout, and because the rule lives in the injected stylesheet it also covers toasts raised after the helper runs.

Review of the committed set

All 22 read individually for layout and per-run value leakage:

  • Masking holds. settings-profile masks username, email, user id, role and ops access; board-toolbar masks its per-run identity value.
  • No wall-clock leakage. calendar-default renders April 2026 from the installed clock, not the run date.
  • capture-modal-typed is correct as-is — it is the typed tab in its default empty state (the spec is capture modal typed mode default), not a composer that failed to receive text. I checked the spec rather than assuming from the filename.
  • No timestamps, user ids, board ids or other run-varying values survive anywhere.
  • card-modal-edit now shows the date-picker control the toast stack had been covering.

Also documented

docs/testing/VISUAL_REGRESSION_POLICY.md now records the three masking rules that were in the helper but not the policy (identity/presence, the session-timeout alert, toasts), that baselines must come from the hosted Linux lane, and the bootstrap-and-review procedure. It also records why the visual-regression-diffs artifact is not a repair source: maxFailures: 5 under CI means it only ever holds the first five failures, which is why the original 5-of-22 diff artifact looked like a small problem.

What this next run proves that the last one did not

Baselines are now present, so the job takes its verify path instead of --update-snapshots. A green Visual Regression here is the round-trip proof — Linux-captured images re-verified against a fresh Linux capture — which no previous run on this branch has ever produced.

Back to ready-for-review once that lands.

Not verified: the suite has never run twice against the same committed set, so cross-run stability beyond this single verification is unproven. If a toast-like transient remains in any image, it would surface as an intermittent failure rather than immediately.

@Chris0Jeky

Copy link
Copy Markdown
Owner Author

Green, and the one red leg was investigated rather than waved through

Visual Regression / Visual Regression passed on the committed set (run 34053635176). That is the round-trip this branch had never achieved: baselines are present, so the job took its verify path rather than --update-snapshots, and Linux-captured images were re-verified against a fresh Linux capture.

The webkit failure

E2E Cross-Browser Matrix / E2E (webkit) first came back red on tests/e2e/cross-browser.spec.ts:46 with Error: page.goto: WebKit encountered an internal error — a browser-process crash on navigation, not a product assertion (1 failed / 4 passed).

I did not treat it as flaky on sight. The branch's own history decides it:

head what the commit changed webkit
0dd2e9e7c deleted PNG baseline files only failure
a391a95a9 one CSS rule in tests/visual/visual-test-helpers.ts + two docs success
d01fc0ec1 re-added PNG baseline files only failure

None of those touches cross-browser.spec.ts, any frontend or backend source, or anything that suite imports — visual-test-helpers.ts is imported only by tests/visual/**. The outcome flipped fail → pass → fail with no causal change on that path.

Then the conclusive check: re-running the failed job against the identical tree (gh run rerun 34053635176 --failed) passed. Same SHA, opposite result.

So it is nondeterminism in the webkit lane, not a defect this PR introduces. Filed as #2763 with the full evidence, deliberately not fixed here — a blanket Playwright retry would hide real webkit regressions, and the label gate makes the true rate unmeasured. Worth knowing: the job only runs on testing-labelled PRs, so recent CI Extended "success" rows elsewhere are skips, not passes.

Marking ready for review.

@Chris0Jeky
Chris0Jeky marked this pull request as ready for review September 6, 2026 19:34
@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.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

…umented

Review round 1 on #2753. The fresh-context pass found that the Linux-capture
section added in a391a95 contradicted four passages it had not touched, which
between them still instructed both of the things that section forbids. That is a
wrong executable instruction, not a style point: an agent following "Adding New
Visual Tests" steps 4-6 verbatim on Windows would commit 22 Windows-rasterised
PNGs, and the next visual-labelled run would fail on all of them with
maxFailures: 5 truncating the report so the cause was not even fully visible.

Reconciled, without weakening anything:

- "Generating Initial Baselines" and "Updating Baselines" merge into one section
  that names the hosted lane as the only committable source and keeps
  npm run test:visual:update for local iteration, which is what it is good for.
- The "regenerate CI-compatible baselines" recipe no longer says to lift
  *-actual.png out of visual-regression-diffs and commit it. That recipe is
  actively harmful at more than five failures: the artifact is capped, so the
  images you do not replace stay stale and the next run fails on those instead.
  Reading the diffs to confirm intent is still right, and still recommended.
- "Adding New Visual Tests" step 4 now says to iterate locally and then discard
  those images in favour of a hosted set.
- The local-vs-CI font note said baselines "may differ". They do not may — it
  fails on essentially every image, which is what parked this PR.
- Last Updated bumped; it had stood at 2026-04-09 through substantive edits.

Also corrects a stale claim in playwright.visual.config.ts, pre-existing and
identical on main: the header said the snapshot path template "includes platform
for OS-specific baselines" three lines above a template that has no {platform}
in it. Omitting it is correct and deliberate under the single-canonical-platform
policy, so the comment now says that instead.

Verification: npx tsc --noEmit clean, eslint clean on both changed TS files,
check-docs-governance and check-doc-links green.

Refs #1363
@Chris0Jeky

Copy link
Copy Markdown
Owner Author

Review round 1 — one fresh-context adversarial pass, complete

Verdict: no merge blockers. The reviewer verified the mechanism against source rather than taking the commit messages on trust. One finding was a wrong executable instruction that I had introduced myself, fixed in ab3d76cdc; the rest are tracked in #2764.

Confirmed sound (checked against source, not asserted)

  • data-toast-id is set unconditionally by both ToastContainer.vue and PaperToastContainer.vue, and existing unit specs already select on it — so it is an established contract, not a new test hook.
  • Both stacks really are position: fixed with pointer-events: none, so hiding shifts no page layout. visibility: hidden is the safer choice over display: none here.
  • The eight-toast arithmetic checks out: helpers.toast.success(...) fires on every board/column/card create, and board-populated seeds 1 board + 3 columns + 4 cards.
  • Hiding rather than waiting is not a workaround, it is the only correct option. toastStore.error(message, duration = 0) means error toasts never auto-remove, and page.clock.install() in the calendar spec freezes the removal timer outright — a "wait for the stack to clear" would hang or flake. A stylesheet also covers toasts raised after the wait, which a one-shot wait cannot.
  • Determinism sweep across all 16 specs came back clean. The only view that renders a date pins the clock; modal timestamps carry data-testid="timestamp" and are block-level so hiding them shifts nothing; presence is seeded synchronously on mount rather than racing SignalR; sidebar badges only render above zero.

Fixed here — the policy contradicted itself (MEDIUM-1)

The Linux-capture section I added in a391a95a9 contradicted four passages it had not touched, which between them still instructed both of the things it forbids: local --update-snapshots as the source of committed images, and lifting *-actual.png out of visual-regression-diffs. That is a wrong executable instruction — an agent following "Adding New Visual Tests" steps 4–6 verbatim on Windows would have committed 22 Windows-rasterised PNGs and re-parked this PR. Reconciled in ab3d76cdc without weakening anything, plus a stale claim in playwright.visual.config.ts (pre-existing, identical on main) that said the snapshot template "includes platform" three lines above a template with no {platform} in it.

Settled from the image review rather than left open (MEDIUM-2)

The reviewer flagged, as an unverified check, that settings-profile.png might predate the .td-info-value.paper-profile__info-value mask fix — which would mean a real username, email and GUID baked into a committed baseline. It does not. I read that image during the baseline review: it carries magenta mask rectangles over username, email, user id, role and ops access. The mask was live when the set was captured. The reviewer's underlying point is right and worth recording though — the old selector .td-info-value exists nowhere in src/, so before that fix the mask matched nothing at all.

Tracked, not fixed → #2764

Variable-length test usernames eroding the pixel-diff budget (real, but inside maxDiffPixelRatio: 0.005, and it lives in a file shared with the whole e2e suite); no toast coverage anywhere in the suite now (the fix is a dedicated toast spec, not weakening the hide rule); two silent-failure seams in the workflow's bootstrap path (R4 control plane, needs its own lane); and label-gated baseline drift accumulating invisibly until someone next applies the visual label.

Also refuted, recorded so it is not re-raised

maxFailures: 5 is not the wrong trade-off — the repo's primary Playwright config uses a stricter maxFailures: 3 in CI, and this lane is advisory with a tight 12-minute step budget at workers: 1.

Base moved under this PR

main advanced to 77c27b47e when #2761 merged, so 8cd733560 merges the new base in and everything is re-proving against it — required by the base-change rule regardless. That base move also produced a Smart CI / Required Gate false red (planner-error, reproducible across three re-runs), which is unrelated to this PR's content: recorded on #2327 and #2562, and it corrects the SC-4 "zero false reds" figure I posted earlier today.

Chris0Jeky added a commit that referenced this pull request Sep 6, 2026
Review round 1 on #2765. No blockers; these are accuracy fixes to a correction,
which is exactly the document that has to be right.

Two of them are places where I over-read my own evidence:

- I wrote that the false red "does not self-heal - three re-runs failed". But
  .claude/rules/ci-control.md already records that `gh run rerun` reuses the OLD
  merge ref, so those three failures are the documented consequence of that
  behaviour, not independent evidence that the condition persists. The re-runs
  now say what they actually show, and the sentence credits what really cleared
  it: pushing a merge of origin/main, after which Plan, Required Gate and
  Planner Self-Test are all green at ab3d76c.

- I stated as fact that a moved base "causes it for every open PR at once".
  That is an extrapolation from n=1, and n=1 was forced: #2753 was the only
  other open PR at 19:31Z, so there was no second PR to check. The mechanism
  does imply it, but the text now says the generalisation is inferred from the
  code path rather than measured, and names what would confirm it.

And three consistency fixes:

- The changelog entry I wrote earlier today still published the retracted "zero
  false reds" figure, untouched by the correction on the row. A future session
  reading the changelog for what the last session established would have taken
  away the exact claim this PR retracts. It now carries the retraction inline.

- The superseded annotation's lead-in still read "the observation window is
  complete and this is now actionable" in bold, unstruck. The row's four
  annotations are not in date order - a 2026-09-03 packet note follows the two
  2026-09-06 ones - so "last annotation wins" is not a rule this row obeys and
  ordering alone was a weak disambiguator for a skimmer. Struck and pointed at
  the correction.

- The 72/66/5/1 tally is now explicitly scoped to before 19:34Z, so it reads as
  a snapshot rather than a closed count that contradicts the correction below it.

Tracked, not fixed here: docs/releases/V0_3_0_READINESS.md still records #2506
as closing this planner shape, which this evening's reproduction contradicts.
That is a different document and belongs on #2562.

No checkbox changed state; verified the SC-4 row is still `- [ ]` and that the
diff against main adds no `- [x]` line.

Verification: check-docs-governance and check-doc-links both green.

Refs #2327, #2562
@Chris0Jeky
Chris0Jeky merged commit 9afac1f into main Sep 6, 2026
39 checks passed
@Chris0Jeky
Chris0Jeky deleted the issue-1363/baseline-census branch September 6, 2026 21:01
@github-project-automation github-project-automation Bot moved this from Pending to Done in Taskdeck Execution Sep 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

testing Test coverage, harnesses, regression prevention, and verification pipeline work.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant