Repository navigation
ci(webviews): split the test shards by recorded duration, not index mod 4 - #27230
Conversation
…od 4 The four react-apps-check shards took files by index mod 4. One new file moved every file after it, and the heavy dev-server files fell together by chance. On feat-cmux-next push runs the shards took about 20, 14, 11 and 9 min (32 vCPU; run 40815704587). - scripts/ci/webviews_test_shards.py: files with a recorded duration go, longest first, to the shard whose estimated wall time grows least. A shard is modelled the way the runner runs it: plain files on 32 lanes, dev-server files on 8, alone files in series. Files with no recorded time go by a stable hash of their path, after the others, so a new file moves only itself. - run-webviews-tests.sh: with a manifest, each Vite config warms on its shortest file (accent-glass-invariants warmed alone for 549 s of an 18.6 min shard), and the plain and dev-server pools start their longest files first. Each file's first-run seconds are written out (CMUX_WEB_TEST_DURATIONS_OUT). - ci-web.yml: web-subarea-scope restores the newest manifest from the cache once and hands it to every shard as an artifact, so all four split by the same copy. react-apps-check merges the shards' seconds with it (each file's average with its prior) and saves the next manifest. A pull request's entry stays in its own ref's scope; fork pull requests save none. Replaying run 40815704587's per-file times through the runner's phases reproduces today's shards (18.6, 11.2, 9.5, 7.7 min against 18.6, 12.1, 9.9, 7.7 measured) and gives 9.2-9.6 min with this split. Red/green: tests/test_webviews_tests_per_file.py's 5 new runner tests fail on the old runner and pass now (the load split, a new file moving only itself, the hash split, the warming pick and pool order, the recorded seconds), plus helper and workflow tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-7a592ef92c66f080e3cc
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Yours to fix: CI failed on
Failures:
Matched log linesNot re-run automatically: Written by red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on 9af05f0 to compare; do not merge until green; see lane-rules |
|
Found 8 test failures on Blacksmith runners: Failures
|
|
Bead |
…acts keep 1 day The review found the manifest checkout, download and cache save inside the five-minute required react-apps-check: continue-on-error survives a failed step, not a stalled one that times the job out. They move to webviews-test-durations, which nothing requires. The shard's manifest download moves before Setup Node, where the setup steps run (test_cmux_next_fast_gates keeps every step between the setup and the tests continue-on-error and gated), and both handoff artifacts keep 1 day (test_ci_upload_artifact_retention): the cache carries the manifest between runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-7a592ef92c66f080e3cc
…the manifest artifact overwrites Review: run-webviews-tests.sh runs one file per Vite config alone before the dev-server pool, and ShardPlan counted only the 8-lane pool (one config's 100 s and 20 s files: 120 s, not 100). The plan now keeps each config's warming file (its shortest so far, as the runner picks it) in series ahead of the pool. A re-run of the whole run would fail on the same-named manifest artifact; it overwrites. Replaying run 40815704587: 9.6, 8.9, 9.7, 9.8 min (max/min 1.10). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-7a592ef92c66f080e3cc
Review: the per-shard duration upload sat after the gated steps without continue-on-error, so an artifact-service failure or stall could fail a required react-apps-check shard. It now keeps going (2 min cap), and the gate step reads its outcome as a warning only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-7a592ef92c66f080e3cc
|
Shipped in:
|
|
Measured after landing: Performance
The split is more even, but the slowest shard fell far less than the replay predicted (9.8 min). There are two causes, and both read the same way in 40846198563 (max/min 1.93):
Follow-up, not in this PR: weigh plain files by contention (balance each shard's total recorded seconds as well as its lane time), and count the expected retry time of files that are red on the base. |
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Follow-up to #27202. The four
react-apps-checkshards took webview test files by index mod 4, so adding one test file moved every file after it, and the heavy dev-server files fell together by chance (the #27045 case #27194 describes). Onfeat-cmux-nextpush runs the shards were consistently 2x apart. The slowest took about 20 min and the fastest about 9.What changes
scripts/ci/webviews_test_shards.py. Files with a recorded time go, longest first, to the shard whose estimated wall time grows least. A shard is modelled the wayrun-webviews-tests.shruns it: plain files on 32 lanes, one warming file per Vite config in series, the other dev-server files on 8 lanes, then// cmux-web-test-alonefiles one after another. Files with no recorded time go by a stable hash of their path, after the others, so a new file moves only itself. The split never reads the runner's own size, so the four shard jobs agree even when one lands on the 16 vCPU fallback.accent-glass-invariants(549 s) came first in the index and warmed its config alone for 9 of shard 3's 18.6 min (run 40815704587).web-subarea-scoperestores the newest manifest from the Actions cache once and hands that copy to all four shards as an artifact, so they split by the same copy. A shard that read the cache itself could get a newer copy than its siblings and skip or repeat files.CMUX_WEB_TEST_DURATIONS_OUT; a retry runs alone and says nothing about the file among the others).webviews-test-durations, averages them with the prior manifest and saves the next one. Nothing requires it, so a stalled download or cache save can't time outreact-apps-check; a missing manifest only means the next split is by path hash.feat-cmux-nextpush runs keep the shared manifest fresh.Performance
Before: the replay of the measured per-file times reproduces today's shards (18.6, 11.2, 9.5, 7.7 min against 18.6, 12.1, 9.9, 7.7 measured), so it models the runner's phases closely. After: the same times through the new split and order. This PR's first run starts from an empty manifest (path-hash split). The manifest it saves feeds the next run, so a measured "after" comes from a run that reads a manifest. The measured slowest shard job before is 19.6 min (run 40815704587, 32 vCPU). I'll add the measured after from the first run that reads a manifest, on the same 32 vCPU class.
Red / green
python3 tests/test_webviews_tests_per_file.py: the 5 new runner tests fail on the base runner and pass on this head: the load split, a new file moving only itself, the hash split for files with no recorded time, the warming pick and pool order, the recorded seconds. There are also new helper tests (merge, record, the lane weighting) and a workflow test (one manifest fromweb-subarea-scope, merged and saved byreact-apps-check, never saved by forks). 36/36 pass.tests/test_webviews_tests_new_reds.py: the test of the base replay re-running every red file now counts the files its shard ran, since the shard is no longer index mod 2. 23/23 pass.Observed / Not run
tests/test_webviews_tests_per_file.py(35 OK),tests/test_webviews_tests_new_reds.py(23 OK),tests/test_web_validation.py,tests/test_ci_change_areas.py,tests/test_test_reds.py,scripts/ci/tests/run-webviews-tests-retry.test.sh,actionlintonci-web.yml,scripts/cmux-next/prepush-gate.py(no new violations).Risk: CI only (
risk:low). Every shard reads the same manifest artifact or fails its download, so shards cannot disagree on the split. A stale or missing manifest only makes the split less even, never incomplete: every file in the git index lands on exactly one shard.Changelog
none
🤖 Generated with Claude Code
Agent session: agent session