ci(nightly): the all-nightly reservation's idle runners take nightly-next's light jobs
"Place the light jobs on a free mini", at the end of build-nightly-app, only offers glaeda-side-* labels. The all-nightly reservation's light runners (glaeda-nightly-only-m4pro, four per dedicated Mac) exist for these jobs, but they never qualified. So on every nightly-next run the step waited its full three minutes on busy side minis, re-reading runners every 30 s, and then sent prepare-nightly-variant-primary, prepare-nightly-variant and await-nightly-tree-marker to Blacksmith anyway.
That wait sits on the path from landing to feed, and the rule allows 30 minutes for that path (the feed was about 45 min behind tonight).
Change (scripts/ci/portable_job_placement.py and the step's env in nightly.yml):
- New
NIGHTLY_ONLY_LABEL(vars.CI_NIGHTLY_ONLY_RUNNER). On a nightly placement whose runners were read, attempt 1 only (the same attempt rule, factored intoattempt_refusal), the jobs take the reservation's idle runners at once. - Idle runners are counted less the jobs the snapshot shows queued on that label. The warm builder carries only
glaeda-nightly-only-m4pro-builder, so it is never counted. - When the reservation is unset, busy or unread, or on a later attempt, the existing side, wait and Blacksmith logic runs unchanged.
- The three jobs use no secrets and no environment, and the reservation already admits nightly.yml jobs on nightly-next (decide, resolve and "build nightly inputs" run there today).
Performance
| metric | before | after | delta | harness or run link |
|---|---|---|---|---|
| "Place the light jobs on a free mini" duration | 186 s (runs 41354494707, 41355147140, 41356701375) | under 15 s (run 41360732074: the three jobs took glaeda-nightly-only-m4pro) | about -3 min per build | build-nightly-app step timings |
| runner reads in that step | about 42 REST requests (github_spend) | 4 requests (run 41360732074) | about -38 requests per run | github_spend lines |
Tests:
tests/test_ci_portable_job_placement.py: 36 pass, including new NightlyOnly cases for placement, the queue count, never the builder, the busy, unread, unset and later-attempt fallbacks, and the workflow wiring.tests/test_ci_nightly_off_blacksmith.py: 21 pass.test_ci_linux_single_sizefails the same way on base (cmux-next-base-tier-kick, cmux-next-dev-kick, ios-internal-nightly-trigger).
Agent session: agent session
š¤ Generated with Claude Code