Skip to content

fix(ci): bump playwright to 1.62.1 so the browser install stops hanging - #5374

Merged
usirin merged 1 commit into
mainfrom
usirin/playwright-bump-5343-EC814B8E
Aug 10, 2026
Merged

fix(ci): bump playwright to 1.62.1 so the browser install stops hanging#5374
usirin merged 1 commit into
mainfrom
usirin/playwright-bump-5343-EC814B8E

Conversation

@usirin

@usirin usirin commented Aug 10, 2026

Copy link
Copy Markdown
Member

Playwright 1.59.1 downloads the browser archive fine and then parks forever in its bundled zip extractor under the repo's pinned Node 26.2.0, so a machine without a prebaked browser never gets one. Triage had already isolated the variable (the Node major) and shown that 1.62.1 extracts fine on the same Node, so this is a version bump, not an investigation. The catalog moves to ^1.62.1 and the e2e job's container tag moves to v1.62.1-jammy in lockstep, because the image's prebaked browsers have to match the locked client.

Fixes #5343

What changed

  • pnpm-workspace.yaml@playwright/test catalog entry ^1.59.1 -> ^1.62.1. Every consumer (apps/web, packages/fabrika-cli, packages/local-render) already reads catalog:, so nothing else moves.
  • pnpm-lock.yaml — regenerated; the diff is playwright-only (@playwright/test, playwright, playwright-core 1.59.1 -> 1.62.1).
  • .github/workflows/ci.ymle2e container mcr.microsoft.com/playwright:v1.59.1-jammy -> v1.62.1-jammy, and the comment above it now says the hang was a 1.59.1 defect that this bump fixes, rather than stating it in the present tense.

