Skip to content

glaeda-cmux-runner-hook: take-root --switch and take-gui for cmux's E2E build - #1260

Merged
teamleaderleo merged 3 commits into
mainfrom
hook-take-gui
Sep 25, 2026
Merged

teamleaderleo merged 3 commits into
mainfrom
hook-take-gui

Conversation

@teamleaderleo

Copy link
Copy Markdown
Owner

Stacked on #1259 (which gives test-e2e's build the compile-gui class).

Why

On an owned mini, test-e2e's build holds the gui token for its whole job, about 15 min, but uses the console session only for its tests, about 1 min. It also can't adopt a product compiled at another canonical root. The job holds one root from admission, and take-root refuses a second, different root. In the E2E reuse misses I checked, one product compiled at /private/tmp/cmux-ci-2 was never adopted by a build holding /private/tmp/cmux-ci. This adds the two step-time helpers the cmux side needs. Nothing changes for any job until cmux calls them.

What

Both go through the existing glaeda-canonical-root shim.

  • take ROOT --switch.
    • The job waits for ROOT while still holding its current root, and lets the old one go only once ROOT is held. So it never holds two, and a timeout (exit 1) leaves it where it was. On success it writes the new CMUX_CI_CANONICAL_ROOT to $GITHUB_ENV.
    • It only works when every held root has a live holder of its own: one taken with take, or the admission root of a ROOT_SWITCHERS class. compile-gui is the only such class, and admission now hands its root to a separate <holder>-root-k.pid holder instead of the main one, which the main holder doesn't inherit. A root held by the main holder can't be let go (exit 2).
  • take-gui [--wait S].
    • Holds the gui token from that step to the end of the job, in a <holder>-gui.pid holder that job-completed releases. It does nothing when admission already gave the job gui.
    • Deadlock guard. A job in take-gui holds a root, and a gui job waiting in take-root holds gui: the opposite lock order. So take-root waiters write capacity/root-k.want-<pid>, which says gui when their job holds gui and is rewritten every second. take-gui exits 3 at once when a gui holder is waiting for a root this job holds. The caller then hands its tests to another job. Markers older than 10 s, or with a dead pid, are ignored and removed.
  • The shim gains take-gui. It is regenerated on fleet re-apply, while the hook file runs fresh for every job.

Unchanged: compile-gui still takes gui at admission. Dropping that is a follow-up once cmux's build calls take-gui before its tests; otherwise a build would test without the token.

Compatibility

  • An old shim answers take-gui with a usage error, exit 2. An old hook rejects --switch and take-gui through argparse, also exit 2. cmux has to treat 2 as "unsupported, fall back".
  • Rollout order: this PR and a fleet re-apply, then the cmux call sites, then the gui drop.

Review

An independent read-only review of 87f5561 found nothing blocking. It checked the fd inheritance across the two forks, the error paths, and the deadlock argument: every wait is bounded, --switch never holds two roots, and the gui-for-root two-party cycle is broken by the marker and exit 3. It found four smaller issues, all fixed in 19c3012:

  • a switch timeout left the job with no root while its environment still named the old one
  • a SIGKILLed holder's pid file passed the switch check
  • a recycled or foreign pid on a stale marker could force a false give-way
  • an unrecorded gui hold broke a second take-gui call
    The fixes are being re-reviewed on 19c3012.

Tests

  • New tests:
    • test_switch_swaps_a_producers_root_without_holding_two: timeout keeps the old root, env export, dead holder, admission-held root
    • test_take_gui_holds_the_token_for_the_rest_of_the_job
    • test_take_gui_gives_way_to_a_gui_job_waiting_for_its_root: real concurrent waiter, stale marker swept
  • The shim test covers the usage errors.
  • Results on 19c3012:
    • scripts/test-glaeda-cmux-runner.py: 155 OK
    • test-glaeda-fleet-status.py and test-glaeda-cmux-runner-fleet.py: OK

🤖 Generated with Claude Code

teamleaderleo and others added 3 commits September 25, 2026 15:47
Two step-time helpers for cmux's E2E build, behind the existing
glaeda-canonical-root shim:

