Skip to content

acpmux: count only live sub-sessions toward the width cap - #27931

Merged
teamleaderleo merged 7 commits into
feat-cmux-nextfrom
lane/subsession-cap-live-2
Oct 30, 2026
Merged

teamleaderleo merged 7 commits into
feat-cmux-nextfrom
lane/subsession-cap-live-2

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

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:

0 open sub-sessions and may have at most 50 open at once

WHAT A STUPID F***ING LIMITATION

WTH IS IT COUNTING

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), running and waiting (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 by close_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 of subsessions.rs, which was over its god-file budget on base): the index keeps open (not closed) and live children apart. Index::note_status is 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::reserve counts live children, waking ones (Hub::waking_children) and reservations under one lock.
  • The refusal states the live count and the counting rule. It no longer tells the agent to close finished children, because they no longer count. list_sessions gains liveChildren, and openChildren keeps its meaning. The work below a parent (work_below.rs) still looks at every open child.
  • The cmux-subsessions MCP descriptions, the setting's note and help (agents.subsessions.maxChildren), and the generated Settings/MDM exports use the same definition.

My changes on top of #27787:

  • In acpmux: count only live sub-sessions toward width cap #27787, the parent's subsession closed/reopened records fired on every slot change, so each hibernation logged a closed and each wake a reopened. They are back to marking a real close and reopen.
  • The restart's lost-wait settle frees the slot; it used to write the status straight into the meta, bypassing the index.
  • Waking children count. Without this, a parent at its limit with one hibernated child could start another while a message to the hibernated one waited for a run slot, and end up past the limit.
  • The index is its own module, to stay within the god-file budget that failed cmux-next checks on 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's subsession records.

In 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's subsession records), cargo clippy -p acpmux --all-targets -D warnings and cargo fmt --all --check all pass.

Observed / Not run

  • Observed: the red and green fleet runs above, 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).
  • Not run: no tagged-build check of the Settings row. Only its help text changes, and the setting's key, kind and default are unchanged.

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. maxRunning still caps concurrent turns, and host admission (admission.rs) still caps sessions.

Agent session: agent session

🤖 Generated with Claude Code

teamleaderleo and others added 3 commits October 30, 2026 03:51
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
@blacksmith-sh

blacksmith-sh Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Found 9 test failures on Blacksmith runners:

Failures

Test View Logs
--from must install a complete prebuilt tree/
--from must install a complete prebuilt tree
View Logs
/tmp/tmp92cwfl4k/summary-fail.json (live):/summary-fail.json (live): View Logs
/tmp/tmpv7hiv1xa/summary-missing.json (live):/summary-missing.json (live): View Logs
[new_workspaces] debug.new_workspace timed 0 of 50 new workspace rows/
[new_workspaces] debug.new_workspace timed 0 of 50 new workspace rows
View Logs
[new_workspaces] the window draws no frames/[new_workspaces] the window draws no frames View Logs
[tabs] debug.tab_switch timed 0 of 40 switches/
[tabs] debug.tab_switch timed 0 of 40 switches
View Logs
[tabs] the window draws no frames/[tabs] the window draws no frames View Logs
test_every_listed_hook_is_one_glaeda_released_with_the_check (main.SigningHooksInSt
epWithGlaedaTests.test_every_listed_hook_is_one_glaeda_released_with_the_check)/
test_every_listed_hook_is_one_glaeda_released_with_the_check (main.SigningHooksInSt
epWithGlaedaTests.test_every_listed_hook_is_one_glaeda_released_with_the_check)
View Logs
test_the_repository_highlights_validate (main.DigestTests.test_the_repository_highl
ights_validate)/
test_the_repository_highlights_validate (main.DigestTests.test_the_repository_highl
ights_validate)
View Logs

Fix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

@github-actions github-actions Bot added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 30, 2026
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review 775b871: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr27931 -f ref=lane/subsession-cap-live-2 -f platform=macos -f backend_mode=local

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
teamleaderleo and others added 2 commits October 30, 2026 04:12
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
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Default changes

This pull request changes 1 default at 775b871bb5a3 (what everyone gets without configuring anything):

  • tunable-source.CmuxNextSettings/Schema/SettingsSchema+Subsessions.generated.swift:descriptors: "c8ed4a3d7c02d932ffa48874103ee37b28c74db6a3184a47f4e4622d1e30c5d9" -> "c750ac1c552737585711d557232bd27c1dd7583a9080619c38221db139a6e00d"

Signed off on this commit by review (codex gpt-6.1-sol).

Regenerate the snapshot with python3 scripts/ci/defaults_guard.py snapshot.

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
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

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:

No findings. The index updates are synchronized with status changes, waking reservations have no lock-order cycle, and queued/turn-lock reservations are released by their owning futures.

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

@teamleaderleo
teamleaderleo marked this pull request as ready for review October 30, 2026 05:26
@teamleaderleo
teamleaderleo merged commit c5dd001 into feat-cmux-next Oct 30, 2026
252 of 261 checks passed
@teamleaderleo
teamleaderleo deleted the lane/subsession-cap-live-2 branch October 30, 2026 06:13
@github-actions

Copy link
Copy Markdown
Contributor

Shipped in:

@github-actions

Copy link
Copy Markdown
Contributor

Shipped in:

@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

teamleaderleo added a commit that referenced this pull request Oct 30, 2026
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
teamleaderleo added a commit that referenced this pull request Oct 30, 2026
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
teamleaderleo added a commit that referenced this pull request Oct 30, 2026
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
teamleaderleo added a commit that referenced this pull request Oct 30, 2026
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
teamleaderleo added a commit that referenced this pull request Oct 30, 2026
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
teamleaderleo added a commit that referenced this pull request Oct 30, 2026
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
teamleaderleo added a commit that referenced this pull request Oct 30, 2026
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
teamleaderleo added a commit that referenced this pull request Oct 30, 2026
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
teamleaderleo added a commit that referenced this pull request Oct 31, 2026
* 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>

This branch was previously deployed

3 inactive deployments
artifacts — 775b871b Deployed Oct 30, 2026 by teamleaderleo via add the Windows daemon to the tree #80619
ci-routing-agent — 775b871b Deployed Oct 30, 2026 by teamleaderleo via namespace autofix #7213
sentry-dsyms — 775b871b Deployed Oct 30, 2026 by teamleaderleo via upload cmux-tui dSYMs to Sentry #80619
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant