cmux-next iPhone: Feed answers reach the Mac that asked; Home names each Chief's and chat's Mac

Merged
AZ
16d ago
+1036-100

With two Macs on one account, the iPhone app's Feed refused every inline answer with "Not connected to your Mac. Nothing was sent." even while both Macs read "Connected". Home also didn't say which Mac each Chief and chat belonged to, and the Mac filter listed one computer twice.

Causes and fixes

Feed: "Not connected to your Mac. Nothing was sent."

  • Cause: FeedStore.actions is weak. Since #23816, LiveCoordinator assigned MultiMacFeedActions(coordinator: self) straight to it and kept no other reference, so it was freed at once. FeedStore then saw actions == nil and failed every Allow, Deny, answer and Decline with that message, whichever Mac had asked.
  • Fix: the coordinator keeps the actions (feedActions).
  • Routing: each Feed item now records the Mac it came from (FeedItem.macID, set by LiveFeed and TerminalFeed, saved in FeedArchive). An answer goes to that Mac's link, never to the chosen Mac.
  • If that Mac's link is idle, the answer opens it (touch) and waits until its chats are ready (AcpmuxHub.waitUntilReady, 20 s). If that Mac hasn't read the ask yet, it reads it first.
  • LiveFeed records which Mac owns an ask even when the Feed already lists it, for example after a relaunch.
  • Opening a notification also opens the link of the notification's Mac.
  • Reply and Open already go by workspace and tab, through the chat store of that tab's Mac (#23816).

Home: which Chief and which chat belongs to which Mac

  • The two pins are the Cloud Chief (the account's Chief, which runs in Cloud on no Mac) and the Mac Chief (it runs on the focused Mac over its link and follows that Mac). Each pin now says where it runs, under its name: "Cloud", or the Mac's name as Workspaces shows it.
  • Every other row is an agent chat tab in a workspace on one Mac. The row title is the workspace. A new line under it shows the agent and, with more than one Mac, the Mac: "Codex · Aziz's MacBook Pro".
  • Home's Filter menu now has the Workspaces Mac filter. Both screens share one setting, remembered per team.
    • Choosing a Mac scopes the rows to that Mac and links it.
    • The Mac Chief then moves to that Mac.
    • The Cloud Chief stays, because it belongs to no Mac.

One Mac listed twice

  • Every cmux install registers its own device id. The deleted "cmux NEXT iOS Test" app left an offline record (39C6) beside the nightly's record (3EB7).
  • New MacRoster: a Mac record is hidden from the Mac filter, Workspaces and Home when it is offline and another record with the same name and owner is online or was seen later. A Mac not seen for 30 days is also hidden, as long as another Mac remains.
  • Hidden records stay in Settings → Devices, where Remove deletes them. A hidden record that comes back online shows again.
  • A teammate's Mac with the same name is never hidden: MacDevice.ownerUserID is compared.
  • A remembered filter that points at a hidden Mac reads as All Macs.

MacScope, MacFilter and MacFilterMemo moved from CmuxMobileWorkspaces to CmuxMobileModel so Home can share them. No Worker or wire change.

Tests

The regression tests were committed first (7cf9ba416cd5). Command: cmux-next-ios/verify/termqa/cmux_mobile_kit-test-ios.sh CmuxMobileLiveTests/MultiMacFeedTests, iOS 26.5 simulator on mini-cmux11s.

Results on the base, 7 issues:

  • theFeedCanAnswerWhileSignedIn: feed.actions was nil.
  • anAskFromTheOtherMacIsAnsweredOnThatMac: the card said "Not connected to your Mac. Nothing was sent." and the second Mac got nothing.
  • anAnswerOpensTheIdleLinkOfItsMac: the same error, and the idle link was never redialed.

All pass on the head.

Also added:

  • anAskNoFeedOwnsIsReadAgainOnItsMac
  • MacRosterTests (duplicate install, owner scoping, 30 days, back online)
  • HomeMacLabelsTests (row subtitle, Chief detail, the filter for rows and the Mac Chief, same-name tags)

Observed / Not run

  • Observed:
    • CmuxMobileLiveTests (238), CmuxMobileModelTests (166), CmuxMobileChiefTests (67), CmuxMobileWorkspacesTests (101) and CmuxMobileShellTests pass in the iOS simulator on mini-cmux11s on b2009c1f14b9.
    • prepush-gate.py: no new violations.
    • Live check over the real link (comment below), run on 13e8d628be9e, before the review fixes.
  • Not run:
    • The user's own phone (no TapKit).
    • The live check again on the review-fix head. Those fixes are covered by unit tests.

No capture: the live-check stills and video are listed in the comment below; cmux-ci capture covers Mac UI, not this iOS app.

Changelog

  • Fixed: Allow, Deny and answers in the iPhone Feed reach the Mac whose agent asked, even when another Mac is chosen.
  • Changed: Home shows where each Chief runs and the agent and Mac of each conversation, and has the Mac filter.
  • Fixed: A Mac registered twice (an old install) shows once in the Mac filter.

🤖 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 the iPhone Feed so Allow, Deny, and answers reach the Mac whose agent asked, and makes Home show which Mac each Chief and conversation belongs to.

  • Answers failed with "Not connected to your Mac. Nothing was sent." because the feed's actions were held weakly and freed at once; the coordinator now keeps them.
  • Each Feed item records the Mac it came from, and an answer goes over that Mac's link — opening it if idle and waiting for its chats to be ready.
  • Home rows now show their agent and Mac ("Codex · Aziz's MacBook Pro"), Chief pins say where they run (Cloud or the Mac name), and Home gains Workspaces' Mac filter.
  • A Mac registered twice (an old install leaving an offline record) shows once in the Mac filter and Workspaces; the hidden record stays in Settings → Devices until removed.