Skip to content

ci: add playwright-update.yml for branch snapshot regeneration#816

Merged
arcjet-rei merged 2 commits intomainfrom
rei/feat/eng-715-playwright-update-workflow
Apr 29, 2026
Merged

ci: add playwright-update.yml for branch snapshot regeneration#816
arcjet-rei merged 2 commits intomainfrom
rei/feat/eng-715-playwright-update-workflow

Conversation

@arcjet-rei
Copy link
Copy Markdown
Contributor

Summary

Adds .github/workflows/playwright-update.yml — a manual workflow_dispatch-triggered workflow that runs against the dispatched ref, regenerates Playwright snapshots, and pushes the result back to the branch.

Why

The existing snapshot regeneration procedure in CONTRIBUTING.md (npm run pw:run -- --update-snapshots=changed) works on Linux x86_64 hosts, including the devcontainer when the host is Linux x86_64. It silently underperforms on Apple Silicon: the devcontainer image (mcr.microsoft.com/devcontainers/javascript-node:24) is multi-arch, so it pulls arm64 on Apple Silicon, and Chromium font rasterization diverges from native amd64 — text-heavy pages overflow the maxDiffPixels: 100 threshold even when the rendered HTML and the dist/ artifact are byte-identical.

PR #815 (ENG-711) hit this on troubleshooting-{light,dark} snapshots (~4000px diff each) and had to pin the baselines to bytes downloaded from the failing CI run's blob report. That works but is not a procedure we want future contributors to rediscover. Running the regeneration on the CI runner eliminates the host-arch concern entirely — the runner is amd64 by definition, so its renders match what the regular Playwright test job produces on the same architecture.

