Skip to content

cmux link agent move: stop a running turn only where it goes on; never mid-compaction - #30567

Merged
teamleaderleo merged 1 commit into
feat-cmux-nextfrom
lane/live-handoff-gates
Nov 1, 2026
Merged

teamleaderleo merged 1 commit into
feat-cmux-nextfrom
lane/live-handoff-gates

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

Follow-ups 2 and 3 of #30460, from the review of #30280 (receipt #30280 (comment)). That work is for cmuxterm-hq#5846 item 1. Leo, 2026-11-01: "those all seem good".

What changes

Since #30280, Move to Cloud and Bring Back Local always pass --interrupt, so a move stops a running turn and acpmux continues it where the chat lands. Two cases lost work:

  • An older source daemon (an un-updated Cloud machine on Bring Back) stopped the turn and queued no continuation, so the turn ended for good. The daemon now lists agent-transfer-continues-v1 beside the transfer verbs. The pump (cmux link agent move) sends interrupt only to a source whose identify lists it. Any other source gets no Stop and refuses the move while the turn runs (transfer.busy), as before acpmux: a move that stops a running turn continues it where the chat lands #30280.
  • A move while Claude compacts. The Stop's compaction branch (cancel.rs) withdraws the person's queued prompts. transfer_begin with interrupt now refuses while the chat is compacting (transfer.busy: the chat is compacting; move it once that ends), before anything is logged or stopped. The check is the same one cancel.rs makes.

spec/commands.md says both.

Tests

  • tests/link_agent_move.rs a_running_turn_is_stopped_only_on_a_source_that_continues_it: an older source's begin gets interrupt: false, one that lists the capability gets true, and with no flag it is never set.
  • tests/cli/agent_session_start.rs: a daemon that serves transfer lists agent-transfer-continues-v1.

cmux-ci receipt below.

