Skip to content

acpmux, agent pane: a question answered in the pane counts on another machine - #23869

Closed
teamleaderleo wants to merge 7 commits into
feat-cmux-nextfrom
cmux/pane-person-proof
Closed

teamleaderleo wants to merge 7 commits into
feat-cmux-nextfrom
cmux/pane-person-proof

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Answering an agent's question in the Mac app's chat pane failed for a chat on an ssh peer (Leo hit it live on huge-blue): the peer's acpmux refused it with "approve this on the Mac app: allowing a permission is accepted only from the cmux app".

Cause

A chat on another machine gets its answers through a connection that is never the person, so the peer counts an allow only with the person's decision proof (cx-0q7o). That proof never covered question answers: person_decided and respond_permission refused any proof when answers was present. Every AskUserQuestion answered in the pane for a peer chat was refused. The rule dates from the design (9c4543d), not a recent change.

Fix

  • acpmux: a new proof acpmux-person-decision-answers-v1 covers the answers too: the allow's five parts plus the sha256 of the canonical answers JSON, the same digest a phone's signed answer uses (approvers::answers_digest). An answer counts only under that proof, so a relay still cannot swap the answers; a plain allow keeps the v1 proof. Nonces are still spent once, under the prompt's lock.
  • Mac pane: signRelayedAllow signs a frame's answers with the bound key (AcpmuxSecretKey.decisionProof(..., answers:), canonical JSON byte-for-byte as acpmux's).
  • A shared vector (the same key, inputs and expected proof in a Rust and a Swift test) keeps the two sides' bytes equal.
  • Pane page: an answer now takes the person's gesture ticket for its session, prompt and option, as an option pick does (direct.ts), and the Swift pick no longer skips frames with answers (AgentPaneGestureIntent.swift). Without the ticket the host never signed the answer, so the first fix alone did not reach the peer (the review caught this).

The ticket covers the click on the option, not the answers themselves: the page fills the answers in after the person's click, which is the same trust the local daemon already gives the page. The proof then binds those exact answers, so nothing past the host can change them. answeredBy is not covered by the proof, as with plain allows.

The peer must run an acpmux with this change; an older peer keeps refusing the same way.

Tests

  • cargo test -p acpmux --test person_allow a_relayed_answer_counts_with_the_persons_proof_over_exactly_its_answers and the_answers_decision_proof_matches_the_apps_vector: red on f078763 (the test commit; the answer is refused, the vector does not compile), green on the head.
  • Web: cd webviews && bun test src/agent-session/acpmux/questionAnswerTicket.test.ts: red at bf80b32 (fleet step ff550a72710e1b8e2ae50508: "a question's answer carries the person's ticket for its session, prompt and option" fails), green at 8028cf3 (0 failed).
  • Swift: AgentPaneRelayedAllowTests anAnswerToAnotherMachinesQuestionCarriesTheProofOverItsAnswers and theAnswersProofMatchesAcpmuxsVector.

Observed / Not run

  • Observed: fleet cmux-ci compile-check --app passed at 8028cf3 (job b352dc53c1eaf8fe20455a0d). Independent review: SHIP at 8028cf3. scripts/cmux-next/prepush-gate.py passes; rustfmt --check is clean. The Rust vector was computed independently with Python (HMAC-SHA256 over the canonical JSON).
  • Not run on this Mac: the cargo and Swift tests above (no local builds here); they run on CI for this head. Not dogfooded against huge-blue.
  • Reds at this head that are not this PR's: cmux-next crash-class rules (CEFFileDragRelay.swift:162 needs a selector probe), cmux-next web bundles and react-apps-check (inspector/ContextSection.css is missing from build-agent-pane-web.sh), and cmux-next CI guard group (workflow-guard-tests on workflow files). None of those files are in this diff.

No capture: the change is in the proof and the gesture plumbing, and the question card looks the same.

Changelog

Fixed: Answering an agent's question in a chat on another machine no longer fails with "accepted only from the cmux app".

risk:high: this changes what the person's decision proof covers (auth).

Agent session: cosmic-gray

🤖 Generated with Claude Code


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


Summary by cubic

Fixes answering an agent's question in the Mac app's chat pane for a chat on another machine, which the peer's acpmux always refused with "accepted only from the cmux app".

