Repository navigation
acpmux: every session list page and session info fits one message (ls never hits message.too_large) - #28831
Merged
Conversation
…limit still go A list whose rows together, and one row alone, pass rpc::MAX_MESSAGE_BYTES: every _acpmux/sessions read (limit pages, with tools, no limit, a census) lists every id with each reply under the limit, and _acpmux/info answers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-741a93e81636ef5970d4
`acpmux ls` on a fleet host failed with "message too large to send:
16927852 bytes, the limit is 15728640". A page asked for by `limit` (ls
reads pages of 1000, with usage) was cut by count alone, and a row of any
size went whole into it; `_acpmux/info` sent a detail of any size. A
reply refused as too large is refused again on every retry.
- hub/reply_fit.rs: one fit rule (shrink_largest: replace the largest
parts first until it fits) and REPLY_BYTES, a MiB under the message
limit. fit_object trims a row's largest fields (a string keeps a 1 KiB
preview), never its id, peer, status, updatedAt or name, and marks them:
omitted {bytes, reason: too_large, fields}.
- Snapshot::page (limit pages and the census's orderBy pages) holds at most
limit rows and at most REPLY_BYTES; a page cut short by bytes hands on
the cursor of its last row, so a client reads the rest. withTools pages
go the same way, no longer through a whole parsed copy of the list.
- A row too large for a page alone is trimmed (row_text), on the byte pages
too; only a kept field that large still goes as the id stub.
- _acpmux/info's detail is fitted (fit_reply_object).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-741a93e81636ef5970d4
…, harness, cwd) The same set #28754's attach reply never trims, so both fits keep one set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-741a93e81636ef5970d4
Contributor
|
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)
web and size checks: green Shipped in:
|
|
Found 2 test failures on Blacksmith runners: Failures
|
teamleaderleo
temporarily deployed
to
artifacts
October 31, 2026 03:34 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
sentry-dsyms
October 31, 2026 03:34 — with
GitHub Actions
Inactive
Review (gpt-6-astra) found that a fitted row could reach a peer unmasked: peer_text masks a summary only when it has sessionId, harness and lastSeq, and lastSeq was not a kept field. And a preview cut at 1 KiB could split a secret into a head the scanner no longer knows: the new peer-path test read ghp_CutkQ9mX7pL2vB8n... at 468e477. - lastSeq is kept. - A preview is masked over 4 KiB past its cut, then cut, as a lane's title is (views.rs masked_cut). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-741a93e81636ef5970d4
teamleaderleo
temporarily deployed
to
ci-routing-agent
October 31, 2026 03:37 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
sentry-dsyms
October 31, 2026 04:08 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 31, 2026 04:08 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 31, 2026 04:28 — with
GitHub Actions
Inactive
Collaborator
Author
teamleaderleo
temporarily deployed
to
ci-routing-agent
October 31, 2026 05:50 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
sentry-dsyms
October 31, 2026 06:17 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 31, 2026 06:17 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 31, 2026 06:20 — with
GitHub Actions
Inactive
Collaborator
Author
|
Independent review (gpt-6.1-sol high) at 9f40ed4: BLOCK.
|
teamleaderleo
temporarily deployed
to
ci-routing-agent
October 31, 2026 18:52 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
sentry-dsyms
October 31, 2026 19:02 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 31, 2026 19:02 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 31, 2026 19:03 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 31, 2026 19:11 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 31, 2026 19:13 — with
GitHub Actions
Inactive
Collaborator
Author
This was referenced Nov 1, 2026
This branch was previously deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Summary
On a fleet host, plain
acpmux lsfails:acpmux: runtime: message too large to send: 16927852 bytes, the limit is 15728640. No one can list that host's sessions, and the census and stall reconciler can't see it either. The CLI only retries with smaller pages, so the daemon has to send every list reply whole and under the cap.Where the daemon still built a reply too large to send:
limitpages were cut by row count only.acpmux lsreads pages of 1000 rows with usage (acpmux ls: read the session list in pages (never one reply), --cursor, titles at most 200 chars #28373). The census'sorderBypages and everywithToolspage are cut the same way. A page of large rows came to 37 MB in the test below. The byte-bounded paging from acpmux: a session list too large for one message goes in pages #28182 covered only replies with nolimit.limitpage. On the byte pages it became an id-only stub. Every field was lost, itscwdand status included._acpmux/infosent a detail of any size, for example a chat whose title is a whole pasted prompt.The fix fits every reply as a whole and never refuses one:
hub/reply_fit.rsholds the shared rule and bound.shrink_largestreplaces the largest parts first until the value fits.REPLY_BYTESis 1 MiB underrpc::MAX_MESSAGE_BYTES.fit_objecttrims a row's largest fields: a string keeps a 1 KiB preview, any other value is dropped. It never trims the fields a row is found and opened by (sessionId,id,qualifiedSessionId,sessionReceipt,peer,status,harness,cwd,updatedAt,name; the same set acpmux: a chat whose records together pass one message still opens (attach reply fits) #28754's attach reply keeps), and it marks the rowomitted: {bytes, reason: "too_large", fields: [...]}.LIST_PAGE_BYTESis nowREPLY_BYTES.Snapshot::page(thelimitpages and census pages) holds at mostlimitrows and at mostREPLY_BYTESbytes. A page cut short by size returns thenextCursorof its last row (k…, ors:<id>for a census), and clients already follow it.withToolspages use the same path. They no longer parse a copy of the whole list._acpmux/inforuns its detail throughfit_reply_object.peer_text.rs).lastSeqis a kept field, since masking recognizes a summary bysessionId,harnessandlastSeq. A preview is masked over 4 KiB past its cut and only then cut, the wayviews.rsmasked_cuttreats titles, so a secret split by the cut is never left as a head.#28754 adds the same kind of fit for the chat-open reply (
_acpmux/attach). The two are built on one rule:paging::fit_replythere isshrink_largestover/events/N/msgand/turnOpener/msg. Whichever PR lands second switches to the shared helper and the single bound.Related: #28182, #28373, #28161, #28105 (the earlier paging work).
Testing
server/list_fit_tests.rs(new) builds a hub with 1,000 peer rows of 20 KB plus one 16 MiB row, and a local chat with a 16 MiB title. The list as a whole is past the cap, and so is one row alone. Through a real server connection:_acpmux/sessionswith{limit: 1000, usage: true},{limit: 1000, withTools: true},{}and a census (orderBy): followingnextCursorto the end lists every id once, and every reply line is underMAX_MESSAGE_BYTES. The large row keeps its id, peer, status andcwd, itsplanStepbecomes a preview, and it is markedomitted.fields = ["planStep"]. Small rows are unchanged._acpmux/infoon the 16 MiB-title chat answers under the cap, with a title preview andomitted.fieldsnamingtitle.lastPromptholds one token near its start and one split at the 1 KiB cut keepslastSeq, and neither token's start appears in the preview (a_trimmed_row_still_goes_to_a_peer_masked). Withreply_fit.rsas of 468e477 this test fails: the split token leaked asghp_CutkQ9mX7pL2vB8n….Command:
cargo test -p acpmux --lib -- list_fit(incmux-tui/).{"limit":1000,"usage":true} page 0: message too large to send: 37190897 bytes, and info fails withmessage too large to send: 16779433 bytes.-- list_fit reply_fit list_guard list_reply acp_list session_pages ls_pages native_history peer_text: 59 passed, 0 failed.cargo clippy -p acpmux --lib --tests -- -D warningsis clean.Observed / Not run
cargo test -p acpmux --libwith a filter). Panic ratchet (rust_panic_ratchet.py,-p acpmux): arithmetic_side_effects and cast_possible_truncation report above baseline, but none of the hits in the changed files are on lines this PR adds (they are existing base code).acpmux lson the failing host. That host runs an acpmux older than acpmux ls: read the session list in pages (never one reply), --cursor, titles at most 200 chars #28373 (its error is the raw daemon message, which the paged CLI would have caught and retried smaller), so it needs an update that includes this change first.Changelog
Fixed:
acpmux lsandacpmux session infowork on a host whose session list, or one session, is larger than one message; an oversized field shows as a preview and is marked omitted.Proof
No UI: daemon reply sizes only. The tests above show it.
_acpmux/sessions {limit:1000, usage}reply, 1,001 rows of 20 KB plus one 16 MiB rownextCursorserver/list_fit_tests.rs_acpmux/infoof a chat with a 16 MiB titleserver/list_fit_tests.rsAgent session: agent session
🤖 Generated with Claude Code