Repository navigation
acpmux: a chat move whose client goes away ends on its own (cx-xtg0.9) - #19411
Conversation
Three behavior tests: the client is gone before the bundle is read (the chat must come back here), after the target finished (the source must commit), and after the copy but before finish (the target must drop the receive and the chat come back). Only the lease setter they use exists yet; today the chat stays frozen in all three. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The source watches each move it began (hub/transfer_watch.rs). Once the move
has been idle for the lease (5 min; begin and each read are activity):
- the bundle was not read to its end: no target can have finished, so the
move aborts (transfer_aborted reason stalled) and the chat runs here again;
- it was: the source asks the target named at begin (to: {socket}) with the
new local-only _acpmux/transfer_forget, which drops any receive of the move
under the lock transfer_finish holds and says whether the chat landed. It
landed: commit. It did not: abort. No answer (or no target named): the chat
stays frozen and the source asks again after another lease.
The state lives in the move's directory, so a restarted daemon watches its
moves again. A repeated commit answers committed. acpmux transfer names its
target at begin.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… abort never interleave transfer_forget leaves transfers/forgot-<id>, so a client that kept the bundle cannot receive the move again after the source gave the chat back. A page read and its note share a lock with the watch's not-fully-read abort. The target's answer has a 30 s timeout, and a clock step back counts as activity (cx-xtg0.9 review). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
A worker's temp dir can make the path longer than a socket allows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
|
Batch queue: dropped from this batch, turns heavy tier red.
Next: fix, push. |
acpmux now has a target-side transfer_forget (#19411). The daemon's receive-abort should forward it for the move named in the receive's own manifest, and acpmux's forget must stay unreachable as a daemon verb. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Forwards acpmux's target-side _acpmux/transfer_forget (#19411) with the transfer and session ids of the receive's own manifest, so acpmux drops the receive's files at once and refuses that move afterwards; acpmux's forget is not a daemon verb. A receive whose manifest lacks plain ids is a bad request. server.rs keeps to its god-file baseline after the base merge: the module is public and its route chains onto the attach route. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…emon's own guard (cx-rppd.1) (#19460) * cmux-tui: behavior tests for guarded agent chat moves (agent-transfer-v1) Tests first for cmuxterm-hq#1874 slice 1 (cx-rppd.1): a trusted local client moves a chat through the daemon, which forwards only the guarded form of acpmux's transfer calls. The module is a stub that serves nothing, so the tests fail on their assertions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-tui: agent-transfer-v1 forwards chat moves to acpmux with the daemon's own guard The Move to Cloud pump (cmuxterm-hq#1874 slice 1, cx-rppd.1) moves a chat between two daemons' acpmux through these verbs. A receive always carries a guard the daemon builds: peer control rooted at $HOME/work on a Cloud host, web control rooted at the named folder (strictly under $HOME, not in a dot folder) elsewhere, and the folder must be under the roots. Finish uses the receive's own folder. Source verbs take the chat only from the surface's tab record, and begin serves the bundle manifest without absolute source paths. Trusted local clients only; no relay allowlist entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-tui: agent-transfer page check in clippy's preferred form Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-tui: tests for agent-transfer host kind, slots and bundle scrubbing Review of #19460: a receive must be refused on a team VM and on a Cloud VM of unknown kind (the hq-84 rule agent-session-start follows), at receive and again at finish; receive slots must not leak; begin must scrub session.json launch settings; read must serve only paths the begin manifest lists. These fail until the next commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-tui: agent-transfer follows the team VM rule and stops leaking slots Review of #19460: - receive and finish read agent-session-start's machine kind gate at each call and refuse on a team VM or a Cloud VM of unknown kind (hq-84), with start's codes: a peer-control chat keeps its policy and mode. - the receive cap is checked before acpmux makes a receive; a finish that fails for good drops its receive; agent-transfer-receive-abort forgets one (acpmux has no target-side abort); abort forgets the move even when acpmux refuses. - begin scrubs session.json launch settings (env, argv, harness roots, preset, tags) next to manifest.json sources, names compared case-insensitively, and read serves only paths the manifest lists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-tui: test that receive-abort has acpmux forget the receive's move acpmux now has a target-side transfer_forget (#19411). The daemon's receive-abort should forward it for the move named in the receive's own manifest, and acpmux's forget must stay unreachable as a daemon verb. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-tui: receive-abort has acpmux forget the receive's move Forwards acpmux's target-side _acpmux/transfer_forget (#19411) with the transfer and session ids of the receive's own manifest, so acpmux drops the receive's files at once and refuses that move afterwards; acpmux's forget is not a daemon verb. A receive whose manifest lacks plain ids is a bad request. server.rs keeps to its god-file baseline after the base merge: the module is public and its route chains onto the attach route. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…br4q) (#19489) * test(settings): empty states and full text for clipped help and paths (cx-9br4q) Red on base: Accounts with no accounts, Harnesses while checking and a theme search with no match draw nothing; clipped help and folder paths carry no title. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(settings): polish pass on every page (cx-9br4q) - Buttons show a hover; MDM and token chips are small-radius rects, not capsules. - Accounts with none, Harnesses while checking and a theme search with no match say so instead of drawing nothing. - Card intros wrap; clipped help, subtitles and folder paths keep their full text as a tooltip; a refused chat root's reason is its own line. - Action and theme rows reserve the Reset slot, so their controls line up with the setting rows; account details line up under the account name. - Your Agents uses the page's buttons, pads its rows, drops the empty outline and draws the doctor's steps with the page's icons. - Profile rows highlight under the pointer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(settings): review fixes for the polish pass (cx-9br4q) - Action rows keep a long path and the Reset slot on one line. - Terminal paths carry their full text as a tooltip. - Only a collapsed profile row highlights, so an open form keeps its fields visible. - Empty lines are output elements, announced as status. - de and km use the page's existing word for theme. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-tui: agent-transfer-v1 forwards chat moves to acpmux with the daemon's own guard (cx-rppd.1) (#19460) * cmux-tui: behavior tests for guarded agent chat moves (agent-transfer-v1) Tests first for cmuxterm-hq#1874 slice 1 (cx-rppd.1): a trusted local client moves a chat through the daemon, which forwards only the guarded form of acpmux's transfer calls. The module is a stub that serves nothing, so the tests fail on their assertions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-tui: agent-transfer-v1 forwards chat moves to acpmux with the daemon's own guard The Move to Cloud pump (cmuxterm-hq#1874 slice 1, cx-rppd.1) moves a chat between two daemons' acpmux through these verbs. A receive always carries a guard the daemon builds: peer control rooted at $HOME/work on a Cloud host, web control rooted at the named folder (strictly under $HOME, not in a dot folder) elsewhere, and the folder must be under the roots. Finish uses the receive's own folder. Source verbs take the chat only from the surface's tab record, and begin serves the bundle manifest without absolute source paths. Trusted local clients only; no relay allowlist entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-tui: agent-transfer page check in clippy's preferred form Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-tui: tests for agent-transfer host kind, slots and bundle scrubbing Review of #19460: a receive must be refused on a team VM and on a Cloud VM of unknown kind (the hq-84 rule agent-session-start follows), at receive and again at finish; receive slots must not leak; begin must scrub session.json launch settings; read must serve only paths the begin manifest lists. These fail until the next commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-tui: agent-transfer follows the team VM rule and stops leaking slots Review of #19460: - receive and finish read agent-session-start's machine kind gate at each call and refuse on a team VM or a Cloud VM of unknown kind (hq-84), with start's codes: a peer-control chat keeps its policy and mode. - the receive cap is checked before acpmux makes a receive; a finish that fails for good drops its receive; agent-transfer-receive-abort forgets one (acpmux has no target-side abort); abort forgets the move even when acpmux refuses. - begin scrubs session.json launch settings (env, argv, harness roots, preset, tags) next to manifest.json sources, names compared case-insensitively, and read serves only paths the manifest lists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-tui: test that receive-abort has acpmux forget the receive's move acpmux now has a target-side transfer_forget (#19411). The daemon's receive-abort should forward it for the move named in the receive's own manifest, and acpmux's forget must stay unreachable as a daemon verb. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cmux-tui: receive-abort has acpmux forget the receive's move Forwards acpmux's target-side _acpmux/transfer_forget (#19411) with the transfer and session ids of the receive's own manifest, so acpmux drops the receive's files at once and refuses that move afterwards; acpmux's forget is not a daemon verb. A receive whose manifest lacks plain ids is a bad request. server.rs keeps to its god-file baseline after the base merge: the module is public and its route chains onto the attach route. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * fix: close the agent page's artifact frame CSS rule (chat pages render unstyled) (#19494) * test: every webviews stylesheet closes the rules it opens (red) feat-cmux-next's conversation.css leaves .acpmux-artifact-frame open since #19473; every rule after it is swallowed and chat pages render unstyled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: close the agent page's artifact frame rule (green) The unclosed .acpmux-artifact-frame block from #19473 swallowed the rest of conversation.css: the composer, code blocks and user rows lost their styles. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(next): PR autofix at 9ddddd6 - vp fmt webviews/test/stylesheets.test.ts Autofix-Run: https://github.com/manaflow-ai/cmux/actions/runs/38161397375 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-autofix[bot] <cmux-autofix[bot]@users.noreply.github.com>
Summary
A chat being moved (
acpmux.transfer.v1) is frozen on its source until the client pumping the move commits or aborts. If that client died (the app quit, the CLI was killed, the machine slept), the chat stayed frozen forever. Now the source watches each move it began and ends a move left idle for the lease (5 min):transfer_aborted {reason: "stalled"}) and the chat runs here again, its queue included.to: {socket}, which theacpmux transferCLI sends) with the new_acpmux/transfer_forget {transferId, sessionId}. The target drops any unfinished receive of the move, marks it so a later receive is refused (transfer.forgotten), and answers{landed}. Landed: the source commits. Not landed: it aborts. No answer (noto, target down, 30 s timeout): the chat stays frozen and the source asks again after another lease.alive,read,to).Commit is now idempotent on an already-closed chat. Backward compatible:
tois optional, and old clients get the partial-read abort.Testing
Behavior tests in
cmux-tui/crates/acpmux/tests/hub_integration/transfer.rs. Fleet,scripts/ci/cmux-tui-rust-check.sh --arg test|all --arg transfer:::FAILED. 2 passed; 3 failed(the three new tests time out; the chat stays frozen).all: fmt, clippy, tests):ok. 5 passed.FAILED. 4 passed; 1 failed(a forgotten move could be received again). Green 6982494 (all):ok. 5 passed.Crash ratchet:
panic_macro 33 -> 35in cmux-tui, which also fails on the merge base, so it comes from base and not this branch. God-file check: no touched file is listed.Reviewed by a subagent twice (correctness first). Known edge cases left as-is (all need the client to vanish mid-finish for longer than the lease): a watch commit and a client commit at the same moment can both record; a watch commit whose kill fails is not retried; a chat deleted on the target within the lease reads as not landed.
Changelog
none
closes cx-xtg0.9
🤖 Generated with Claude Code
Summary by cubic
A chat being moved (
acpmux.transfer.v1) is frozen on its source until the client pumping the move commits or aborts; if that client dies or goes away, the chat stays frozen forever. The source now watches each move it began and ends a move left idle for the lease (5 min):transfer_aborted {reason: "stalled"}) and the chat runs here again, its queue included.to: {socket}, sent by theacpmux transferCLI) with_acpmux/transfer_forget; the target drops any unfinished receive, refuses later ones, and answers whether the chat landed, which decides commit or abort.committed, and a forgotten move stays refused.tois optional and they get the partial-read abort.Written for commit 7a2ca8a. Summary will update on new commits.