Repository navigation
ci(rescue): move every nightly.yml sign, verify and DMG job off a stalled Blacksmith macOS label - #26534
Conversation
…lled Blacksmith macOS label The signing-stall rescue's table missed nightly-next's signer-dmg-image and signer-verify, so run 40585960129's signer-verify sat on blacksmith-6vcpu-macos-26 for 78 minutes and, counted as unfinished work, kept the run's stalled final-DMG verify where it was too. Main's classic nightly was not covered at all. - NIGHTLY_SIGN_ALTERNATES gains signer-dmg-image and signer-verify, and takes several alternate-label expressions per job (main's classic one checks the pick's own attempt). Main's nightly attempt 1 gets the same signing watch. - A job pinned to a nightly's reserved runner other than the app build (main's prepare-nightly-variant legs, #26494) waits RESERVED_FOLLOWER_SECONDS (5 min) at most, then moves like a stuck job; the build's own wait stays untimed. - A main nightly whose app build succeeded is not made moot by main moving on (pull_moved()): its failed jobs are re-run instead of the run being left cancelled. A newer run pending behind it still wins. - owned_pool_sources.uncovered_sign_jobs(): tests/test_ci_owned_pool_sources.py derives the sign, verify and DMG jobs that can sit on a Blacksmith macOS label from both branches' nightly.yml and fails when main's rescue cannot move one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3
|
Owned by an agent session · session |
|
All contributors have signed the CLA ✍️ ✅ |
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Reserved-runner follower handling scripts/ci/owned_pool_rescue.py, tests/test_ci_owned_pool_rescue.py |
The reserved build remains untimed. Other jobs pinned to its runner become stuck after five minutes in the queue. Main nightly runs with a successful app build are not treated as moot solely because main moved. Tests cover follower rescue, build watching, and main nightly reruns. |
Cross-branch signing-stall rescue scripts/ci/owned_pool_rescue.py, scripts/ci/owned_pool_sources.py, tests/test_ci_owned_pool_rescue.py, tests/test_ci_owned_pool_sources.py |
Signing-stall checks now apply to qualifying nightly runs on both branches and accept any configured alternate-label expression. Source checks detect signing, verification, and DMG jobs and report missing rescue-table coverage. Tests cover alternate routes and source detection. |
Priority:
Estimated code review effort: 3 (Moderate) | ~25 minutes
Change: Bug fix
Sequence Diagram(s)
sequenceDiagram
participant NightlyWorkflow
participant RescueWatch
participant NIGHTLY_SIGN_ALTERNATES
participant SigningJobs
NightlyWorkflow->>RescueWatch: Starts a qualifying nightly watch
RescueWatch->>NIGHTLY_SIGN_ALTERNATES: Checks configured alternate label expressions
RescueWatch->>SigningJobs: Retries stalled jobs with alternate labels
Possibly related issues
manaflow-ai/cmux#25921— The PR adds a nightly workflow-to-rescue-table coverage test for signing, verification, and DMG jobs.manaflow-ai/cmux#26038— The PR keeps the nightly app build untimed while adding a timeout for reserved-runner followers.manaflow-ai/cmux#26172— The PR changes reserved-runner rescue behavior and preserves the app build as the untimed exception.manaflow-ai/cmux#26190— The PR changes reserved-runner rescue behavior and preserves the app build as the untimed exception.manaflow-ai/cmux#13807— The PR detects nightly signing jobs and checks that the rescue table covers them.
Suggested reviewers: lawrencecchen, austinywang
Merge Risk: 
Minimal · up to df59e
-
The supplied evidence identifies no issue that prevents merging after normal checks.
Pre-merge checks: 
24 · 
1
-
Failed checks: 1 warning Passed checks: 24 passed-
Full details: Description check
-
Explanation
The description clearly explains the problem, behavior changes, implementation, tests, proof, deployment, and risk. It omits the template's Changelog and Checklist sections, but the remaining content is sufficiently complete for this CI-only change.
Full details: Cmux Cloud Persistent Session And Early Input
-
Explanation
PASS: The pull request changes only nightly CI rescue logic and its tests in four files. The diff introduces no Cloud terminal creation, cmux-tui transport, manual renderer, Ghostty runtime, input routing, snapshot, authentication, revision, or lease behavior covered by the rule.
Full details: Cmux Browser Automation Off-Main
-
Explanation
PASS: The pull request changes only CI Python scripts and their Python tests. It does not change
Sources/TerminalController.swift,ControlCommandExecutionPolicy.swift, or any Swift browser automation routing. The diff contains nobrowser.*, WebKit, AppKit, socket-worker, or main-actor automation changes.
Full details: Cmux Expensive Synchronous Load
-
Explanation
PASS: The pull request changes only Python CI scripts and Python tests. It adds no production Swift code and does not add or move any synchronous agent-history load onto a main-actor or interactive path.
Full details: Cmux Cache Substitution Correctness
-
Explanation
PASS: The pull request changes only Python files under scripts/ci and tests. It introduces no production Swift, TypeScript, or JavaScript change, so the cache-substitution correctness check does not apply.
Full details: Cmux No Hacky Sleeps
-
Explanation
PASS. The diff adds no sleep, timer, delayed dispatch, or new polling loop.
RESERVED_FOLLOWER_SECONDSis an explicit queue-rescue timeout in the existingassess()state machine. It triggers cancellation and rerun only for queued reserved-runner followers, while started jobs and the app build remain protected. Tests cover the threshold and these exceptions.
Full details: Cmux Algorithmic Complexity
-
Explanation
No algorithmic-complexity violation is introduced. The new scans operate on bounded GitHub Actions workflow data, not user-owned records: nightly variants are explicitly limited to one or three values, and the rescue table has ten static entries.
app_built()is a single pass over jobs. The small nested checks inassess()anduncovered_sign_jobs()compare bounded workflow/job collections. The new source-inspection helpers are used only by tests in this repository and are not hot UI, socket, search, or persistence paths.
Full details: Cmux Swift Package Boundaries
-
Explanation
The pull request changes only four Python files under scripts/ci and tests/. The authoritative diff contains no Swift files or Swift package targets, so the Swift package-boundaries rule is not applicable.
Full details: Cmux Swiftpm Lockfiles
-
Explanation
PASS: The pull request changes only Python rescue logic and Python tests (
scripts/ci/*.pyandtests/*.py). It does not change a SwiftPM package, Xcode project,.gitignore, workflow, dependency declaration, orPackage.resolvedfile. The SwiftPM lockfile policy is therefore not applicable.
Full details: Cmux Swift Logging
-
Explanation
The pull request changes only Python CI scripts and Python tests. It changes no Swift, Objective-C, or runtime application files, and adds no prohibited logging calls or diagnostics. The Swift logging check therefore has no applicable failure.
Full details: Cmux User-Facing Error Privacy
-
Explanation
PASS. The diff changes only CI rescue logic, CI source inspection, and tests. The production path is
.github/workflows/ci-owned-pool-rescue.ymlrunningpython3 scripts/ci/owned_pool_rescue.py; its output is an operator CI log and step summary, not a cmux product UI, CLI, or API response. The added diagnostics name CI jobs, Blacksmith runners, labels, and workflow expressions, which the rule explicitly allows for internal CI and operator diagnostics. No changed text exposes secrets, credentials, tokens, private data, raw upstream errors, or unredacted payloads.
Full details: Cmux Full Internationalization
-
Explanation
The PR changes only CI rescue scripts and their tests:
scripts/ci/owned_pool_rescue.py,scripts/ci/owned_pool_sources.py, and two test files. It adds operational Python logic, comments, and test messages. It does not change Swift text, string catalogs, Info.plist files, web UI, locale data, API responses, rendered markdown, or changelogs.
Full details: Cmux Swiftui State Layout
-
Explanation
PASS: The pull request changes only four Python files: scripts/ci/owned_pool_rescue.py, scripts/ci/owned_pool_sources.py, and two Python test files. No Swift or SwiftUI code changed, so the SwiftUI state and layout failure conditions do not apply.
Full details: Cmux Swift Auxiliary Window Close Shortcuts
-
Explanation
PASS: The pull request changes only Python CI scripts and Python tests. The authoritative diff contains no Swift changes and no standalone cmux-owned window code, so the auxiliary-window close-shortcut rule does not apply.
Full details: Cmux Source Artifacts
-
Explanation
The pull request changes only two hand-written CI source files and two test files. The diff adds rescue logic, source inspection helpers, and focused test fixtures. No logs, screenshots, recordings, temporary folders, caches, dependency checkouts, build output, or broad artifact directories appear in the changed-path inventory.
Full details: Cmux No Test Or Debug Seam In Production Source
-
Explanation
The pull request changes only Python files under scripts/ci and tests. It changes no Swift file under a production Sources/ path, so the specified production-source test/debug seam condition does not apply.
-
Full details: Docstring Coverage
-
Explanation
Docstring coverage is 70.59% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 17 functions across 4 files.
Resolution
Write docstrings for the functions missing them to satisfy the coverage threshold.
-
Finishing Touches: 💡 1
-
📝 Generate docstrings: 💡
-
- Commit to this branch
- Create a new PR
🧪 Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands.
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Merge receipt for |
sr2's order: "Rescue gap on nightly-next: ci-owned-pool-rescue's include_blacksmith_macos covers cmux-next.yml only, so a nightly.yml job stalled on a Blacksmith macOS label is never moved. Today run 40585960129 had signer-verify queued on blacksmith-6vcpu-macos-26 for 3 h+, and 40610802228's sign job has been queued since 01:16Z. Please extend include_blacksmith_macos (or the equivalent) to nightly.yml's sign, verify and dmg-image jobs. That's the queue bound for the Linux signing path, since GitHub has no queue timeout."
Leo, 2026-10-27: "a waiting nightly, promote or nightly sign/verify job is admitted on a mini ahead of every PR, DEV and side job"; the routing order ends at Blacksmith macOS ("IT WAS ALWAYS FUCKING LAST RESORT"), and no job waits on one reserved machine.
Problem
For nightly.yml, the code that does what include_blacksmith_macos does for cmux-next.yml is the signing-stall rescue (
NIGHTLY_SIGN_ALTERNATES,signing_stall()). It had three gaps:blacksmith-6vcpu-macos-26from 00:34 to 01:52Z. Because it was not in the table it counted as unfinished work, so the run's stalledVerify final nightly DMG (arm64)was not moved either.pick-classic-sign-runner, which also checks the attempt that made the pick).The coordinator added a fourth item for this file, a blocking finding on #26494: main's prepare-nightly-variant legs will be pinned to the trusted mini right after the build. Main's push nightlies run in parallel, so a newer push's build can take that mini first. The rescue never moved a job waiting on a reserved runner, so the legs would sit behind a full build with no fallback.
Change (
scripts/ci/owned_pool_rescue.py,scripts/ci/owned_pool_sources.py)NIGHTLY_SIGN_ALTERNATESgainssigner-dmg-imageandsigner-verify. Each entry now takes a tuple of alternate-label expressions, so main's classic expression counts too.Target.signs_late: main's nightly attempt 1 gets the same signing-stall watch as nightly-next. Main's later attempts are unchanged, because a full re-run there builds the app again.reserved_follower()) now waits at mostRESERVED_FOLLOWER_SECONDS(5 min). After that it moves like a stuck job: the run is cancelled, then its failed jobs are re-run, and the re-run takes the Blacksmith fallback. The build's own wait stays untimed. A started job is still never cancelled: if any job of the run is running, the follower keeps waiting.pull_moved(): a main nightly whose app build succeeded (app_built()) is no longer treated as moot when main moves on. It used to be cancelled without a re-run, which threw away the build. Now its failed jobs are re-run. A newer run pending behind it in a shared group still wins, as before.signing_stall()acts only when every other job of the run has finished, andstarted_nightly_work()/nightly_cancel()re-check right before the cancel.Test: derived from nightly.yml, not hard-coded
tests/test_ci_owned_pool_sources.py::test_every_nightly_sign_verify_and_dmg_job_on_blacksmith_macos_is_rescuedreads main's rescue table (AST,sign_table()) and checks it against both branches' nightly.yml (the working tree plus origin/feat-cmux-next, fetched under Actions as the file already does). It finds every job whose id matches sign, verify or dmg and whose runs-on can name a Blacksmith macOS label (a literal orvars.MACOS_RUNNER_26; theCI_CLOUD_OVERFLOW_SAVEDoutage literal is ignored). It fails when such a job is missing from the table, or when its runs-on has none of the table's alternate-label expressions. Mutation check: removingsigner-dmg-imagefrom the table fails the test for origin/feat-cmux-next. The test already runs in ci-guards ("Validate that the persistent-pool rescue watches every owned-pool workflow"), so it is blocking on main.#26491 (merged) removed signer-verify from feat-cmux-next. The derived list follows that change automatically; the table entry stays for runs still in flight.
Proof (replay of run 40585960129's real jobs at 01:44Z, head efc7808's nightly.yml)
watch | Verify final nightly DMG (arm64) queued on blacksmith-6vcpu-macos-26 ... but signer-verify not finished; cancelling the run would lose that work, so it is not rescued on this lookstalled | Verify final nightly DMG (arm64), signer-verify queued on blacksmith-6vcpu-macos-26 with no runner past the 600s Blacksmith stall time, and every other job of the run has finishedTests
tests/test_ci_owned_pool_rescue.py: 335 pass. New cases: signer jobs are rescued; main's attempt 1 with the classic alternate is rescued; main moving on no longer drops a built run; a pinned follower moves at 5 min while the build never does; a follower never moves while a leg is running.tests/test_ci_owned_pool_sources.py: 11 pass, against the live origin/feat-cmux-next.Deploy: the rescue checks out main, and a running sweeper hands over within
CODE_CHECK_TICKSonce main's copy changes, so merging deploys it.Risk: medium. A main nightly whose sign or verify jobs stall now gets cancelled-then-re-run once nothing else in it runs. A main nightly's pinned follower moves to Blacksmith after 5 min.
Agent session: agent session
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.Summary by cubic
Extends the nightly signing-stall rescue so every sign, verify, and DMG job in nightly.yml can be moved off a stalled Blacksmith macOS label, and covers main's classic nightly for the first time.
NIGHTLY_SIGN_ALTERNATESgainssigner-dmg-imageandsigner-verify; each entry now holds several alternate-label expressions, including main's classic one.Written for commit df59e0d. Summary will update on new commits.
Summary by CodeRabbit