A relayed allow's decision proof never covered question answers. The pane now signs an answer with acpmux-person-decision-answers-v1 — the allow's five parts plus the sha256 of the canonical answers JSON — and acpmux counts an answer only under that proof, so a relay cannot swap the answers. An answer also takes the person's gesture ticket for its session, prompt and option, as an option pick does.

The answer's answers now reach that machine's acpmux: RemoteAcpmuxWire and agent-session-permission previously dropped or refused them, so the peer checked the answers proof against a plain allow and refused the answer. The daemon passes a JSON object of at most 64 KiB to acpmux unchanged.

The peer must run an acpmux with this change; an older peer still refuses the answer.

Written for commit 5afde6f. Summary will update on new commits.

View guided diff Turn on auto-fix

teamleaderleo and others added 2 commits October 21, 2026 15:47
…proof over its answers (fails: answers are never covered)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bdd-880a-7a72-b582-c0a285babfd6&host=cosmic-gray
… machine (the proof covers the answers)

Answering an agent's question in the Mac pane for a chat on an ssh peer was
refused by the peer as "accepted only from the cmux app": a relayed decision
proof never covered question answers. The pane now signs the answers too
(acpmux-person-decision-answers-v1, the sha256 of the canonical answers JSON as
a phone's signed answer has it), and acpmux counts such an answer only under
that proof, so a relay still cannot swap the answers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bdd-880a-7a72-b582-c0a285babfd6&host=cosmic-gray
@teamleaderleo teamleaderleo added the risk:high Risk tier (docs/ci/risk-tiers.md) label Oct 21, 2026
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 21, 2026 23:49 — with GitHub Actions Inactive
@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

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

Review 5afde6f: 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=pr23869 -f ref=cmux/pane-person-proof -f platform=macos -f backend_mode=local

Unclear: web / react-apps-check failed: no known signature; failed step: Check webview test shards.

CI failed on 5afde6fc34 (run 39841951809 attempt 1): 1 code, 1 unknown.

Job Verdict Why
web / react-apps-check (1) code a web test failed
web / react-apps-check unknown no known signature; failed step: Check webview test shards

Failures:

  • seen on other PRs agent-pane-jump-latest-motion.test.ts chromium: a reply streaming in during Jump to latest's glide is followed to its latest row: failed (job)
  • seen on other PRs agent-pane-jump-latest-motion.test.ts webkit: a reply streaming in during Jump to latest's glide is followed to its latest row: failed (job)
  • seen on other PRs agent-pane-no-capsules.test.ts agent pane page > rounds its controls as small-radius rects, not capsules: failed (job)
  • seen on other PRs agent-pane-peer-chat.test.ts a chat on an SSH machine > counts its running turn from the prompt and offers no machine switch mid-...: failed (job)
  • seen on other PRs composer-edges.test.ts composer card: appearance.borders = none draws no edge: failed (job)
  • seen on other PRs composer-edges.test.ts composer card: one hairline edge by default: failed (job)
  • seen on other PRs composer-foot-pill-inset.test.ts the row's padding is counted from the inset, so only the pill grows, not the text's place: failed (job)
  • seen on other PRs composer-location-strip.test.ts the chat composer: no hairline across the seam under the strip: failed (job)
Matched log lines
web / react-apps-check (1): (fail) chromium: a reply streaming in during Jump to latest's glide is followed to its latest row [5154.14ms]

Not re-run automatically: web / react-apps-check (1), web / react-apps-check are not machine failures.

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); signatures are its SIGNATURES table. A machine verdict is the runner's fault, not this PR's; yours means the failing file is one this PR changes, also red on main that main's latest full suite fails the same way, seen on other PRs that it failed on another pull request's run lately.

red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on 44fc3d3 to compare; do not merge until green; see lane-rules
red: web / Web status; NEW: green on the base 44fc3d3; do not merge until green; see lane-rules
red: web / react-apps-check; no finished base run on 44fc3d3 to compare; do not merge until green; see lane-rules
red: web / react-apps-check (1); no finished base run on 44fc3d3 to compare; do not merge until green; see lane-rules

Gallery before/after for 5afde6f: 16 states rendered, 3 images differ, 1587 more touched states not rendered. Images are in the run's artifact, not on this public PR.

gh run download 39841951518 -R manaflow-ai/cmux -n gallery-advisory-23869-5afde6fc3410a25165e28debb126b1abe800af29 (then read gallery-review.json)

