cmux NEXT Cloud: owner answer on the app-server link (cmux-platform#89 C1)
Part C1 of manaflow-ai/cmux-platform#89 (the app side of the caller-ownership answer). Leo, 2026-10-30, on building the app-server cloud path now instead of after the Oct 31 demo: "well why can't we just.... do our best now?"
What
On the Cloud app-server link, every app-started chat and every folder-trust call on a Worker machine was refused with agent_session.host_unverified ("the Cloud API did not say this machine is yours"). The cause: AgentTabs+Wiring.swift built the owner closure only from the legacy link (CloudMachineSession.link), which is nil on an app-server session, so AgentSessionAttachClient.ownerAnswer always refused (cmux#27778 review, comment 6514080989).
This PR reads the owner answer on the app link, with the same rules as the legacy link:
CloudConnectOpResolverdecodesvm_kindfrom the Cloud app server'scloud.machine.connectanswer. Only the exact valueowner(the classic attach answer's value) setsCloudLinkSocket.callerOwnsVM. An absent, empty, differently cased or padded value, or any other kind, does not.CloudLinkSession.ownerLinkis the current connect's id while that link is up (ready or attached) and its answer said owner, else nil. The attach client reads it before it connects and again as it sends, so the answer never outlives its link: a newer connect gets a new id, and adownorrevokedchange, a pause (end) or a second endpoint call ends it.CloudMachineSession.ownerLinkanswers from whichever link the session has (legacy or app link).AgentTabs+Wiringuses it.
Until the server side sends vm_kind (piece A: cmux#27940 on the Worker and cmux#27943 on the Cloud app server), nothing changes: the answer stays nil and the start is refused as before. Nothing here grants owner privileges without that exact answer.
Risk
risk:high (an owner/auth decision). Ownership stays a server answer, so the client can't widen it: no answer, or any value other than owner, still refuses. The legacy path keeps the same closure.
Tests
CloudAppLinkOwnerAnswerTests (CmuxNextAppTests), committed red first (2671109afe3) before the fix:
- only an exact
ownervalue marks the connect as owned (absent, "", "Owner", " owner", "teammate", "team", "guest" do not); - the answer holds only while its own connect is up: a new connect gets a new id; a down, a revoke and a pause end it;
- a connect whose answer doesn't say owner gives no answer;
- an app-link
CloudMachineSessionanswers for its own link.
Observed / Not run
- Observed:
scripts/cmux-next/prepush-gate.py: no new violations (app-size warning only, +8 App lines). - Not run yet: the Swift suite on the fleet (this lane VM can't run it). The CI results at the head go in a comment.
- Not run: an end-to-end start on a Worker machine. That needs piece A's server answer.
Changelog
none (the app-server link is a Debug-only path today)
No capture: no UI change.
š¤ Generated with Claude Code
Agent session: agent session