Repository navigation
acpmux: count only live sub-sessions toward the width cap - #27931
Conversation
A hibernated (idle) or dead (disconnected) child still holds its parent's width slot on base; this test expects only ready, running and waiting children to. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-4730a60ace5c976462c0
The width slot follows every status write, but a child that hibernates or whose harness dies is not closed: the parent's log says closed and reopened only for a close and a reopen, as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-4730a60ace5c976462c0
|
Found 9 test failures on Blacksmith runners: Failures
|
|
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); NEW: green on the base 079bc45; do not merge until green; see lane-rules |
settle_one wrote Idle straight into the meta, so a sub-session whose host died across a restart while it waited stayed counted against its parent. It now updates the index under the same lock, as write_status does. The module doc also states that a prompt to a hibernated, dead or closed child wakes it past the limit, as a reopen always did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-4730a60ace5c976462c0
subsessions.rs and lifecycle.rs were over the god-file budget on base; this change grew both. The live-children index (Index, Reservation, holds_width_slot) moves to subsession_index.rs, and the width tests, the unit test #27787 added included, sit under it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-4730a60ace5c976462c0
A child that is not live but has a prompt on its way to a turn (queued for the turn lock or a run slot, or holding the turn lock while its harness starts) counts as live when a start reserves a slot, so a start never takes the slot a wake needs. Prompts a failed turn holds do not count. The index keeps open (not closed) children apart from live ones again, so the work below a parent still sees a dead child's own children. list_sessions' openChildren is the open count again; liveChildren is live plus waking. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-4730a60ace5c976462c0
Default changesThis pull request changes 1 default at
Signed off on this commit by Regenerate the snapshot with |
A child live when a start read its waking siblings but resting by the time it reserved was not counted, though its prompt was already on its way. The read now covers every open child, and the index counts the ones not live under its lock (Index::used, shared by reserve and list_sessions' liveChildren). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-4730a60ace5c976462c0
|
Review (codex gpt-6.1-sol): SHIP at 775b871 An independent Codex gpt-6.1-sol review (high, fast), reading the code at the exact head. Earlier rounds said BLOCK and their findings are fixed in this head's commits: the restart's lost-wait settle bypassed the index (round 1), a wake of a hibernated child was not counted (round 2), and a child hibernating between the waking read and the reservation was missed (round 3). Round 4:
Red on base: https://github.com/manaflow-ai/cmux/actions/runs/41002461341. Green at this head: https://github.com/manaflow-ai/cmux/actions/runs/41007731238 |
|
Shipped in:
|
|
Shipped in:
|
|
Shipped in:
|
A push fast tier on the base branch can end with no verdict: its concurrency group replaces it while pending, or the head preflight skips it. No push run containing c5dd001 (#27931, generated SettingsSchema Swift) finished the fast tier (runs 41012836913 and 41013125180 cancelled, 41014687570 skipped), so that Swift landed with only a Release compile behind it. A push fast tier that runs to a verdict now uploads a cmux-next-fast-tier-finished marker. path_route reads the markers (existing actions: read token) and routes the diff since the newest one on the push history through the pull-request router; the push fast tier skips only when that diff reaches no Mac tier. Any error or missing marker runs it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-db2d0bd6a321df7a1f3a
A push fast tier on the base branch can end with no verdict: its concurrency group replaces it while pending, or the head preflight skips it. No push run containing c5dd001 (#27931, generated SettingsSchema Swift) finished the fast tier (runs 41012836913 and 41013125180 cancelled, 41014687570 skipped), so that Swift landed with only a Release compile behind it. A push fast tier that runs to a verdict now uploads a cmux-next-fast-tier-finished marker. path_route reads the markers (existing actions: read token) and routes the diff since the newest one on the push history through the pull-request router; the push fast tier skips only when that diff reaches no Mac tier. Any error or missing marker runs it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-db2d0bd6a321df7a1f3a
A push fast tier on the base branch can end with no verdict: its concurrency group replaces it while pending, or the head preflight skips it. No push run containing c5dd001 (#27931, generated SettingsSchema Swift) finished the fast tier (runs 41012836913 and 41013125180 cancelled, 41014687570 skipped), so that Swift landed with only a Release compile behind it. A push fast tier that runs to a verdict now uploads a cmux-next-fast-tier-finished marker. path_route reads the markers (existing actions: read token) and routes the diff since the newest one on the push history through the pull-request router; the push fast tier skips only when that diff reaches no Mac tier. Any error or missing marker runs it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-db2d0bd6a321df7a1f3a
A push fast tier on the base branch can end with no verdict: its concurrency group replaces it while pending, or the head preflight skips it. No push run containing c5dd001 (#27931, generated SettingsSchema Swift) finished the fast tier (runs 41012836913 and 41013125180 cancelled, 41014687570 skipped), so that Swift landed with only a Release compile behind it. A push fast tier that runs to a verdict now uploads a cmux-next-fast-tier-finished marker. path_route reads the markers (existing actions: read token) and routes the diff since the newest one on the push history through the pull-request router; the push fast tier skips only when that diff reaches no Mac tier. Any error or missing marker runs it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-db2d0bd6a321df7a1f3a
A push fast tier on the base branch can end with no verdict: its concurrency group replaces it while pending, or the head preflight skips it. No push run containing c5dd001 (#27931, generated SettingsSchema Swift) finished the fast tier (runs 41012836913 and 41013125180 cancelled, 41014687570 skipped), so that Swift landed with only a Release compile behind it. A push fast tier that runs to a verdict now uploads a cmux-next-fast-tier-finished marker. path_route reads the markers (existing actions: read token) and routes the diff since the newest one on the push history through the pull-request router; the push fast tier skips only when that diff reaches no Mac tier. Any error or missing marker runs it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-db2d0bd6a321df7a1f3a
A push fast tier on the base branch can end with no verdict: its concurrency group replaces it while pending, or the head preflight skips it. No push run containing c5dd001 (#27931, generated SettingsSchema Swift) finished the fast tier (runs 41012836913 and 41013125180 cancelled, 41014687570 skipped), so that Swift landed with only a Release compile behind it. A push fast tier that runs to a verdict now uploads a cmux-next-fast-tier-finished marker. path_route reads the markers (existing actions: read token) and routes the diff since the newest one on the push history through the pull-request router; the push fast tier skips only when that diff reaches no Mac tier. Any error or missing marker runs it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-db2d0bd6a321df7a1f3a
A push fast tier on the base branch can end with no verdict: its concurrency group replaces it while pending, or the head preflight skips it. No push run containing c5dd001 (#27931, generated SettingsSchema Swift) finished the fast tier (runs 41012836913 and 41013125180 cancelled, 41014687570 skipped), so that Swift landed with only a Release compile behind it. A push fast tier that runs to a verdict now uploads a cmux-next-fast-tier-finished marker. path_route reads the markers (existing actions: read token) and routes the diff since the newest one on the push history through the pull-request router; the push fast tier skips only when that diff reaches no Mac tier. Any error or missing marker runs it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-db2d0bd6a321df7a1f3a
A push fast tier on the base branch can end with no verdict: its concurrency group replaces it while pending, or the head preflight skips it. No push run containing c5dd001 (#27931, generated SettingsSchema Swift) finished the fast tier (runs 41012836913 and 41013125180 cancelled, 41014687570 skipped), so that Swift landed with only a Release compile behind it. A push fast tier that runs to a verdict now uploads a cmux-next-fast-tier-finished marker. path_route reads the markers (existing actions: read token) and routes the diff since the newest one on the push history through the pull-request router; the push fast tier skips only when that diff reaches no Mac tier. Any error or missing marker runs it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-db2d0bd6a321df7a1f3a
* ci(cmux-next): a push fast tier routes from the last finished one A push fast tier on the base branch can end with no verdict: its concurrency group replaces it while pending, or the head preflight skips it. No push run containing c5dd001 (#27931, generated SettingsSchema Swift) finished the fast tier (runs 41012836913 and 41013125180 cancelled, 41014687570 skipped), so that Swift landed with only a Release compile behind it. A push fast tier that runs to a verdict now uploads a cmux-next-fast-tier-finished marker. path_route reads the markers (existing actions: read token) and routes the diff since the newest one on the push history through the pull-request router; the push fast tier skips only when that diff reaches no Mac tier. Any error or missing marker runs it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-db2d0bd6a321df7a1f3a * ci: keep anchor regressions on explicit fleet runs Agent-Session: https://cmux.com/deeplink/agent?id=aid-db2d0bd6a321df7a1f3a --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Takes over #27787, whose owner is gone. This PR carries its commit with its authorship, adds a red/green test, and makes one change to it.
Leo asked:
What changes
A sub-session's width slot (
maxChildren) used to be held by every child that was not closed, including hibernated children and children whose harness had died. A parent that fanned out and waited for its children kept all of its slots until it closed each child by hand.Now only live children hold a slot:
ready(harness alive between turns),runningandwaiting(waiting for input). A child with a message on its way to a turn also holds one: queued behind a turn or for a run slot, or starting its harness. That way a start never takes the slot a wake needs. A child that finished and hibernated (idle), whose harness died (disconnected), that failed at start (closed byclose_refused), or that was closed frees its slot right away, and its history stays. A finished child keeps its harness alive for up to the idle window (2 min,IDLE_CHILD) and holds its slot until it hibernates. That idle window is also how long its process lives. The limit refuses starts. A message to a child the parent already has still wakes it, as a reopen always did.hub/subsession_index.rs(moved out ofsubsessions.rs, which was over its god-file budget on base): the index keeps open (not closed) and live children apart.Index::note_statusis the only way status reaches it. It is called from every status write (write_status), on load, on the restart's lost-wait settle (log_load.rs, which used to bypass it), on offer acceptance, and when a start's reservation settles.Index::reservecounts live children, waking ones (Hub::waking_children) and reservations under one lock.list_sessionsgainsliveChildren, andopenChildrenkeeps its meaning. The work below a parent (work_below.rs) still looks at every open child.agents.subsessions.maxChildren), and the generated Settings/MDM exports use the same definition.My changes on top of #27787:
subsessionclosed/reopenedrecords fired on every slot change, so each hibernation logged aclosedand each wake areopened. They are back to marking a real close and reopen.cmux-next checkson the first push.Changelog
Fixed: an agent's sub-sessions that finished, hibernated or died no longer count toward its limit of open sub-sessions.
Tests
Regression test:
only_live_children_hold_a_width_slot. It walks a real child through ready, running, waiting, idle, a queued message, a harness start, running, disconnected and closed, and checks the width the parent uses, whether a start can reserve, and the parent'ssubsessionrecords.hub::lifecycle::subsession_width_tests):cargo test --locked -p acpmux --lib hub::lifecycle::subsession_width_testsfails witha finished, hibernated child frees its slot(left: 1, right: 0). Fleet run https://github.com/manaflow-ai/cmux/actions/runs/41002461341cargo test --locked -p acpmux --lib -- hub::subsessionspasses both width tests (the test moved tohub::subsessions::index::width_tests). Fleet run https://github.com/manaflow-ai/cmux/actions/runs/41007731238In the same head run:
width_slots_count_live_children_only(from #27787, extended),--test subsessions agents_start_children_within_their_width_and_depth_limits,--test hub_integration run_parent(the parent'ssubsessionrecords),cargo clippy -p acpmux --all-targets -D warningsandcargo fmt --all --checkall pass.Observed / Not run
scripts/cmux-next/prepush-gate.py(no new violations),check-no-godfiles.sh --only rust --base(pass),gen-settings-sources.py --check, and four review rounds (BLOCK, BLOCK, BLOCK, SHIP; their findings are fixed in the later commits).No capture: the only native UI change is the help and note text of the existing Open Sub-sessions per Session setting; layout is unchanged.
Risk: normal. Daemon logic for sub-session admission. The worst case is a parent that can start more harness-alive children than intended.
maxRunningstill caps concurrent turns, and host admission (admission.rs) still caps sessions.Agent session: agent session
🤖 Generated with Claude Code