Follow-ups (from its review, kept in #30460)

  • acpmux, not the daemon beside it, should say it continues a stopped turn: on a Cloud VM the two can update apart.
  • An acpmux test of the compaction refusal.
  • The narrow window between the compaction check and the Stop.

Changelog

none

🤖 Generated with Claude Code

Agent session: agent session


Summary by cubic

Fixes cmux link agent move so a move never stops a running turn unless the source's acpmux continues it where the chat lands, and never stops one mid-compaction.

  • The daemon now lists agent-transfer-continues-v1; the pump sends interrupt only to a source that lists it. An older source (an un-updated Cloud machine on Bring Back) would stop the turn for good, so there the move is refused while the turn runs, as before --interrupt.
  • A move with --interrupt is refused (transfer.busy: the chat is compacting) while the chat compacts, since the Stop would withdraw the person's queued prompts.
  • Both cases (and the capability) are documented in spec/commands.md.

Written for commit 588f353. Summary will update on new commits.

View guided diff Turn on auto-fix

…r mid-compaction

Follow-ups 2 and 3 of #30460 (review of #30280):
- The daemon lists agent-transfer-continues-v1 (its acpmux continues a turn a
  move stops). The pump sends `interrupt` only to a source that lists it; an
  older source (an un-updated Cloud machine on Bring Back) would stop the
  turn for good, so there the move is refused while the turn runs, as before.
- acpmux refuses a move with interrupt while the chat is compacting
  (transfer.busy): the Stop's compaction branch withdraws the person's queued
  prompts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-823b964b033ac6533d82
@github-actions github-actions Bot added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Nov 1, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (subagent claude-opus-5-5 medium): SHIP at 588f353

Independent read of the commit: the capability is listed exactly where the transfer verbs are served; a failed or missing identify means no interrupt, so an older source refuses the move as busy, as before #30280. The compaction check matches cancel.rs and runs before anything is logged or stopped; unfreeze(e, None) is right there. The child lock guard is a temporary (no lock across an await). The new pump test covers older, current and no-flag sources; the spec text is accurate.

Follow-ups (in #30460):

  • [follow-up] acpmux should advertise that it continues a stopped turn itself: on a Cloud VM the daemon and acpmux can update apart.
  • [follow-up] An acpmux test of the compaction refusal.
  • [follow-up] The narrow window between the compaction check and the Stop.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="cmux-tui/crates/cmux-tui/src/link/agent_cli.rs">

<violation number="1" location="cmux-tui/crates/cmux-tui/src/link/agent_cli.rs:503">
P1: This capability check can describe a different daemon than the `source` connection that receives `agent-transfer-begin`. If the socket is replaced between the two connects, an older source can receive `interrupt: true` and permanently lose the running turn; probe capabilities on the same connection used for `begin`, or verify the peer identity before using the result.</violation>
</file>

<file name="cmux-tui/crates/acpmux/src/hub/transfer_out.rs">

<violation number="1" location="cmux-tui/crates/acpmux/src/hub/transfer_out.rs:239">
P1: This is only a snapshot, so compaction can begin after the check but before `log_continuation` and the eventual `SESSION_CANCEL`; the transfer can therefore log and stop a turn during compaction instead of refusing it. Couple the compaction transition and Stop through a shared fence, or revalidate immediately before stopping and abort before logging when compaction has begun.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

/// say so, or does not answer `identify`.
fn source_continues(socket: &std::path::Path) -> bool {
let capability = cmux_tui_core::server::agent_transfer::AGENT_TRANSFER_CONTINUES_CAPABILITY;
let identity = super::machine_gate::identify(socket);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: This capability check can describe a different daemon than the source connection that receives agent-transfer-begin. If the socket is replaced between the two connects, an older source can receive interrupt: true and permanently lose the running turn; probe capabilities on the same connection used for begin, or verify the peer identity before using the result.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At cmux-tui/crates/cmux-tui/src/link/agent_cli.rs, line 503:

<comment>This capability check can describe a different daemon than the `source` connection that receives `agent-transfer-begin`. If the socket is replaced between the two connects, an older source can receive `interrupt: true` and permanently lose the running turn; probe capabilities on the same connection used for `begin`, or verify the peer identity before using the result.</comment>

<file context>
@@ -489,6 +496,14 @@ fn sync_frozen(sync: &Sync) -> Result<(), Failed> {
+/// say so, or does not answer `identify`.
+fn source_continues(socket: &std::path::Path) -> bool {
+    let capability = cmux_tui_core::server::agent_transfer::AGENT_TRANSFER_CONTINUES_CAPABILITY;
+    let identity = super::machine_gate::identify(socket);
+    identity.as_ref().and_then(super::machine_gate::served).is_some_and(|s| s.contains(&capability))
+}
</file context>

// A Stop while Claude compacts withdraws the person's queued prompts (`cancel.rs`):
// the move waits for the compaction instead of losing them.
let child = session.child.lock().await.clone();
let compacting = session.compacting.load(std::sync::atomic::Ordering::SeqCst)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: This is only a snapshot, so compaction can begin after the check but before log_continuation and the eventual SESSION_CANCEL; the transfer can therefore log and stop a turn during compaction instead of refusing it. Couple the compaction transition and Stop through a shared fence, or revalidate immediately before stopping and abort before logging when compaction has begun.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At cmux-tui/crates/acpmux/src/hub/transfer_out.rs, line 239:

<comment>This is only a snapshot, so compaction can begin after the check but before `log_continuation` and the eventual `SESSION_CANCEL`; the transfer can therefore log and stop a turn during compaction instead of refusing it. Couple the compaction transition and Stop through a shared fence, or revalidate immediately before stopping and abort before logging when compaction has begun.</comment>

<file context>
@@ -233,6 +233,15 @@ impl Hub {
+            // A Stop while Claude compacts withdraws the person's queued prompts (`cancel.rs`):
+            // the move waits for the compaction instead of losing them.
+            let child = session.child.lock().await.clone();
+            let compacting = session.compacting.load(std::sync::atomic::Ordering::SeqCst)
+                || child.is_some_and(|c| c.translator.as_ref().is_some_and(|t| t.is_compacting()));
+            if compacting {
</file context>

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

CI at 588f353 (https://github.com/manaflow-ai/cmux/actions/runs/41292530431): clippy -D warnings shows no hits in this PR's files (CLIPPY_OURS=0; the hits are base's, in agent_tools.rs, cloud_repo_mcp.rs, remote_guard.rs, cloud_repos/*, agent_session_folders.rs, from #30361/#30363, fixed on base by #30528). link_agent_move 15 passed (the new gate test included), cloud_move_journey 3 and bring_back_journey 2 passed, cli agent_session_start 38 of 39 passed.

The one failure, agent_session_start::a_first_chat_on_the_callers_own_cloud_vm_starts_in_its_trusted_work_folder (assert!(work.is_dir(), "the work folder was not made"), base line 510), is base's: #30363 (efd30f5) made a home-folder start on the caller's own Cloud VM create ~/chats/<id> instead of the work folder and did not update this test. This PR changes neither that test nor agent-session-start.

@teamleaderleo
teamleaderleo merged commit 7e0a0f2 into feat-cmux-next Nov 1, 2026
31 of 32 checks passed
@teamleaderleo
teamleaderleo deleted the lane/live-handoff-gates branch November 1, 2026 09:26
@cursor

cursor Bot commented Nov 1, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot 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.

@github-actions

github-actions Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

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

Review 588f353: 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=pr30567 -f ref=lane/live-handoff-gates -f platform=macos -f backend_mode=local

Shipped in:

@blacksmith-sh

blacksmith-sh Bot commented Nov 1, 2026

Copy link
Copy Markdown

Found 7 test failures on Blacksmith runners:

Failures

Test View Logs
nightly must build and hand off the macOS 26 helper and Xcode 26.5 app before publishin
g/
nightly must build and hand off the macOS 26 helper and Xcode 26.5 app before publishin
g
View Logs
test_each_app_reads_the_feed_its_publisher_writes: AssertionError()/
test_each_app_reads_the_feed_its_publisher_writes: AssertionError()
View Logs
test_every_compile_job_names_its_warm_sources (main.ThisTree.test_every_compile_job
_names_its_warm_sources)/
test_every_compile_job_names_its_warm_sources (main.ThisTree.test_every_compile_job
_names_its_warm_sources)
View Logs
test_helper_never_takes_a_hosted_mac_and_skips_compile_on_hit (main.WorkflowTests.t
est_helper_never_takes_a_hosted_mac_and_skips_compile_on_hit)/
test_helper_never_takes_a_hosted_mac_and_skips_compile_on_hit (main.WorkflowTests.t
est_helper_never_takes_a_hosted_mac_and_skips_compile_on_hit)
View Logs
test_the_nightly_is_covered (main.NightlyStepCoverageTests.test_the_nightly_is_cove
red)/
test_the_nightly_is_covered (main.NightlyStepCoverageTests.test_the_nightly_is_cove
red)
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
test_under_githubs_limit_with_headroom (main.NightlyWorkflowSize.test_under_githubs
_limit_with_headroom)/
test_under_githubs_limit_with_headroom (main.NightlyWorkflowSize.test_under_githubs
_limit_with_headroom)
View Logs

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

This branch was previously deployed

1 inactive deployment
ci-routing-agent — 588f3534 Deployed Nov 1, 2026 by teamleaderleo via cmux-tui tree preflight #95020
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