Repository navigation
Require local Allow for Phone Access on this Mac - #25437
Conversation
Re-cut the per-Mac phone admission intent from #21898 and the sole-user question binding from #23552 on current base. Hold for Leo’s product decision. Preserve hostd phone credentials and exclude Iroh entries from approval authority. Agent-Session: https://cmux.com/deeplink/agent?id=aid-fa0019a44432440c6217
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Gallery before/after for
States
Pick other states with a Passes: CI passes on CI passes on Written by web and size checks: green Default changesThis pull request changes 3 defaults at
Signed off on this commit by Merge receipt: merged as Regenerate the snapshot with Shipped in:
|
|
Bead |
|
Orphaned: no activity for 13 h, and no lane holds a lease on it. The orphan sweep could not merge |
|
For awareness: #27297 (iOS host wake) adds an independent wake observer/control line and a NEXT keep-awake reason in the same MobileHostSupervisor/IPhoneHostService files. It doesn't touch admission or credentials, so this PR's local Allow gate is unaffected. When merging, keep both initializer additions. |
|
Owned by an agent session · took over from an earlier session · session |
|
Independent review (codex gpt-6.1-sol high; Astra via SR2 hung): BLOCK at c260dfa Summary: Adds per-user persisted phone admission and gates Iroh sessions on a local Allow. Findings, most severe first:
The current tip also materially rewrites this area and removes/replaces several PR-added files; the three-way comparison reports conflicts in the touched AppDelegate, pairing, supervisor, device-list, and service files. |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-006fc1b94bdcbe5a7e87
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-006fc1b94bdcbe5a7e87
Keep removals and sealed writes ordered through the paired-device queue. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-006fc1b94bdcbe5a7e87
Route Iroh removals through the synchronous admission marker. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-006fc1b94bdcbe5a7e87
Exercise removal during load and restoration of older sealed bytes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-006fc1b94bdcbe5a7e87
… that ended Turning Phone Access off cancels its open questions one hop later. If it came back on first, that hop cancelled the new period's questions too; an account switch's reconciliation likewise cancelled questions asked since the switch. Each now cancels only questions from an ended serving period or an earlier account, and the per-phone admission tokens keep counting up instead of resetting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… tests only Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An account switch is already settled by the generation check (its questions cancelled, the listener restarted), so its removal event no longer runs the removal loop. A real removal stops as soon as another account is selected, including while a disconnect is suspended, so it cannot cancel or disconnect the new account's phone. Store change events now carry their account generation and whether they are an account switch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Account switches rely on the listener restart to end the old account's phone links, but stopHost() fired its teardown and forgot it, so a quick sign-out and sign-in (or off and on) could start the new listener while the old one still served. The teardown is now kept and the next start waits for it. Also fix the new account-switch test's capture of a var in a Sendable closure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A start that a quicker one cancelled still had its old listener stopping inside the cancelled task, outside `stopping`, so the next listener could start beside it. Every teardown, from a stop or a restart, now goes through one chain that each new listener awaits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
savePaired queued its store edit from a Task, so a Remove in Settings > Mobile made in the same main-actor turn reached the queue first, and the later approval started after the removal and could restore the phone. MobileHostPairedStore.submit queues the edit before it returns, and savePaired uses it, so the removal wins as it did before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bugbot needs on-demand usage enabledBugbot 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. |
|
Review (codex gpt-6-astra high): SHIP at 252c251 The listener-teardown, account-switch cleanup, legacy approval/removal ordering and admission cancellation findings from earlier heads are resolved. A fleet app compile passed at this head. Follow-ups:
|
Phone rows now stay listed while the host is off so they can still be removed, so the step that checks the card turned off now passes no phones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bugbot needs on-demand usage enabledBugbot 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. |
|
Review (codex gpt-6-astra high): SHIP at b2a476b The listener-teardown, account-switch cleanup, legacy approval/removal ordering and admission cancellation findings from earlier heads are resolved. A fleet app compile passed at 252c251; this head adds only a webview test fixture fix (phone rows stay listed while off). Follow-ups:
|
…se-quit-flush Port of #28275 onto feat (lead decision 05:20Z), keeping feat's state-file and quit work and adding only what this PR adds beyond it: - AgentUnsentDrafts: feat's #28204 undelivered drafts and unreadable-file set-aside, on this PR's per-app AgentPaneStateFiles (no static registry). - QuitCoordinator: feat's #22919 QuitStepLimiter, time-left reply margin, launch marks and engineCloseWait, plus this PR's drains of the state files around the engine close, the testable quitSteps() (was steps(), which now names feat's limiter) and closeEngines seam, and the deadline end that records cut-off files. - AppDelegate/AppServices: feat's openedURLs, windowRecord, peer approver and injected key window; this PR's secondSignalExit (no blocking flush in prepare) and the state-files owner and loss record. - Paired phones: feat's #25437 MobileHostPairedStore now owns the directory's one MobileHostPairedDevicesFile (configure(directory:lastQuitCutOff: cutOffSettled:)); the iPhone host takes it from the store for the quit watch, so the shared-list transactions and this PR's cut-off accounting use one file object and one queue (an instance enqueue that counts as saving), not two.
Leo, asked "should Phone Access ask on this Mac before serving a new phone on your account?", answered: "probably? you can decide". Decided: yes, an unfamiliar phone waits for a local Allow on this Mac.
Leo's words for the iOS/remote push: "well i just think we can improve it a f***ton more than it is now... it's slow it's bad it belabours the point in too many tooltips it's ugly in places it doesn't even work in places there's lots of functionality that needs to get in"
What changes
Phone Access currently serves same-account MobileIrx peers without a local decision on this Mac. With this PR, an unfamiliar TLS-proved phone endpoint waits for a person's Allow on this Mac. The decision is saved in the shared per-user/per-Mac phone list, and removing the phone in Settings > Mobile closes its sessions and makes it ask again.
This adds a local Allow gate to the existing Iroh phone transport (MobileIrxHost, already on base). It adds no new Iroh machine-to-machine use.
Credits the intent of #21898 and the sole-user ownership/question-binding fix from #23552. From #21898:
Screens
Before: no prompt; a same-account phone is served with no decision on this Mac.
After (dark, 2x, synthetic device and account), from
PhoneAdmissionCaptureTestson a fleet Mac at this head's app code. I viewed it before landing:The light capture draws the shared dialog's glass-layer title and buttons blank in an offscreen render. That happens in the existing
CmuxDialogView, which this PR does not change, so it isn't shown here.Validation at
49bcf768a371a604a541b607b0ee3e551905c3f7fc52c2a3(the last commit only adds two entries toscripts/localization-allowed-omissions.json).fc52c2a3, all passed: CmuxNextMobileHostTests (44 tests, 10 suites) and CmuxNextMobileTests (93 tests, 18 suites), which include PhoneAdmissionTests, PhoneAdmissionCaptureTests, PhoneAdmissionStoreTests and PhoneAccessGateTests; PhoneAccessMigrationTests and PhoneAccessSettingTests in a separate run.88d80eca).fc52c2a3: the new labels "%@ · cmux next" and "%@ · cmux (iOS)" copied English into 8 locales each.49bcf768lists them as brand literals, so IPhone.xcstrings stays at its baseline of 19.88d80eca(full PR, including both earlier BLOCK findings),f016131(capture test),fd115828andfc52c2a3(hand-resolvedfeat-cmux-nextupdates; both sides of each conflict are kept), and49bcf768(the localization entries).Changelog
Added: Phone Access asks once on this Mac for each unfamiliar phone, and Settings > Mobile can forget it.
Agent session: agent session
🤖 Generated with Claude Code