ci(next): the tip suite dispatcher also runs the daemon suite on the feat-cmux-next tip

TE
7d ago
+283-73

Problem

A feat-cmux-next push never runs cmux-next daemon tests. As a result, the base has had no daemon-test verdict for hours, and scripts/ci/base_red_excuse.py (via test_reds.py) refuses every pull request's daemon red with "no completed feat-cmux-next run of its workflow has a verdict". This blocks #27692, #27868 and others. The only base logs so far came from hand dispatches.

Change

The tip suite dispatcher (cmux-next-tip-swift-suite-dispatch.yml) runs the daemon suite the same way it runs the Swift suite. It gets a matrix leg per suite (swift, daemon), and each leg keeps its own cadence:

  • The daemon leg asks cmux-next.yml on refs/heads/feat-cmux-next for a tip_daemon_suite run.
  • It dispatches right away when the diff since the last daemon verdict reaches the router's daemon tier (cmux_next_route.py daemon=). This uses the same router step as Swift, now reading the leg's own tier.
  • It also dispatches once the tip is 20 landings past the last daemon verdict, whatever changed, so the base log stays fresh.
  • A green per tested commit is reused: a tip that already has a verdict is never run again. A tip with no daemon-tier change since the last green is not run until the 20-landing floor.
  • Runs are matched by name (cmux-next tip daemon suite · <tested sha>), and the tested commit is read from the name. A same-tree run that tests a recorded sha after the tip moved still counts for that sha.
  • At most one run per suite per tick, never while one is in flight or one started in the last 25 minutes. A tip with no verdict is retried at most 3 times.
  • Until the companion feat-cmux-next PR lands, the tip's cmux-next.yml refuses tip_daemon_suite (HTTP 422). The daemon leg warns on that instead of failing the tick.

There are no new permissions or secrets. The job keeps its existing actions: write / contents: read and its existing runner expression.

Companion PR on feat-cmux-next: the tip_daemon_suite input, its tree-wait handling, and the base_red_excuse.py lookup (linked in a comment below).

Performance

Runner minutes added per base push (estimate). The daemon-test job took 9 to 13 minutes in the hand dispatches 41024114885 and 41001517417. The base gets about 30 pushes an hour, and the daemon leg starts at most 2 runs an hour.

metricbeforeafterdeltaharness or run link
Mac runner-minutes per base push (daemon-test)0≤ 0.9 (≤ 2 runs/h × ~13 min ÷ ~30 pushes/h)+≤ 0.9runs 41024114885, 41001517417
Linux runner-minutes per tick (dispatcher)~1 (one leg)~2 (two legs)+~1 per 30 minthis workflow
Base daemon-test verdict ageunbounded (hours, hand dispatch only)≤ ~1 h after a daemon-tier landing, ≤ 20 landings otherwisen/aplan tests

Tests

python3 tests/test_cmux_next_tip_swift_suite_dispatch.py passes. New cases cover:

  • daemon dispatch inputs
  • swift and daemon runs never standing in for each other
  • the tested sha read from the name, not head_sha
  • a skipped daemon job counts as no verdict
  • the 20-landing floor (and Swift has none)
  • per-suite cadence
  • the 422 warning

Existing Swift cases are unchanged.

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.


Summary by cubic

Makes the tip suite dispatcher also run the daemon suite on feat-cmux-next, so base pushes get a daemon-test verdict for base_red_excuse.py to compare pull request daemon reds against. Previously feat-cmux-next never ran daemon tests, leaving PRs like #27692 and #27868 blocked.

Changes

  • The dispatcher gets a matrix leg per suite (swift, daemon), each with its own cadence and one run per tick.
  • The daemon leg dispatches tip_daemon_suite when the router's daemon tier is reached, and also once the tip is 20 landings past its newest verdict — red or green — whatever the diff.
  • Runs are matched by name and their tested commit, so a same-tree run still counts.
  • A daemon run whose tree was still publishing (daemon-test skipped) is pending for 90 minutes, letting its same-tree run give the verdict; past that it is retried as a lost run. Swift has no deferred state.
  • Only the unknown-input 422 warns; any other dispatch failure fails the tick.
  • The owned-pool rescue now wakes on a failed tip daemon suite run when it completes.
  • No new permissions or secrets.

Summary by CodeRabbit

  • Chores
    • CI tracks Swift and daemon test suites independently, using suite-specific results and change routing.
    • Daemon checks are dispatched when the tip is at least 20 commits past the newest verdict. Skipped daemon checks may be deferred for up to 90 minutes while the tree publishes; skipped Swift checks are retried immediately.
    • A refusal to dispatch a daemon check is reported as a warning; other dispatch errors remain errors.
    • Failed daemon-suite runs are now recognized by the CI rescue workflow.