Closes ENG-715. Related: ENG-711 (#815).

Behavior

  • Trigger: workflow_dispatch only. No auto-trigger on PR comments, labels, or pushes.
  • Branch targeting: runs against the ref the workflow is dispatched on, e.g. gh workflow run playwright-update.yml --ref rei/feat/some-branch.
  • Refresh policy: --update-snapshots=all so a deliberate dispatch always produces a full refresh rather than depending on Playwright's "changed" heuristic.
  • Guard: the guard job refuses to run if github.ref == 'refs/heads/main' to prevent accidental baseline mutation against the protected branch.
  • No-op safety: if no snapshot files changed, the workflow exits cleanly without an empty commit.
  • Push mechanism: uses the default GITHUB_TOKEN with contents: write permission. Does not skip pre-receive hooks.
  • Traceability: the commit message links back to the workflow run.

Known limitation

Pushes from GITHUB_TOKEN do not retrigger downstream workflow runs. After this workflow commits new snapshots, the existing Playwright tests workflow will not re-run automatically — you'll need to push another commit (or rerun the checks manually) to verify the regenerated snapshots actually pass. Documented in a header comment on the workflow file.

Test plan

  • Merge, then dispatch against a feature branch with intentionally stale snapshots (e.g. one that intentionally shifts a sidebar entry):
    gh workflow run playwright-update.yml --ref rei/test/intentional-sidebar-tweak
  • Confirm a test: regenerate Playwright snapshots from CI commit appears on that branch.
  • Push a no-op commit to that branch and confirm the regular Playwright tests workflow now passes.
  • Dispatch against main and confirm the guard job fails immediately.
  • Dispatch against a feature branch with no actual snapshot changes and confirm the workflow exits cleanly (no empty commit).

🤖 Generated with Claude Code

Manual workflow_dispatch-triggered workflow that runs against the
dispatched ref, regenerates Playwright snapshots, and pushes the result
back to the branch.

Resolves the cross-arch snapshot problem documented in ENG-715: the
existing CONTRIBUTING.md procedure works for Linux x86_64 contributors
but produces ~few-thousand-pixel divergence for Apple Silicon
contributors because Chromium font rasterization differs between native
amd64 and Rosetta-emulated amd64, even inside the multi-arch
devcontainer. Running the regen on the CI runner eliminates the
host-arch concern entirely.

Behavior:
- workflow_dispatch only; no auto-trigger.
- Refuses to run against main (guard job exits 1 if github.ref ==
  refs/heads/main).
- Uses --update-snapshots=all so a deliberate dispatch always produces
  a full refresh rather than relying on Playwright's "changed"
  heuristic.
- No-ops if no snapshot files changed.
- Pushes via GITHUB_TOKEN with contents: write. Does not skip pre-receive
  hooks.
- Commit message links back to the workflow run for traceability.
- Note: GITHUB_TOKEN pushes do not retrigger downstream workflows; the
  existing Playwright tests workflow needs another push or manual
  re-run after this one commits.

Closes ENG-715.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
arcjet-docs Ready Ready Preview, Comment Apr 29, 2026 5:51pm

Request Review

Copy link
Copy Markdown
Contributor

@arcjet-review arcjet-review Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arcjet Review — 🟡 Medium Risk

Decision: Approved

Rationale: Adds a new manual workflow to regenerate Playwright snapshots on a feature branch from CI. Triggers the ci-cd-changes escalation. The change is well-scoped, isolated to a new file, and uses defensive practices: workflow_dispatch only, an explicit guard job that refuses to run on main, pinned action SHAs, harden-runner with audit egress, set -euo pipefail in the push step, and contents:write scoped only to this workflow. The 'secret' ARCJET_KEY is intentionally a dummy value per the inline comment. No real credentials are introduced and no untrusted PR-controlled inputs are evaluated. Approving with one inline nit about commit-message body indentation.

Summary of Changes

Adds .github/workflows/playwright-update.yml — a manually-dispatched workflow that regenerates Playwright snapshots on the dispatched feature branch (refusing to run against main), runs npm ci + Playwright with --update-snapshots=all, and commits/pushes the result back via GITHUB_TOKEN.

Escalation Triggers

  • CI/CD Pipeline: Adds a new GitHub Actions workflow file under .github/workflows/.

Notes

Workflow uses pinned action SHAs and harden-runner — good supply-chain hygiene. PR is small (~97 lines added) and well below the size threshold.

Review: 777ce902 | Powered by Arcjet Review

Comment thread .github/workflows/playwright-update.yml Outdated
Comment thread .github/workflows/playwright-update.yml
@qw-in
Copy link
Copy Markdown
Member

qw-in commented Apr 29, 2026

It silently underperforms on Apple Silicon: the devcontainer image (mcr.microsoft.com/devcontainers/javascript-node:24) is multi-arch, so it pulls arm64 on Apple Silicon

Really? If its multi-arch that is very surprising...here is from my docs devcontainer

uname -m
aarch64

- Reject non-branch refs (`refs/tags/...`) in the guard job alongside the
  existing `main` check, so the push step's `refs/heads/` strip always
  has something to strip.
- Switch the commit step from a single multi-line `-m` argument to multiple
  `-m` flags so the body lines aren't committed with the YAML's leading
  indentation preserved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@arcjet-rei
Copy link
Copy Markdown
Contributor Author

@qw-in Yeah — aarch64 from your devcontainer is exactly the symptom. The image is published as a multi-arch manifest (you can confirm with docker manifest inspect mcr.microsoft.com/devcontainers/javascript-node:24 — it lists both linux/amd64 and linux/arm64), and Docker Desktop on Apple Silicon picks the arm64 variant by default. So inside the container uname -m reports aarch64, Chromium runs as a native arm64 binary, and the snapshots don't match what an x86_64 CI runner produces — even though everything inside the devcontainer is "Linux".

The workflow sidesteps the whole question by running the regen on the GitHub-hosted runner, which is amd64 by definition.

@arcjet-rei arcjet-rei enabled auto-merge April 29, 2026 17:50
@arcjet-rei arcjet-rei added this pull request to the merge queue Apr 29, 2026
Merged via the queue into main with commit 78799b1 Apr 29, 2026
11 checks passed
@arcjet-rei arcjet-rei deleted the rei/feat/eng-715-playwright-update-workflow branch April 29, 2026 18:03
@qw-in
Copy link
Copy Markdown
Member

qw-in commented Apr 29, 2026

@arcjet-rei im happy to have the ci run for this as well but with the specific chrome configuration it has been a pixel perfect match for the last 6 months or so

Claude is really bad about it and gets very concerned and confused but in practice it's pretty stable

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.

2 participants