States
State Theme Status Diff Picked by
agent-pane.chat-width/standard Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.chat-width/standard Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.chat-width/wide Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.chat-width/wide Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.chat-width/wide-blocks Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.chat-width/wide-blocks Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.composer-floats/scrolled-to-end Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.composer-floats/scrolled-to-end Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.composer-floats/composer-grown Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.composer-floats/composer-grown Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.docked-chat/new-chat Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.docked-chat/new-chat Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.docked-chat/after-turn Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.docked-chat/after-turn Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.docked-chat/working Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.docked-chat/working Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.docked-chat/typing-in-dock Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.docked-chat/typing-in-dock Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.docked-chat/long-title Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.docked-chat/long-title Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.inspector/chat-menu Apple System Colors changed 0% imports direct.ts (1 hops)
agent-pane.inspector/chat-menu Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.inspector/wire-log Apple System Colors changed 0.0342% imports direct.ts (1 hops)
agent-pane.inspector/wire-log Apple System Colors Light changed 0.017% imports direct.ts (1 hops)
agent-pane.orchestration-lab/local-queue Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.orchestration-lab/local-queue Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.orchestration-lab/build-box Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.orchestration-lab/build-box Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.orchestration-lab/cloud-fair-share Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.orchestration-lab/cloud-fair-share Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.permission-panel/buttons-current Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.permission-panel/buttons-current Apple System Colors unchanged 0% imports direct.ts (1 hops)

Pick other states with a Gallery: entry.id, entry.id/variant line in the PR body.

@github-actions github-actions Bot added risk:normal Risk tier (docs/ci/risk-tiers.md) and removed risk:high Risk tier (docs/ci/risk-tiers.md) labels Oct 21, 2026
@blacksmith-sh

blacksmith-sh Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Found 47 test failures on Blacksmith runners:

Failures

Test View Logs
---/--- View Logs
---/--- View Logs
---/--- View Logs
---/--- View Logs
---/--- View Logs
---/--- View Logs
---/--- View Logs
---/--- View Logs
---/--- View Logs
/tmp/tmp_6wzvvy2/summary-missing.json (live):/summary-missing.json (live): View Logs

...and 37 more test failures. View all on Blacksmith: run 39841951723, run 39841951809, run 39841951667

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

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next crash-class rules / cmux-next crash-class rules is red on 8 of 8 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next guards / cmux-next localization debt ratchet is red on 14 of 15 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

@teamleaderleo

teamleaderleo commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator Author

Owned by hb-acpmux on big-red · session

