Pane policy: policy.json matches the macOS host's params, with a Swift parity test (cx-ctddg)
cx-ctddg. The Rust pane policy (cmux-agent-pane-policy/policy.json) had drifted from the macOS host's tables (AcpmuxPaneMethods.requests and knownParams). Those Swift tables are what enforce the pane's frames today. The Swift side of the parity tests was deleted, so nothing caught the drift. #20644 broke local chats when the two sides disagreed (cx-ibngi).
Change
- New test,
tests/swift.rs: reads both Swift tables and asserts thatpolicy.json'srequestsandknown_paramsequal them. policy.json: gains the four params Swift already allows (scoping below).src/params.rs: a_acpmux/permission_respond_metamust hold the pick's gesture ticket and nothing else. This is the same rule as Swift'sbreaksParamsRule. Without it, adding_metato the list would have let anacpmuxkey through.tests/cases/params.json:- the "every known param" cases now include the new params;
- two new cases must break:
_metawith more than the ticket, and_metawithout it.
tests/typescript.rs: base has since fixed the same allowlist scan oftypedRequestcalls (6bf943f, cx-js8uc). After the base merge this file is identical to base.
Review fixes
- Gesture pick,
src/check.rs:GesturePick::newgains Swift'sAgentPaneGesturePickbranch for_acpmux/permission_respond. Its pick is{sessionId, permissionId, optionId}, and there is no pick when it carriesanswers. Before, Rust droppedsessionIdfrom the pick, and this PR's_metaparam made that path reachable. src/lib.rs: says hosts strip asession/new's_meta.acpmux.noProjectin their folder step, asAcpmuxPathPolicydoes.- Stale references: the deleted
AgentPanePolicyParityTestsis no longer cited inpolicy.json's description,lib.rs, or the SwiftcheckOnedoc comment. That comment is the only Swift change. - More params cases:
_meta: {}on permission_respond breaks; a non-string ticket passes the params rule, as in Swift.
Scoping of each added param
Swift already allows each of these with the same reason, and no new method is added.
| Method | Param | What it does | Scope |
|---|---|---|---|
session/new | _meta.acpmux.noProject | The pane's "Do not work in a project". The host's path policy reads and strips it. | Before any session exists, so no session scope. Grants no folder. |
session/prompt | _meta.acpmux.context | A chat's workspace context on its first prompt (cx-ihyx2). acpmux sends it to the agent and keeps it out of the transcript text. | The prompt's sessionId must be the pane's (session_scoped). |
_acpmux/models | refresh | The picker's Refresh models: acpmux runs again the model probes it already runs in the background. | Grants nothing, so no gesture rule. |
_acpmux/permission_respond | _meta | Only the gesture ticket of the person's pick (cx-0q7o). | Any other key, or no ticket, breaks the params rule. The ticket is checked against the pick. |
Verification
All runs were on the Linux builder, with the same focused command:
cargo test -q -p cmux-agent-pane-policy --test swift
| Commit | Result |
|---|---|
| Red, 3eda6d1 | The requests check passes. the_known_params_are_the_macos_hosts fails on exactly the four params above. |
| Green, the fix | 2 passed. |
Gesture pick, with the focused command cargo test -q -p cmux-agent-pane-policy --test parity full_check_order:
| Commit | Result |
|---|---|
| Red, c12cf36 | Fails on "a ticketed permission answer binds its pick…". The got pick is {optionId, permissionId}; the expected pick also names sessionId: s1. |
| Green, 9035b2b | 1 passed. |
On the fix:
- the crate's full tests pass: parity 16, swift 2, typescript 4;
- rustfmt is clean;
- the crash ratchet is ok.
The only Swift change is one doc comment. sbx build on the merged head (base dbb1123) completes. On the merged head, the crate passes 16 + 2 + 4 and rustfmt is clean. No host runs the Rust policy's frame check at runtime today, so nothing changes for users.
Defaults snapshot
This PR does not change schemas/defaults/cmux-next.json. The autofix bot added a line recording Lawrence's existing key.home.switchView default, and I dropped it. A red defaults-snapshot check here is the base red for that missing record, not a new default from this PR.
Changelog
none
🤖 Generated with Claude Code
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Restores parity between the Rust pane policy (policy.json) and the macOS host's Swift tables, which enforce the pane's frames today. The Swift parity tests were deleted, so nothing caught the drift — #20644 broke local chats when the two sides disagreed (cx-ibngi).
- Adds
tests/swift.rs, which assertspolicy.json's requests and known params equal the Swift tables. - Adds the four params Swift already allowed:
session/newnoProject,session/promptcontext,_acpmux/modelsrefresh, and_acpmux/permission_respond_meta. - Enforces that
_acpmux/permission_respond_metaholds the gesture ticket and nothing else, matching Swift'sbreaksParamsRule. - Makes a permission answer's gesture pick name its session, permission, and option — and pick nothing when it carries
answers— matching Swift'sAgentPaneGesturePick. - The allowlist test now also reads the method each
typedRequestcall indirect.tsnames, fixing a pre-existing red test after #20576 moved_acpmux/permission_respondto that helper. - Documents in
lib.rsthat hosts strip asession/new's_meta.acpmux.noProjectin their folder step, and drops stale references to the deletedAgentPanePolicyParityTests(including the SwiftcheckOnecomment).
No Swift behavior changes, and no host runs the Rust policy's frame check at runtime, so nothing changes for users.