- take ROOT --switch: lets go of the roots the job holds, then waits for
  ROOT, so a build that finds a product to reuse at another canonical root
  can move there without ever holding two roots. Only roots with a holder
  of their own can be let go: those from an earlier take, and the admission
  root of a ROOT_SWITCHERS class (compile-gui), which admission now hands
  to a separate holder (<holder>-root-k.pid) instead of the main one.
- take-gui [--wait S]: holds the gui token from that step to the end of the
  job (a <holder>-gui.pid holder, released by job-completed). A no-op when
  admission already gave the job gui. A job in take-gui holds a root while
  a gui job waiting in take-root holds gui, the opposite order, so take-root
  waiters leave capacity/root-k.want-<pid> markers and take-gui exits 3
  (gave way) at once when a gui holder waits for one of its roots.

compile-gui still takes gui at admission; dropping it waits for cmux's
build to call take-gui before its tests. The shim needs a fleet re-apply.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e is held

Review follow-ups for take-root --switch and take-gui:

- --switch waits for the new root while still holding the old one and
  lets go only once the new one is held, then writes the new
  CMUX_CI_CANONICAL_ROOT to $GITHUB_ENV. A timeout used to leave the job
  holding no root while its environment still named the old one.
- A switch needs a live holder for every held root, not just its pid file:
  a SIGKILLed holder's leftover file no longer lets a job hold two roots.
- Waiters rewrite their want marker every poll and take-gui ignores and
  sweeps markers older than 10 s, so a killed waiter whose pid is recycled
  (or belongs to another user) cannot make take-gui give way.
- take-gui releases the token and exits 1 when it cannot record holding it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s go

Re-review follow-up: the record no longer names a released root if the
hook dies mid-switch, and the ROOT_SWITCHERS comment matches the new order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo
teamleaderleo merged commit ef02350 into main Sep 25, 2026
4 of 6 checks passed
@teamleaderleo
teamleaderleo deleted the hook-take-gui branch September 25, 2026 20:17
teamleaderleo added a commit to manaflow-ai/cmux that referenced this pull request Sep 25, 2026
The build job's tests share an owned Mac's one console session, so glaeda
gives the job its gui token, today from job start, which keeps every other
GUI job off that Mac through the whole compile. The step that decides
whether the build tests now takes the token itself with glaeda's take-gui,
so glaeda can stop handing it out at job start (teamleaderleo/glaeda#1260):

- exit 0 (held, or already held from job start) or 2 (a hook without
  take-gui, which gave the token at job start): test here as before.
- exit 3 (a GUI job holding the token waits for this job's canonical root,
  so waiting would deadlock) or 1 (still taken after 300 s): leave the
  tests to the test job, which the late upload already feeds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit to manaflow-ai/cmux that referenced this pull request Sep 25, 2026
…ild (#14705)

The build job's tests share an owned Mac's one console session, so glaeda
gives the job its gui token, today from job start, which keeps every other
GUI job off that Mac through the whole compile. The step that decides
whether the build tests now takes the token itself with glaeda's take-gui,
so glaeda can stop handing it out at job start (teamleaderleo/glaeda#1260):

- exit 0 (held, or already held from job start) or 2 (a hook without
  take-gui, which gave the token at job start): test here as before.
- exit 3 (a GUI job holding the token waits for this job's canonical root,
  so waiting would deadlock) or 1 (still taken after 300 s): leave the
  tests to the test job, which the late upload already feeds.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
rajinsyed pushed a commit to rajinsyed/supermux that referenced this pull request Oct 3, 2026
…ild (#14705)

The build job's tests share an owned Mac's one console session, so glaeda
gives the job its gui token, today from job start, which keeps every other
GUI job off that Mac through the whole compile. The step that decides
whether the build tests now takes the token itself with glaeda's take-gui,
so glaeda can stop handing it out at job start (teamleaderleo/glaeda#1260):

- exit 0 (held, or already held from job start) or 2 (a hook without
  take-gui, which gave the token at job start): test here as before.
- exit 3 (a GUI job holding the token waits for this job's canonical root,
  so waiting would deadlock) or 1 (still taken after 300 s): leave the
  tests to the test job, which the late upload already feeds.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant