Repository navigation
cmux-next: a quit in the Swift test helper no longer ends the whole test run - #23658
Conversation
The CmuxNextAppTests run has ended with status 0 mid-way since at least 2026-10-20: hundreds of tests started and never finished, no crash report. Three quits were scheduled on the run loop as a bare NSApp.terminate, which is exit(0) in a process whose app never ran, as soon as any test spun the main run loop. NSApplication.terminateFromRunLoop (CmuxNextCompat) schedules the quit as before, but refuses when the app is not running and prints the call site and the asking stack. QuitCoordinator.requestQuit, UpdateDropBack.relaunchAfterExit and DebugUpdater.terminate use it. A test-only C target prints the stack of every exit() of the test process, so any other caller is named in the CI log. A guard keeps bare deferred terminates out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-9c97-76c3-88d7-6d0422d2fadc&host=cosmic-gray
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-9c97-76c3-88d7-6d0422d2fadc&host=cosmic-gray
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Passes: CI passes on CI passes on Written by red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on 118beeb to compare; do not merge until green; see lane-rules Tour of |
|
Owned by chief-sidebar-2 on cosmic-gray · session |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-9c97-76c3-88d7-6d0422d2fadc&host=cosmic-gray
|
Bead |
|
Found 12 test failures on Blacksmith runners: Failures
...and 2 more test failures. View all on Blacksmith: run 39716194200, run 39716194354
|
…h ratchet Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-9c97-76c3-88d7-6d0422d2fadc&host=cosmic-gray
…ar-2/test-helper-exit # Conflicts: # .github/workflows/cmux-next-guards.yml # tests/test-execution.toml
|
|
|
What the tracer named (CI at 81560ef, swift test job 119449955268): the mid-run exit is not so the async test This PR still stands as a rail (a test's quit can no longer end the run) and as the tracer. A follow-up from me traces who stops the main run loop ( |
|
Review (subagent, correctness first): SHIP at 81560ef Release compile green (rerun; the first attempt hit a Blacksmith runner without Xcode 26.6). Reds are not this PR's: checks (Package conventions lint, Tier routing: base), swift test (the mid-run exit this PR traces, base), perf gate ([relaunch] pane_snapshots 4.0 > 1 at PaneController pane mount; same failure on #23638), daemon tests (ClassicUpgradeSimulationTests workspace order; the diff touches no daemon or workspace-order code). Review notes (comments that name terminate as the cause; guard-regex blind spots) go into the follow-up. |
|
Review (subagent, correctness first): SHIP at 4ec4a78 Same diff as the reviewed 81560ef plus a feat-cmux-next merge. Release compile and the checks job are green. Reds are not this PR's: swift test (the mid-run exit this PR traces), daemon tests (ClassicUpgradeSimulationTests, as before), release-notary (highlight restored-terminals-come-back.md from base) and its Guard status rollup, fleet test-compile (runner setup failed). |
|
|
|
Review (codex gpt-6.1-sol): SHIP at 46d180f Blocking findings: none. Non-blocking findings: none. Checked: merge-base 373ba24 through this exact head; all three deferred quit call sites and the AppKit helper's running/test-process paths; package and test-target wiring; the C exit tracer; the workflow and registry guard; and diff whitespace plus Python syntax. No macOS build or Swift test suite was run. |
|
Review (codex gpt-6.1-sol): SHIP at c139c30 Blocking findings: none. Non-blocking findings: tests/test_cmux_next_deferred_terminate.py:17-20,31 only searches six physical lines and only matches NSApp/NSApplication.shared. A deferred closure using app.terminate or placing the call later in the closure passes this guard, so it would not catch the regression it claims to prevent. Checked the exact merge-base diff (118beeb..c139c30), whole-file quit call paths, package target wiring, workflow/registry entries, Python syntax, and diff whitespace; no macOS build or Swift test suite was run. |
#23658 put CmuxNextTestExitTrace at Tests/Support/CmuxNextTestExitTrace with an explicit `path:`. The reader assumed Sources/<name> or Tests/<name>, so test_the_manifest_reader_finds_the_graph_targets failed, and Tier routing stopped before it reached the build-metrics test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba2-4ce2-7e02-8fa2-5cd34f7648b1&host=cosmic-gray
… and #24018's reuse skip (base red) (#24196) * ci(tests): the build-log upload test accepts #24018's reuse skip The swift-test and generated-files upload steps now read `(always()) && steps.reuse.outputs.hit != 'true'`: a run that reused a pass built nothing to upload. The test still pins that a failed build uploads its measurement and log. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba2-4ce2-7e02-8fa2-5cd34f7648b1&host=cosmic-gray * ci(tests): the route test's manifest reader honours a target's own path: #23658 put CmuxNextTestExitTrace at Tests/Support/CmuxNextTestExitTrace with an explicit `path:`. The reader assumed Sources/<name> or Tests/<name>, so test_the_manifest_reader_finds_the_graph_targets failed, and Tier routing stopped before it reached the build-metrics test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba2-4ce2-7e02-8fa2-5cd34f7648b1&host=cosmic-gray --------- Co-authored-by: Leo Li <leoli.4u@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…under Tests/ (#24231) #23658 added CmuxNextTestExitTrace, a regular target at Tests/Support/CmuxNextTestExitTrace that only test targets link. The coverage test counted it as a production target CmuxNextApp does not reach and asked for it in the swift-canary-fleet list. Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba2-4ce2-7e02-8fa2-5cd34f7648b1&host=cosmic-gray Co-authored-by: Leo Li <leoli.4u@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
Shipped in:
|
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
The CmuxNext Swift test run (
cmux-next swift test) has ended with status 0 partway through since at least 2026-10-20 14:35Z. Hundreds of tests are left "started and never finished" (742 in #23599's job 119381263992), with no crash report and no signal. WindowServer logs an ordinary process death. HomeOpenFocusesComposerTests is usually the last suite to report, because its click helper spins the main run loop. About 400 PR swift-test jobs ran since 10-19 12:00Z, and one succeeded. Base pushes skip this job by design (cmux-next.yml:2360), so base never showed it.Likely cause. Three quits were scheduled on the main run loop as a bare
NSApp.terminate(nil):QuitCoordinator.requestQuitUpdateDropBack.relaunchAfterExitDebugUpdater.terminateIn a process whose app never ran (the Swift test helper), AppKit's terminate is
exit(0). It fires as soon as any test spins the main run loop.Fix
NSApplication.terminateFromRunLoop(CmuxNextCompat) schedules the quit exactly as before when the app is running. When the app never ran, it refuses, and prints the call site and the stack that asked on stderr (also kept inrefusedTerminations). The three sites use it.CmuxNextTestExitTraceis a test-only C target linked into CmuxNextAppTests. Everyexit()of the test process prints its stack, so if anything else ends the run, the CI log names the caller.tests/test_cmux_next_deferred_terminate.py(linux-guard, run in cmux-next guards) keeps bare deferred terminates out.Tests:
TestProcessExitTests. A quit asked in the test process is refused and names its call site; before this change, that test ended the whole run. A second test checks that the exit tracer is installed.The caller that triggers it in the suite will be named here once this PR's swift-test log shows the refusal line.
No capture: no UI change (quit plumbing and test support).
Agent session: cosmic-gray
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.Summary by cubic
Fixes the
cmux-next swift testrun ending with status 0 partway through since at least 2026-10-20, leaving hundreds of tests started but never finished with no crash report. A bareNSApp.terminate(nil)scheduled on the main run loop becameexit(0)in the test helper process, whose app never ran, firing as soon as any test spun the run loop.Adds
NSApplication.terminateFromRunLoop(CmuxNextCompat): it schedules the quit exactly as before when the app is running, but refuses when it is not, printing the call site and the asking stack to stderr and recording it inrefusedTerminations. The three quit sites —QuitCoordinator.requestQuit,UpdateDropBack.relaunchAfterExit,DebugUpdater.terminate— now use it. Test-onlyCmuxNextTestExitTraceprints the stack of everyexit()of the test process so any other exit caller is named in CI logs; it installs only when tests actually run, staying quiet during--list-tests/--dump-tests-json. A new linux-guard (test_cmux_next_deferred_terminate.py) keeps bare deferred terminates out.TestProcessExitTestsverifies a quit in the test process is refused with its call site named, and that the exit tracer is installed.No UI change; quit plumbing and test support only.
Written for commit c139c30. Summary will update on new commits.