3c9668f9e2
Measured on run 35535225637 (push to main, caches warm). The critical path was the browser job at 263s plus an 11s deploy; everything else finished inside it. Its decomposition: harness lint 37s, Playwright browser download 50s, `./harness/build.sh` 110s, `npx playwright test` 50s. Three wasm-pack builds ran in that 110s, and two of them — the client and the worker bundle — were the same two `pages-build` ran in its own 68s step, in a parallel job with a separate rust-cache key (`add-job-id-key` defaults on). Same work, twice per run. - One `build` job now runs `./harness/build.sh` (all three bundles plus the `harness/serve` tree) and then `./web/assemble.sh site $GITHUB_SHA` from the pkg dirs it just produced. It uploads `harness/serve`, the two raw bundles, and the Pages artifact. `pages-build` is folded into it. - `browser` downloads `harness/serve` whole and needs no Rust toolchain and no wasm-pack. Downloading the tree rather than reassembling it keeps one answer to "what does the harness serve" (improvise-vvl3): `harness/build.sh`. Verified locally that the two assemblies differ in exactly the four cache-bust-stamped files and nothing else — the .wasm bytes are identical. - `harness-lint` is its own job. It gated nothing the harness needs and cost 37s of the critical path, and `cargo fmt --all` run from inside `harness/opfs-contract` formats the WHOLE outer workspace (114 files, measured) despite that crate's empty `[workspace]` table, so a rustfmt violation anywhere in the repo failed the *Browser harness* job. `-p opfs-contract` scopes it to the one file it is about. - Playwright's browser download is cached on the resolved package version. - rust-cache in `build` and `harness-lint` covers `harness/opfs-contract`'s own target dir, which the default single-workspace config never did. No gate is weakened. `pages-deploy` still needs every check that could previously fail it; `harness-lint` is named explicitly because it used to be a step inside `browser`. `kb`, `wasm` and `test` gain no dependency on `build` — none of them consumes an artifact. On improvise-864a: the gap between the Pages artifact upload and the deploy narrows from ~182s to ~115s on this run's shape, so the window in which a superseding run can expire it is smaller. The race is not closed, and not widened. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>