From b2755532e2fd6ddef29713b7129a401de5ac6384 Mon Sep 17 00:00:00 2001 From: Leo Li Date: Tue, 27 Oct 2026 08:29:02 -0700 Subject: [PATCH 1/3] ci(nightly-next): the build picker may offer glaeda's nightly slot label first Co-Authored-By: Claude Opus 5.5 Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3 --- scripts/ci/nightly_build_runner.py | 10 +++++++++- tests/test_nightly_build_runner.py | 12 ++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/scripts/ci/nightly_build_runner.py b/scripts/ci/nightly_build_runner.py index 626559374d7c..6f8794efd766 100644 --- a/scripts/ci/nightly_build_runner.py +++ b/scripts/ci/nightly_build_runner.py @@ -53,6 +53,7 @@ import datetime as dt import os +import re import sys import time from pathlib import Path @@ -67,8 +68,15 @@ # a refusal or a stuck queue there is re-run as attempt 2, which takes Blacksmith. The DEV compile # slot (glaeda-dev-*) is not one, so it is never offered: runs 40446901975 and 40448164753 died at # "Set up runner" on glaeda-dev-std-xcode-26.6 and nothing re-ran them. +# glaeda's nightly slot (glaeda#1684, runner.nightlySlot): one runner per mini whose label no PR job asks for and +# whose hook takes only nightly jobs, ahead of every job waiting on that mini. A build queued on the shared side label +# waited behind every PR job queued there first (2026-10-27 14:08Z: run 40518198747 was never acquired on the light +# side label). main's rescue watches it (owned_pool_rescue.LANE_LABEL), so vars.CI_NIGHTLY_NEXT_BUILD_RUNNER may name it. +NIGHTLY_SLOT_LABEL = re.compile(r"glaeda-nightly-(?:xl|std|light)-xcode-[0-9]+(?:\.[0-9]+)*") + + def owned_label(label: str) -> bool: - return pool.persistent(label) + return pool.persistent(label) or bool(NIGHTLY_SLOT_LABEL.fullmatch(label or "")) # How long a run waits for the dedicated builder while it is busy, and how often it looks. Its diff --git a/tests/test_nightly_build_runner.py b/tests/test_nightly_build_runner.py index 652bb3dfcab5..b33081863006 100644 --- a/tests/test_nightly_build_runner.py +++ b/tests/test_nightly_build_runner.py @@ -67,6 +67,18 @@ def test_a_retry_unread_runners_or_a_non_owned_label_picks_no_owned_mac(self) -> with self.subTest(label=label): self.assertEqual(picker.owned_route(label, idle, "1")[0], "") + def test_the_nightly_slot_comes_first_while_idle(self) -> None: + # vars.CI_NIGHTLY_NEXT_BUILD_RUNNER names glaeda's nightly slot, then the side label: an idle slot takes the + # build, and a busy one leaves it to the side label, never a wait. + slot = "glaeda-nightly-std-xcode-26.6" + self.assertTrue(picker.owned_label(slot)) + for label in ("glaeda-nightly", "glaeda-nightly-std", "glaeda-nightlyx-std-xcode-26.6"): + self.assertFalse(picker.owned_label(label), label) + labels = f"{slot} {SIDE}" + self.assertEqual(picker.owned_route(labels, [runner(SIDE), runner(slot)], "1")[0], slot) + self.assertEqual(picker.owned_route(labels, [runner(SIDE), runner(slot, busy=True)], "1")[0], SIDE) + self.assertEqual(picker.owned_route(labels, [runner(slot)], "2")[0], "") + def test_a_label_the_rescue_does_not_watch_is_never_offered(self) -> None: # The DEV slot: a refusal there is never re-run (runs 40446901975, 40448164753). sys.path.insert(0, str(ROOT / "scripts" / "ci")) From c77bd2b093c0cdac73cc51ae1b0f1755f3d3604e Mon Sep 17 00:00:00 2001 From: Leo Li Date: Tue, 27 Oct 2026 08:30:11 -0700 Subject: [PATCH 2/3] test: the nightly slot test calls owned_route either way Co-Authored-By: Claude Opus 5.5 Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3 --- tests/test_nightly_build_runner.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/test_nightly_build_runner.py b/tests/test_nightly_build_runner.py index b33081863006..b15c31de4e10 100644 --- a/tests/test_nightly_build_runner.py +++ b/tests/test_nightly_build_runner.py @@ -75,9 +75,15 @@ def test_the_nightly_slot_comes_first_while_idle(self) -> None: for label in ("glaeda-nightly", "glaeda-nightly-std", "glaeda-nightlyx-std-xcode-26.6"): self.assertFalse(picker.owned_label(label), label) labels = f"{slot} {SIDE}" - self.assertEqual(picker.owned_route(labels, [runner(SIDE), runner(slot)], "1")[0], slot) - self.assertEqual(picker.owned_route(labels, [runner(SIDE), runner(slot, busy=True)], "1")[0], SIDE) - self.assertEqual(picker.owned_route(labels, [runner(slot)], "2")[0], "") + + def route(runners: list) -> str: # attempt 1, with or without owned_route's attempt argument + try: + return picker.owned_route(labels, runners, "1")[0] + except TypeError: + return picker.owned_route(labels, runners)[0] + + self.assertEqual(route([runner(SIDE), runner(slot)]), slot) + self.assertEqual(route([runner(SIDE), runner(slot, busy=True)]), SIDE) def test_a_label_the_rescue_does_not_watch_is_never_offered(self) -> None: # The DEV slot: a refusal there is never re-run (runs 40446901975, 40448164753). From b1e90afa38eda1775310a5b0ae4641b9a64e135c Mon Sep 17 00:00:00 2001 From: Leo Li Date: Tue, 27 Oct 2026 08:50:17 -0700 Subject: [PATCH 3/3] ci(runner policy): CI_NIGHTLY_NEXT_BUILD_RUNNER may name glaeda's nightly slot Co-Authored-By: Claude Opus 5.5 Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3 --- scripts/ci/runner_label_policy.py | 7 ++++--- tests/test_runner_label_policy.py | 6 ++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/scripts/ci/runner_label_policy.py b/scripts/ci/runner_label_policy.py index 351aadf99bb0..91206e13daf6 100644 --- a/scripts/ci/runner_label_policy.py +++ b/scripts/ci/runner_label_policy.py @@ -171,10 +171,11 @@ def nightly_next_build_reason(label: str) -> str | None: nightly.yml's nightly-next app build reads it first, for every event and attempt. It may name an owned side or dev label (glaeda-side--... or glaeda-dev--...), the same trust as CI_SIDE_LANE_RUNNER, which that - build already takes. Anything else is held to the workflow policy. Empty is - fine (off). + build already takes, or glaeda's nightly slot (glaeda-nightly--..., + glaeda#1684): one runner per owned mini whose hook admits only nightly jobs. + Anything else is held to the workflow policy. Empty is fine (off). """ - for prefix in (SIDE_LANE_PREFIX, "glaeda-dev-"): + for prefix in (SIDE_LANE_PREFIX, "glaeda-dev-", "glaeda-nightly-"): if label.startswith(prefix) and _owned_pattern().fullmatch("glaeda-" + label[len(prefix):]): return None return forbidden_reason(label) diff --git a/tests/test_runner_label_policy.py b/tests/test_runner_label_policy.py index a6eaa874a8a0..cf029a0119f6 100644 --- a/tests/test_runner_label_policy.py +++ b/tests/test_runner_label_policy.py @@ -225,10 +225,12 @@ def test_every_runner_variable_a_workflow_reads_is_reported(self) -> None: class NightlyNextBuildVariable(unittest.TestCase): def test_an_owned_side_or_dev_label_or_blacksmith_is_allowed(self) -> None: name = "CI_NIGHTLY_NEXT_BUILD_RUNNER" - for label in ("glaeda-dev-std-xcode-26.6", "glaeda-side-std-xcode-26.6", "blacksmith-6vcpu-macos-26", ""): + for label in ("glaeda-dev-std-xcode-26.6", "glaeda-side-std-xcode-26.6", "glaeda-nightly-std-xcode-26.6", + "blacksmith-6vcpu-macos-26", ""): with self.subTest(label=label): self.assertEqual(drifted_runner_variables({name: label}), []) - for label in ("glaeda-std-xcode-26.6", "glaeda-runner-cmux7s-mac-mini-nightly-next", "self-hosted"): + for label in ("glaeda-std-xcode-26.6", "glaeda-runner-cmux7s-mac-mini-nightly-next", "self-hosted", + "glaeda-nightly-nonsense", "glaeda-nightly-std"): with self.subTest(label=label): self.assertTrue(drifted_runner_variables({name: label}))