…re ticket (fails: no ticket is taken with answers)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bdd-880a-7a72-b582-c0a285babfd6&host=cosmic-gray
…s pick ignores the answers, so the host signs it for another machine (review of #23869); the test key parses before it allocates

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bdd-880a-7a72-b582-c0a285babfd6&host=cosmic-gray
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (independent subagent): SHIP at 8028cf3. Fleet compile-check --app passed at that head (job b352dc53c1eaf8fe20455a0d). Reds at this head are base: crash-class rules (CEFFileDragRelay.swift:162 selector probe), web bundles/react-apps-check (inspector/ContextSection.css missing from build-agent-pane-web.sh), CI guard group (workflow-guard-tests); none of those files are in this diff.

…aemon with its answers

RemoteAcpmuxWire drops a relayed answer's answers before agent-session-permission, and the
daemon's verb refuses the field, so that machine's acpmux checks the answers proof against a
plain allow and refuses it. Red at this commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bdd-880a-7a72-b582-c0a285babfd6&host=cosmic-gray
RemoteAcpmuxWire passed a relayed answer's option and proof to the owning session daemon but
dropped its answers, and agent-session-permission had no answers field, so that machine's acpmux
verified the answers proof against a plain allow and refused the answer (Codex review of #23869).
The wire now hands the answers to AgentSessionRemoteClient.permission, AgentSessionAttachClient
sends them, and the daemon passes a JSON object of at most 64 KiB to acpmux unchanged; acpmux
still checks them against the question and the proof over them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bdd-880a-7a72-b582-c0a285babfd6&host=cosmic-gray
@cursor

cursor Bot commented Oct 22, 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.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Orphaned: no activity for 15 h, and no lane holds a lease on it. Adopted by the orphan sweep: merged feat-cmux-next in at 5afde6f. A later pass queues it for the merge hub if it is reviewed, small and red only on base reds.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next guards / nightly-guards / workflow-guard-tests / release-notary is red on 21 of 22 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next / cmux-next checks (god files, concurrency, crash safety, l10n) › Checks job structure is red on 19 of 19 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next / cmux-next checks (god files, concurrency, crash safety, l10n) › No fleet host names in gallery fixtures is red on 17 of 17 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next / cmux-next checks (god files, concurrency, crash safety, l10n) › No new SwiftUI (macOS UI is AppKit) is red on 17 of 17 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next / cmux-next swift test is red on 12 of 17 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Re-cut as #25424, rebased onto feat-cmux-next. This branch isn't under the adopting lane's push prefix, so the work moves there. Credit for the work stays with this PR. Adopted by hb-acpmux after the stale-pr-reconciler flagged this PR as orphaned.

teamleaderleo added a commit that referenced this pull request Oct 26, 2026
…hine carries the person proof over its answers and annotations

Re-cut of #23869 (cosmic-gray lane), pane side; the daemon side is its own PR.
The pane signs a relayed answer with acpmux-person-decision-answers-v1 over
its answers and annotations, its gesture ticket binds those (by the sha256 of
their canonical bytes), and the remote wire and the session daemon client
carry both to that machine.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 26, 2026
…er the person proof over its answers and annotations

Re-cut of #23869 (cosmic-gray lane), daemon side; the pane side is its own PR.
A relayed AskUserQuestion answer was refused because the person decision
proof (cx-0q7o) never covered answers. acpmux-person-decision-answers-v1
covers the answers digest, and the annotations digest when there are any;
annotations from a connection that is not the person count only under it.
cmux-tui agent-session-permission carries answers and annotations to acpmux
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 26, 2026
…hine carries the person proof over its answers and annotations

Re-cut of #23869 (cosmic-gray lane), pane side; the daemon side is its own PR.
The pane signs a relayed answer with acpmux-person-decision-answers-v1 over
its answers and annotations, its gesture ticket binds those (by the sha256 of
their canonical bytes), and the remote wire and the session daemon client
carry both to that machine.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 26, 2026
…er the person's proof (re-cut of #23869, daemon side) (#25424)

* acpmux: a question answered in the pane counts on another machine under the person proof over its answers and annotations

Re-cut of #23869 (cosmic-gray lane), daemon side; the pane side is its own PR.
A relayed AskUserQuestion answer was refused because the person decision
proof (cx-0q7o) never covered answers. acpmux-person-decision-answers-v1
covers the answers digest, and the annotations digest when there are any;
annotations from a connection that is not the person count only under it.
cmux-tui agent-session-permission carries answers and annotations to acpmux
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* acpmux tests: rustfmt

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 26, 2026
…hine carries the person's proof (re-cut of #23869, pane side) (#25440)

* agent pane: a question answered in the pane for a chat on another machine carries the person proof over its answers and annotations

Re-cut of #23869 (cosmic-gray lane), pane side; the daemon side is its own PR.
The pane signs a relayed answer with acpmux-person-decision-answers-v1 over
its answers and annotations, its gesture ticket binds those (by the sha256 of
their canonical bytes), and the remote wire and the session daemon client
carry both to that machine.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* agent pane: the answers proof extension is nonisolated, so the gesture pick (nonisolated) can take a digest

The Release compile refused canonicalDigest from AgentPaneGestureIntent and
AgentPaneGesturePick: the extension took the module default (main actor).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* agent pane tests: no nested #require (recursive macro expansion), and the presence test client takes answers and annotations

Rebased onto feat-cmux-next, which added RemoteAcpmuxPresenceTests (#25375)
with its own AgentSessionRemoteClient.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

This branch had an error being deployed

1 failed and 3 inactive deployments
ci-routing-agent — 5afde6fc Deployed Oct 22, 2026 by github-actions[bot] via cmux-next macOS placement #30755
artifacts — 5afde6fc Deployed Oct 22, 2026 by teamleaderleo via publish tree-addressed cmux-tui #44276
sentry-dsyms — 5afde6fc Deployed Oct 22, 2026 by teamleaderleo via upload cmux-tui dSYMs to Sentry #44276
cmux-tui-merge-tree — 5afde6fc Deployed Oct 22, 2026 by teamleaderleo via publish the merge tree #4931
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant