Repository navigation
ci: every runner selection reads its size's declared pool (no single-size pins, 1/2) - #32457
Conversation
|
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)
Passes: CI passes on CI passes on Written by web and size checks: green Shipped in:
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/41497919334 at f6b340f failed: cmux-next crash ends the app, cmux-next daemon tests. |
|
Found 6 test failures on Blacksmith runners: Failures
|
A literal single-size Blacksmith label in runs-on, a matrix pool, a *RUNNER* env mirror or a reusable-workflow runner input becomes fromJSON(vars.RUNNER_POOLS).<pool> (main's .github/runners.json pools, written every 10 minutes by scripts/ci/runner_pools.py), so a size that stops starting jobs is left by the pool instead of by a YAML edit. Each pool's first member is the literal it replaces: routing is unchanged until a size stalls. Forks keep their literal: an existing fork branch stays ahead of any read, and a read a fork could reach is wrapped as (<fork pull request> && '<old label>' || <pool read>). Comparisons, membership lists, the owner branch and the CI_TRUSTED_RUNNER selector (runner trust policy) keep their literals. Tests that assert exact lines now expect the pool reads, and tests that assert Blacksmith is absent also refuse the pool read. Leo-ask: ask-973a915bea Co-Authored-By: Codex <noreply@openai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-04cad32e0d917ebc8a49
bb52cf4 to
83d4bbf
Compare
|
This is a note for the lane adding swift-test-fleet / daemon-test-fleet jobs and Linux twin branches to This PR rewrites each literal Blacksmith label in Please write new branches in pool form. Whichever PR lands second rebases. This PR does not touch |
|
Review (codex gpt-6-astra high, sweep, via the review router; full diff from merge base 9fde804 to this head): BLOCK at bb52cf4 [P1] [blocking] tests/test_ci_repo_variable_defaults.py:45 - The pool fallback matcher does not recognize parenthesized pool routes such as |
…rsal nightly workflow) (#32529) - Validate nightly push throttle (test_ci_warm_sources): #32513 moved "Build and sign the release notes" into release-notes-build-sign.sh, and the warm-sources detector reads a script named *build*.sh as a compile. The step compiles nothing, so the script is renamed release-notes-sign.sh. - Validate universal nightly workflow (test_nightly_universal_build.sh): #32457 turned literal runner labels into declared pool reads (fromJSON(vars.RUNNER_POOLS).<pool>, whose first member is the old literal) but left three exact-expression checks expecting the literals: the decide gate, refresh-compilation-cache and build-nightly-ghostty-cli-helper. They now expect the pool reads #32457 wrote; each still matches the job's whole expression. Base-red-job: cmux-next guards / nightly-guards / workflow-guard-tests / release-notary Agent-Session: https://cmux.com/deeplink/agent?id=aid-f724bb1ff9295c18fee7 Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…32653) #32457 moved the iOS kit picker's fallback to fromJSON(vars.RUNNER_POOLS).linux_8, but the fixture variable held only `linux`, so the picker's runs-on resolved to null and four "iOS kit picker fallback" cases failed on feat-cmux-next. The fixture now holds each pool declared in .github/runners.json at its first member (what runner_pools.py keeps it at), and the iOS kit cases test the pool reads: the eight vCPU pool, a moved pool, the bounded LINUX_RUNNER sizes and the saved-overflow sixteen vCPU pool. The unset and empty variable cases are gone: RUNNER_POOLS is required and an unset one fails the run at fromJSON(). Agent-Session: https://cmux.com/deeplink/agent?id=aid-73244be6791fcec67af9 Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
feat-cmux-next's #32457 made nearly every runner selection read vars.RUNNER_POOLS, and the guard counted each as able to take an owned Mac, so CI fast guards failed on main and on every pull request, and the macOS admission gate then refused them. runner_pools.py rejects any pool member that isn't an ephemeral Blacksmith label, so these reads can't reach one. fast-checks.yml was watched only for that read, so its entry goes too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 25fb044)
#35630) #30657 added scripts/ci/nightly_next_control_runner.py and nightly_next_control_rescue.py as a helper-only prerequisite for #30509, which closed in favour of the runner-pool design (#32457). No workflow on feat-cmux-next or main calls either; only their own tests, a pool test and the test registry named them. The tick already picks its runner from RUNNER_POOLS. Agent-Session: https://cmux.com/deeplink/agent?id=aid-f08996319b14c7281027 Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…size feat-cmux-next's runner guards refuse a literal single-size label (#32457) and one with no overflow failover (#26439), and the old linux_2 route was reachable outside manaflow-ai. The job now takes the owner fork branch, then the overflow pool linux_16 or linux_8, the same pools backend.yml's credentialed jobs end in. It no longer reads vars.LINUX_RUNNER, so that variable cannot move it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-8b9c8964a6aea0b7e2bd
… production journey names its runner (#35717) * ci: the backend secret-route guard covers the three Cloud journey jobs journey-preview, journey-staging and journey-production (#35103) read secrets and the cmux-next-cloud-journey environment, so they belong in BACKEND_SECRET_JOBS; without them the guard's credentialed-set check fails and their routes go unchecked. Their routes already have the bounded pool-read shape. cloud-journey-prod.yml's job holds the production account, so it names blacksmith-4vcpu-ubuntu-2404 literally, as on main (#35303). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-8b9c8964a6aea0b7e2bd * ci: the production journey reads the Blacksmith pools, not a literal size feat-cmux-next's runner guards refuse a literal single-size label (#32457) and one with no overflow failover (#26439), and the old linux_2 route was reachable outside manaflow-ai. The job now takes the owner fork branch, then the overflow pool linux_16 or linux_8, the same pools backend.yml's credentialed jobs end in. It no longer reads vars.LINUX_RUNNER, so that variable cannot move it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-8b9c8964a6aea0b7e2bd --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Leo-ask: ask-973a915bea
Leo: "Where the f*** are the generalized solution to all these fing problems that these incessant fing pins?"
Part 1 of 2: the workflows. Part 2 adds the guard that keeps them this way.
Size: about 2,080 changed lines. 932 are one-for-one workflow line swaps (the same transform on 169 workflow files, proven by the round trip below); the rest are the tests that assert those exact lines and must change with them, so it is not split further.
Prior art: #32393 (per-size pools on main) and #32417 (pool copy check) landed the pools these reads use. #27114 (open) moves queued jobs off a stalled label only when their runs-on reads a pool, so this makes it apply to almost every job. #27440 and #27448 (open) change some macOS sizes on lines this touches; whichever lands second rebases.
Why
A
runs-onthat ends in a literalblacksmith-<N>vcpu-*label can never move: when that size stops starting jobs (2026-10-28, nightly.yml's 4 vCPU fallback), every run waits until someone edits the YAML. One declared runner set fixes that. Each size has its own pool in main's.github/runners.json(#32393), andscripts/ci/runner_pools.pywrites each pool's live member tovars.RUNNER_POOLSevery 10 minutes. A job that reads its measured size's pool,fromJSON(vars.RUNNER_POOLS).linux_8, follows the pool when it fails over, with no YAML edit. The live variable has had every per-size key since 15:28Z today.What
Each literal single-size label in a runner selection (
runs-on, matrix pools,*RUNNER*env mirrors, reusable-workflow runner inputs) becomes its size's pool:Kept as they were:
pull_requestrun gets no repository variables. Where a fork branch already exists (head.repo.full_name != github.repository && '<label>'), it keeps its literal and comes before any pool read. Where a workflow a fork can trigger had none, each pool read is wrapped as(<fork pull request> && '<old label>' || fromJSON(vars.RUNNER_POOLS).<pool>), so a fork resolves to exactly the label it resolved to before. Inside a fork branch's own operand, labels stay literal.== '<label>',contains(fromJSON('[...]'), ...)) are checks, not routes, and are unchanged.contains(fromJSON('[...]'), vars.CI_TRUSTED_RUNNER) && vars.CI_TRUSTED_RUNNER || 'blacksmith-4vcpu-ubuntu-2404'(pull_request_target, comment events, CLA, about 27 workflows) is runner trust policy: a pool read there would let whoever writes RUNNER_POOLS route the trusted token. It stays byte-for-byte as on base.cmux-next-guards.ymlsigning-runner-variables keeps its literal: it checks the runner variables, so its own route must not read them.scripts/ci/runner_routing_table.py'ssensitive: Apple/signing/notary secrets, codesign, notarytool, the signing keychain, release uploads) is left as it is. 42 such jobs in 15 workflows keep their routes. A pool read there would let whoever writes RUNNER_POOLS choose the machine that holds the keys. That is runner trust policy, and the release lane's own check (tests/test_ci_release_sdk_lane.sh) holds the release signer's literal fallback whole. Their pickers (pick-sign-runner and the like) hold no secret and do read pools. The light-Linux hosted signer lines intests/test_ci_self_hosted_guard.share unchanged.cancel-in-progressor concurrency group is touched.Proof the routing is unchanged: replacing every pool read with the literal it replaced (and unwrapping each fork wrap) turns all 466 changed workflow lines back into their base lines exactly. Every per-size pool's first member is that literal.
Tests that assert Blacksmith is absent (the nightly Blacksmith-only ratchet, the signer never-16/32 checks, the owned-only nightly checks) now also refuse the matching pool read, since every per-size pool is Blacksmith;
BLACKSMITH_LINUX_ONLY_DEBTis unchanged from base.Performance
Each pool's first member is the label the job named before, so routing is unchanged until a size stalls. After that, the job moves to the pool's next member instead of waiting.
.github/runners.jsonpools: first member = previous literalscripts/ci/runner_pools.pyreconcileTesting
All 147 tests that read workflows or runner routing (
tests/files namingruns-on,RUNNER_POOLS,blacksmith-or the touched workflows) ran on this head, plustests/test_ci_no_single_size_pins.py:9fde804c, the same tests in the same way:test_check_ghostty_zig_workflows(bashlex not installed),test_ci_cloud_probe_rescue,test_ci_fleet_rule_lints,test_ci_merge_main(needs git 2.46).test_ci_fast_checks_failovertimed out once under the parallel run and passes on its own, as it does on base.each pool read -> its old literal) reads back 466 of 466 changed workflow lines to base, the 2 others being the ci-guards step rename in part 2.Observed / Not run
Ran all the above locally with python3 and bash. Not run: the workflows themselves on GitHub (routing is unchanged until a pool fails over, by the round trip).
Changelog
none
Agent session: agent session
🤖 Generated with Claude Code