Repository navigation
cmux-tui headless owner: the terminal reaper and the Chief brain supervisor no longer spin on a past deadline (idle CPU) - #33173
Conversation
…ot make the reaper's next wait zero Red on base: a due terminal whose reap comes back Retained (the close guard still sees it placed) or Reaped while still listed loses its deadline (forget); the next scan re-adds it at now + grace - unplaced_for, and since #29476 unplaced_for is the durable time already past the grace, so the deadline is now and the reaper thread waits zero and runs again: a hot loop of registry prunes, an unplaced-time write, a screen capture and a guarded close per pass. The outcome handling moves into ReapSchedule::settle unchanged so the test drives it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-be6d2cae00b3baee4240
…empt instead of re-running at once A due terminal's attempt, whatever it came to, now postpones its deadline by the grace (at least MIN_RETRY) instead of forgetting it. A scan that no longer lists the terminal (closed, placed again or kept) still drops the deadline, so a reaped or re-placed terminal behaves as before; one the attempt left reapable is tried again a grace later, not on a zero wait. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-be6d2cae00b3baee4240
…e the supervisor a past deadline Red on base: next_deadline offers the idle stop of every running brain, but on_time stops only a brain that is not typing. A turn that keeps its typing on for more than 30 minutes leaves a deadline in the past that nothing moves: the chief-brains thread waits zero, does nothing and runs again, one core at 100%. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-be6d2cae00b3baee4240
…r a brain that is still typing Its idle stop matches on_time's: a brain mid-turn is not stopped, so it has no idle deadline until its typing ends (which sets last_activity). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-be6d2cae00b3baee4240
|
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)
red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on 4575ff4 to compare; do not merge until green; see lane-rules Shipped in:
|
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
|
Found 2 test failures on Blacksmith runners: Failures
|
…l closed again gets its fresh grace Review (Sol, BLOCK at 9dba1e8): postponing the deadline of a Retained terminal let a terminal placed again and closed again before the next scan keep the attempt's retry deadline, short of a fresh grace from its new unplaced time. Reaped and Retained now forget the deadline as before and keep a retry floor while the terminal stays reapable; the next deadline is the later of the two. Attached and failed attempts postpone as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-be6d2cae00b3baee4240
…anaflow-ai/cmux into lane/tui-reap-retained-backoff
…ad does Review (Sol, BLOCK at f498f81): after the retry-floor change a Retained or Reaped attempt leaves no deadline until the next scan, so the test's expect on the next wait panicked. The test now scans once a millisecond for a second, as topology and registry events wake the thread, and counts the reap attempts: one with the floor, a thousand when each scan re-adds the terminal at its durable unplaced time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-be6d2cae00b3baee4240
|
Review (codex gpt-6-astra high, next-review): SHIP at fa06154 SHIP at fa06154
Source review completed; tests could not run because this box has no Rust toolchain. Follow-ups:
|
A newer verdict blocks d6258ef (no independent SHIP at the head).
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
The app's headless cmux-tui owner (
cmux-tui --headless --session cmux-app-nightly) was seen at about 150% CPU for 40 minutes on an idle Mac, against a budget of no CPU at idle. Two background threads in that owner can run with a zero wait once a deadline is in the past and nothing moves it. Each is fixed here with a test that fails on base.1.
mux-terminal-reap: a reap attempt that leaves the terminal reapable re-runs at onceWhen a due terminal's reap came back
RetainedorReaped, the reaper dropped its deadline (forget). If the next scan still listed the terminal, it re-added the deadline atnow + grace - unplaced_for. Since #29476,unplaced_foris the durable time the terminal was first seen unplaced, which is already past the grace, so the new deadline wasnow.The thread then waited zero (
recv_timeout(0)) and ran the next pass at once, and kept doing so. Every pass costs:sync_terminal_unplacedwrite,When several terminals are stuck this way, their attempts run in parallel on
mux-terminal-work.A terminal ends up stuck this way whenever the scan and the close guard disagree about whether it is placed. The scan matches a view's runtime id or the content's placements. The guard matches any surface with the same host identity.
Fix:
ReapSchedule::triedpostpones the deadline bygrace.max(MIN_RETRY)after every outcome, asAttachedand errors already did. A scan that no longer lists the terminal (closed, placed again, or kept) still drops the deadline inobserve_unplaced, so terminals that were really reaped or re-placed behave as before.2.
chief-brains: a brain still typing after the idle stop is due leaves a past deadlinenext_deadlineoffered the idle stop (last_activity + 30 min) for every running brain.on_timestops only a brain that is not typing. So a turn that kept its typing on for more than 30 minutes left a deadline in the past that nothing moved. The thread waited zero, did nothing, and ran again, holding one core at 100% until the turn ended.Fix: a brain has no idle deadline while it is typing, which matches
on_time. When the typing ends,handlesetslast_activity, and the stop counts from that point.Loops touched: stop conditions and cleanup
mux-terminal-reap:TerminalReaper::stop/ drop (thestopflag plus closing the mailbox), and the thread ends when theMuxis gone.terminal_reaper_eventsis cleared on exit (unchanged).MIN_RETRY(1 s) per stuck terminal, normally a full grace.chief-brainssupervisor:Signal::Shutdown, or the inbox disconnecting (unchanged).Tests (red on base)
terminal_reap::tests::terminal_reap_schedule_waits_after_an_attempt_that_left_the_terminal_reapable: one terminal unplaced for three graces, with a reap attempt that leaves it reapable. The test simulates the thread's waits for one second and counts the passes.terminal_reap::tests::terminal_reap_schedule_drops_a_settled_terminal_once_it_is_no_longer_reapablechief_brains::supervisor_idle_tests::a_brain_typing_past_the_idle_stop_leaves_no_past_deadlinePerformance
terminal_reap_schedule_waits_after_an_attempt_that_left_the_terminal_reapablea_brain_typing_past_the_idle_stop_leaves_no_past_deadlineRelated: #33099 fixes the "cmux-tui stopped and could not start again" toast, not this cause. #33117 (open) adds a cap on the reap grace in the same file; the two do not conflict.
Agent session: agent session
🤖 Generated with Claude Code
Open in [code]smith · Need help on this PR? Tag
@codesmith-botwith what you need.Summary by cubic
Fixes two hot loops that spin the headless
cmux-tuiowner at ~150% CPU on idle: the terminal reaper and the Chief-brains supervisor can wait zero, doing nothing, when a deadline falls in the past and nothing moves it.Bug Fixes
mux-terminal-reap: a reap attempt that leaves a terminal reapable now keeps a retry floor (the next deadline is the later of the scheduled one and the floor), so the terminal is retried after at leastMIN_RETRYinstead of being re-added as due at once. A terminal that a scan no longer lists drops its deadline and floor; one placed again and closed again gets a fresh grace from its new unplaced time.chief-brains: a brain that is typing has no idle deadline (matching the idle stop inon_time), and the idle stop counts from when its typing ends, so a past deadline can no longer sit untouched and keep the thread spinning.Written for commit bb990df. Summary will update on new commits.