Evidence (real runs, darwin-arm64, Node 26.2.0 — the repo's volta.node pin)

Cold playwright install chromium into an empty PLAYWRIGHT_BROWSERS_PATH, DEBUG=pw:install: exit 0 in about 8 seconds. extracting archive is followed one second later by fixing permissions and SUCCESS installing — the exact line the 1.59.1 runs parked on forever. 568 MB landed (chromium-1234, chromium_headless_shell-1234, ffmpeg-1011).

packages/fabrika-cli/scripts/provision-browser.mjs end to end, no PLAYWRIGHT_BROWSERS_PATH, no CI, no skip flag, and no chromium-1234 in the default cache: exit 0 in 11 seconds, both browsers downloaded and extracted into the default cache. That is well inside the script's spawn timeout, so the run-time exit-11 remediation path is no longer where a cold machine ends up.

Guards: pipeline-cli catalog-guard check green (29 manifests, all catalog:/workspace:), pnpm typecheck green (31/31), pnpm lint:worktree a clean skip (no biome-handled files changed).

CI: the diff touches pnpm-lock.yaml and .github/workflows/ci.yml, both of which trip the e2e path filter, so this PR runs the e2e suite inside the new container. No job timeout was raised.

Finding: the browser cache the issue asks about does not exist on main

One acceptance criterion asks for the .github/workflows/ci.yml browser cache to be shown saving and hitting, or for a finding explaining why it cannot. There is no browser cache step in ci.yml on main — the only ms-playwright mention is a comment. The cache is introduced on #5169's branch, together with the removal of provision-browser.mjs's CI skip. Until that lands, no CI job extracts a browser at all (e2e uses the prebaked image; every other job hits the CI skip), so there is nothing here to save or hit. This bump is what makes that cache able to work once #5169 lands; proving the save/hit belongs to #5169's PR, where the cache actually exists.

Deviations

  • Class: narrowed a suggested fix-shape. Said: the issue leaves the lowest fixed playwright version open and notes 1.60.0/1.61.x were never tested. Did: bumped straight to 1.62.1, the version triage verified first-hand, without bisecting for a smaller move. Why: an unverified smaller bump would trade a proven fix for a guess, and 1.62.1 is latest with a matching -jammy image. Disposition: no action needed — the issue explicitly says the smallest-possible-move question only needs answering if the implementer wants it.
  • Class: acceptance criterion discharged by a finding rather than a demonstration. Said: show the CI browser cache saving and hitting. Did: recorded the finding above instead. Why: the cache does not exist on main. Disposition: the issue's own criterion sanctions this fork; the demonstration belongs to fabrika: the browser-provisioning CI skip pre-empts the presence check, so it only fires when the browser is genuinely missing #5169.
  • Class: a pre-existing test failure I did not fix. Said: nothing. Did: the first pre-push hook run reported one failing unit test in the fate-live suite (a Post:post-clobber case) out of 2424; a re-run of the same command found no changed test files and the second push was clean. Why: the diff touches no apps/web code, so this is unrelated flake, not a regression from the bump. Disposition: for the reviewer to judge — flagged here rather than silently swallowed.

@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

🚀 Preview deployed

  • web — Stage pr-5374 torn down.

@usirin

usirin commented Aug 10, 2026

Copy link
Copy Markdown
Member Author

review-code: advisory — blocking-set PR (§CP — approval-gated)

PR #5374 is §CP: it touches .github/workflows/ci.yml, which is control plane under the canonical §CP set (.github/**; ADR 0053/0065) and is owned by @kamp-us/control-plane in CODEOWNERS. This verdict is advisory only. It does not authorize a merge, and it deliberately carries no first-line @ <sha>, so it never enters the auto-merge PASS namespace of ship-it. Under the §CP hard gate (ADR 0135) a @kamp-us/control-plane member approves this at its current head and ship-it then enqueues it (ADR 0048 single merge authority). Plainly: this PR banks for human approval and never auto-ships.

Reviewed-head: @ c9d264f

Class routing: pipeline-cli class-probe classify --namespaces over the 3 changed files (.github/workflows/ci.yml, pnpm-lock.yaml, pnpm-workspace.yaml) names exactly one required namespace, review-code (§CLASS no-class fail-closed: root tooling outside the code roots rides has-code). No UI-affecting path, no docs, no skills, so no other gate is required at this head.

Read the PR head (§HEAD): every file under review was sourced from c9d264f6 through a per-run ref plus a throwaway worktree, never from the launched checkout working copy.

Verified PR #5374 against the acceptance criteria of #5343, one at a time. All pass:

  • [PASS] playwright install chromium completes into a cold browsers directory under the pinned Node, demonstrated by an actual run — independently reproduced by this gate, not lifted from the PR body. Node v26.2.0 (the repo volta.node pin), playwright-core@1.62.1, PLAYWRIGHT_BROWSERS_PATH pointed at an empty scratch directory, DEBUG=pw:install: exit 0, and 554 MB landed as chromium-1234 / chromium_headless_shell-1234 / ffmpeg-1011. The extraction stage that parked forever at 1.59.1 completes here. The author cold-install run recorded on fabrika: playwright 1.59.1's browser install hangs in extract-zip after the download completes, so provisioning never succeeds on a cold machine #5343 corroborates it.
  • [PASS] The @playwright/test catalog entry moves to a version shown to work under the pinned Node, and catalog-guard stays green — pnpm-workspace.yaml carries @playwright/test: ^1.62.1; the lockfile resolves 1.62.1 in the catalog block and in all three consuming importers (apps/web, packages/fabrika-cli, packages/local-render), each still on specifier: catalog:. pnpm install --frozen-lockfile in the head worktree exits 0, so lockfile and edited catalog are consistent at this head. The CI job check every package.json dep is on catalog:/workspace: is green at c9d264f6.
  • [PASS] The e2e container tag matches the new pin exactly — .github/workflows/ci.yml pins mcr.microsoft.com/playwright:v1.62.1-jammy against a locked client of 1.62.1. The tag is real: an MCR manifest request for v1.62.1-jammy returns 200, while the negative control v1.99.9-jammy returns 404. Stronger still, the e2e job at this head actually ran inside it — the job log shows docker pull mcr.microsoft.com/playwright:v1.62.1-jammy then Status: Downloaded newer image, and the job passed in 8m10s. Catalog and container are genuinely in lockstep, in one commit, so they cannot drift.
  • [PASS] packages/fabrika-cli/scripts/provision-browser.mjs provisions a browser end to end on a machine with no prebaked browser, inside its spawn timeout, evidenced by a real run — the script is untouched by this diff; at head it spawns pnpm exec playwright install chromium under a 600s spawnSync timeout. That spawned command is exactly the path proven above to complete in well under a minute at 1.62.1 on Node 26.2.0, orders of magnitude inside the timeout, where 1.59.1 burned the whole budget and still failed. The author end-to-end wrapper run (exit 0 in 11s, cold default cache, no CI, no skip flag, no PLAYWRIGHT_BROWSERS_PATH) is recorded on fabrika: playwright 1.59.1's browser install hangs in extract-zip after the download completes, so provisioning never succeeds on a cold machine #5343. Fence: my own run exercised the underlying install rather than the wrapper; the wrapper adds only skip checks and this diff changes neither.
  • [PASS] The browser cache in .github/workflows/ci.yml is shown to save and hit, or a finding is recorded on this issue explaining why it still cannot — discharged through the second fork of the criterion, and that fork is genuinely sanctioned, not an escape hatch. I checked the premise against live main rather than accepting it: ci.yml on main contains exactly one actions/cache@v4.2.3, and it is the turbo build cache (path: .turbo/cache, keyed on the lockfile plus build sources). There is no browser cache step, and the only ms-playwright occurrence in the file sits inside a comment. So there is nothing on main to demonstrate saving or hitting; the cache arrives with fabrika: the browser-provisioning CI skip pre-empts the presence check, so it only fires when the browser is genuinely missing #5169, still open. The finding is recorded on fabrika: playwright 1.59.1's browser install hangs in extract-zip after the download completes, so provisioning never succeeds on a cold machine #5343 itself, not only in the PR body, which is what the criterion asks for. This gate does not accept a criterion re-scoped by an author; it accepts this one because the issue text wrote the fork.
  • [PASS] e2e and the rest of CI stay green, with no job timeout raised to accommodate the install — every check at c9d264f6 is green, including e2e (reads + authed + flows, blocking), integration tests, lint / format / typecheck, unit + client tests and packages unit tests. The diff contains no timeout-minutes change; the e2e job stays at timeout-minutes: 25.
  • [N/A] If no bump turns out to be viable, the alternative is an in-repo pnpm patch per ADR 0038 or a recorded finding — the bump was viable and is proven, so this branch never opens. The hard floor of the criterion is respected: the Node pin was not downgraded (package.json still pins 26.2.0).
  • [PASS] deviation-disclosure (§DEV) — the body carries a ## Deviations section disclosing all three departures, and each holds up: (1) bumping straight to 1.62.1 without bisecting for the lowest fixed version is explicitly authorized by the triage note on the issue; (2) discharging the cache criterion by a finding is authorized by the or fork of that criterion, and the finding is verified present on the issue; (3) the flaky unit failure was surfaced for the reviewer rather than swallowed. Nothing undisclosed that this gate could see.
  • [PASS] comment-discipline — the single comment this diff touches is the e2e container rationale in ci.yml. It is a KEEP-category note under the deslop-comments rubric: a workaround plus its forcing constraint (the image is used because a ~170MB download per run is cost this job does not need), with the stale present-tense hang claim corrected to a 1.59.1-scoped past fact. Not narration, not a name-restater. Recorded honestly: the automated comment-scan reports scanned 0 because .yml is off its comment-bearing surface, so this line is my own judgement rather than the output of the scan.

Independent check of the disclosed lockfile-collision risk (playwright-only, nothing near the typescript entries that #5370 is moving) — verified, with one caveat. The pnpm-lock.yaml patch is 38 changed lines, every one playwright: the catalog entry, three importer pins, and the @playwright/test / playwright / playwright-core package and snapshot blocks. Zero typescript occurrences anywhere in the patch. Against the in-flight #5370 (typescript@7): the two pnpm-workspace.yaml edits are disjoint (this PR at lines 28-34, #5370 at 21-27 / 43-49 / 74-80), and no lock hunk of either PR overlaps the other. Nearest approach is about 7 lines (@@ -873,7 here beside @@ -880,19 there, and @@ -1052,7 beside @@ -1059,19). A textual merge should be clean. Caveat, offered as an observation and not a gate finding: both PRs regenerate the same lockfile, so whoever lands second should re-run pnpm install --frozen-lockfile on the merged result before shipping. Disjoint hunks guarantee no conflict marker, not a semantically re-resolved lockfile.

Independent check of the disclosed flaky unit failure — genuinely unrelated. The case is apps/web/worker/features/fate-live/do.test.ts:630 (Post:post-clobber, the #731 replay-side regression test). Three independent reasons it is not caused by this PR: (1) the diff touches no apps/web code at all; (2) CI at this exact head ran the full unit surface green, and the run-evidence bundle records 2424/2424 passed, 0 failed; (3) I re-ran that suite 5 times in the head worktree and got 33/33 passing every time. The test is also timing-sensitive by construction: it sets bufferedFrameTtlMs: 30 and ages a frame out with a setTimeout(50), so under the CPU contention of a full 2424-test pre-push run those two windows can invert. Verdict: a pre-existing latent flake, correctly not fixed here. Recommend filing it through report so the flake is tracked; it is out of scope for this PR and should not ride along.

Sub-gates: glossary-freshness: not applicable (no new feature folder, public package or export; detector expressible here, 50 candidate surfaces on base). unresolved-threads: not applicable (no review threads on this PR). session-caching gate: not applicable (0 candidate seams in the diff). The containment marker on #5343 reads none, so the flag-gating step is a clean no-op.

Run-evidence bundle: PRESENT for head c9d264f6 — producer run 31435121998, artifact 9080787623, manifest.commit == head, schemaVersion 1; checks 2/2 pass; tests 2424/2424 passed, 0 failed, 0 skipped.

In-worktree typecheck: 31/31 tasks successful (turbo full-cache hit, meaning the inputs are content-identical to a prior green run, which is expected since this diff contains no TypeScript). The real lint / format / typecheck CI job is green at this head and is the authoritative signal for it.

All criteria pass. review-code does not merge, and on this §CP PR it cannot even signal auto-merge: a @kamp-us/control-plane human must approve at c9d264f6, after which ship-it enqueues it. Merging will auto-close #5343 through its Fixes #5343.

Verdict-written: 2026-08-10T22:11:30Z

@usirin
usirin added this pull request to the merge queue Aug 10, 2026
Merged via the queue into main with commit 676085d Aug 10, 2026
46 checks passed
@usirin
usirin deleted the usirin/playwright-bump-5343-EC814B8E branch August 10, 2026 23:29
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.

fabrika: playwright 1.59.1's browser install hangs in extract-zip after the download completes, so provisioning never succeeds on a cold machine

2 participants