ci(cmux-next): route GUI jobs off a gui/session pool with no room

Merged
TE
6d ago
+493-20

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.yml has the same existing 11-input workflow_dispatch error 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