ci(cmux-next): route GUI jobs off a gui/session pool with no room
Leo: "Bro, I thought we already had logic to automatically route stuff. How can we still have pins like this? I hate pins. Like, just pin the set of the stuff that isn't hilariously slow. Like most of what GitHub has is hilariously slow. We can't be using them."
GUI/session placement previously chose any online owned role label even when all its runners were busy and its queue was deeper than overflow's. Rescue bot reruns could then return to the same queue. The #26809 incident left Swift and daemon tests waiting more than 45 minutes.
Placement now weighs queued jobs against online runners and Blacksmith's queue, emits gui_overflow when the GUI pool has no room, and checks the optional session lane the same way. The three GUI jobs accept overflow only from their current placement attempt. Rescue bot attempts leave fixed GUI/session labels; a person's rerun retains its owned route. Autofix exports use the same bot/person distinction.
Updated onto feat-cmux-next at f8b0183ff86b6f6a880ead08a5ae589049a8024b. Base's Seen.owned holds oldest wait minutes for its side-route dead-end logic. This PR keeps that data and adds owned_queued for queue counts, with coverage distinguishing the two units. Both sets of fallback tests survive the merge.
Risk: CI routing only. No new dispatch, cancellation, permissions, trust boundary, repository variable or service change. Placement uses its existing snapshot read once. No new timer or loop. GUI_OVERFLOW remains the existing cascade macOS route; #27129 owns the shared runner-pool migration.
Validation
python3 tests/test_ci_side_lane_placement.py: 71 passed, including saturation, session lane, rescue rerun, carried outputs and count/wait separation.python3 tests/test_ci_runs_on_fallback.py: 16 passed.python3 tests/test_ci_next_macos_cascade.py DeadEndRoute: 5 passed, preserving base's wait-duration behavior and verifying snapshot queue counts separately.- The same behavioral placement probe on base and head: 3 busy GUI runners, 5 queued jobs, empty overflow queue. Base selected the saturated owned label (red); head selected overflow (green).
python3 scripts/cmux-next/prepush-gate.py: no new violations.git diff --check f8b0183ff86b6f6a880ead08a5ae589049a8024b HEAD: clean.- actionlint: the two changed autofix workflows pass;
cmux-next.ymlhas the same existing 11-inputworkflow_dispatcherror on base and head.
Observed / Not run
Observed: portable placement and workflow-expression tests above. Additional workflow structure/session/rescue checks and exact-head independent review are in progress. Not run: a live saturated-pool placement or native build; this change has no native code. Existing workflows own automatic PR CI; no duplicate dispatch.
Changelog
none
Agent session: agent session