fix(ci): keep nightly controls on fleet when routing reads fail
When the routing App exhausts its quota, early NEXT nightly placement currently emits no fleet route and sends portable controls to Blacksmith. Keep those controls on the configured owned-mini pool when runner capacity or the queue snapshot cannot be read. Preserve runner eligibility and attempt checks; Linux-only signer compilation cannot take a mini.
Leo: “FOR OUR NIGHTLIES ARE THEY END TO END ON OUR FLEET? WE CAN'T BE RELYING ON BLACKSMITH THAT CUTS OUT”.
This fixes the quota fallback, building on #29864. It does not establish a reservation or bounded 180-second no-start overflow, and does not move signer-build or credential-bearing jobs. Unknown fleet capacity can queue controls; separate admission work must provide a start receipt before overflow. Existing caches and warm sources are unchanged; no native compile is added.
Validation: python3 tests/test_ci_portable_job_placement.py </dev/null reproduces five failing assertions at regression commit 69d3fce30e65 and passes all 28 tests at 750fe9f9323841e7d56cf496e7b189bc40921089. Coverage includes unread/stale capacity, deadline cleanup, Linux-only exclusion, invalid labels, rerun eligibility and non-nightly behavior.
Observed / Not run
Observed: focused Python policy tests pass. No live nightly has exercised this commit yet. Full fleet build and end-to-end no-start overflow verification were not run for this small fallback change.
Performance
| Metric | Before | After | Delta | Harness or source |
|---|---|---|---|---|
| Portable controls sent to Blacksmith on unread capacity | 5 | 0 | -5 selections | Same deterministic placement fixture |
| Blacksmith minutes/day | Not measured | Not measured | Not claimed | Telemetry pending deployment |
Changelog
none
Agent session: agent session
🤖 Generated with Claude Code