ci: cmux_next_ daemon tests take a free owned Mac, else Blacksmith macOS 15

Merged
TE
10d ago
+167-5

The cmux_next_ daemon tests (macOS) job gates nightly-next promotion. Attempt 1 of a feat-cmux-next push sent it to the owned side lane glaeda-side-std-xcode-26.6, and it queued there behind everything else on that label.

Evidence (2026-10-26)

  • Run 40397154574 (4881e357): the daemon tests have been queued on glaeda-side-std-xcode-26.6 since 22:19Z, 75+ minutes and counting.
  • Run 40419603252 (tip 23802b0a): its daemon tests are queued the same way.
  • Promotion tick 40420216032 at 23:33Z refused 22 commits, 10 of them with "daemon tests have not passed". nightly-next is still on 76b6e0de, promoted at 21:20Z.

Change

  • A new job, cmux-next-daemon-tests-runner, runs on Blacksmith Linux 2 vCPU, has a 5-minute timeout and continue-on-error. It carries the same if: as the tests, so the tests are never skipped for want of it. For a feat-cmux-next push it picks the label at queue time with scripts/ci/e2e_runner_pool.py --requested auto, the picker cmux-next-dev-daily.yml already uses. That picker names an owned Mac only when one is free now; otherwise the job falls back to Blacksmith macOS 15, never the nightly's macOS 26 labels.
  • cmux-next-daemon-tests takes that pick first on attempt 1 of a feat-cmux-next push. The declared CI_NEXT_DAEMON_POOL / CI_NEXT_PROMOTE_POOL slot and the rest of the existing chain stay as the fallback when the pick fails (empty output). Every other context routes exactly as before.
  • Routing order: Linux is not possible yet, because a Linux run writes no daemon marker. #25758 moves the tests to Linux and will rebase onto this PR. Until then the order is a free owned Mac, then Blacksmith macOS last.

Before / after

  • Before: daemon tests queued 75+ minutes on one saturated owned label, and promotion was blocked.
  • After: a free owned Mac or Blacksmith macOS 15 is chosen when the job queues, so the tests start within minutes.

Tests

  • tests/test_ci_tui_routes_avoid_nightly_label.py gains test_daemon_tests_take_the_pickers_free_runner_first. It covers every owner, event, ref and attempt, with the pick both owned and Blacksmith and the declared pool both set and unset, and checks the route never hits the nightly label.
  • tests/test_tui_publish_workflow_security.py gets the exact route string with the pick slot, plus checks on the pick job's shape.
  • These pass locally: test_tui_publish_workflow_security, test_ci_tui_routes_avoid_nightly_label, test_cmux_tui_publisher_testing, test_cmux_tui_daemon_tests_linux, test_ci_nightly_off_blacksmith, test_supplychain_security, test_ci_runs_on_fallback, test_runner_label_policy, test_ci_check_repo_variables.
  • test_ci_fork_runner_routing shows the same 3 failures as base, with none in this file. actionlint reports nothing new.

Risk

  • Low. If the pick job fails or times out, the label is empty and the route is exactly today's.
  • The pick job uses the existing ci-routing-agent environment and glaeda-route App token (read-only runner scopes), which other jobs in this workflow already use.
  • cmux_tui_publisher_testing.py still compares against DAEMON_POOL only when it is set, and DAEMON_POOL is unset today.

Agent session: agent session

šŸ¤– Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.