cmux NEXT: Home says the daemon is too old only once it answers so (no flash while connecting)

Merged
TE
14d ago
+130-5

In a restore launch, Home showed "Conversations need a newer cmux daemon." from 2012 to 2339 ms after process start, while the Chief owner was still connecting. It's the third finding of the launch recording in #23680. Leo: show nothing, or the snapshot, until the daemon actually answers with an old version.

Cause: ChiefConversationOwner.supports is connection != nil && …, so "still connecting" and "too old" were the same false. On top of that, HomeHostView added the placeholder label visible before its availability stream ran.

Change:

  • ChiefConversationOwner.refusal keeps the handshake's refusal (DaemonCompatibility(refusal:): missing capabilities, another protocol, another app). It stays nil while connecting, after a timeout or a closed socket, and once connected.
  • A retry that times out after a refusal keeps the refusal.
  • HomeService.isRefused reads it.
  • HomeHostView starts with the label hidden and shows it only for a refusal or a migration notice. While connecting, the pane shows its fill (or the launch image) and nothing else.

Test: HomeDaemonNoticeTests. While the owner is connecting, or after a timeout, the notice is hidden. After a missingCapabilities refusal it shows, and a later timeout keeps it up.

Red, then green: the first commit adds the test and the owner state without the view change, so the test fails on it. The second commit is the fix.

Test fix after adoption (1632cbf4d32, 7c46910a1c6): the first version of the test looked for the notice among NSTextFields, but Home's notice is a ChromeLabel, so it never saw it (the connecting checks passed without looking, and its red came only from the refusal check, which could never pass). A failing #expect that captured the view also crashed the test process on the fleet (Swift Testing reflected a null NSPasteboard). The lookup now reads ChromeLabel text and the checks read plain booleans.

Observed / Not run

  • Observed: cmux-ci run ... suite Packages/macOS/CmuxNext HomeDaemonNoticeTests at 1632cbf4d32: both tests pass. At 7c46910a1c6 (before the lookup fix) the refusal test failed with only hidden NSTextFields found. cmux-ci compile-check --app passed at 1632cbf4d32.
  • Not run: the fixed test against the pre-fix view (label visible while connecting); by reading, noTooOldNoticeWhileTheOwnerIsStillConnecting fails there, since the label starts visible with this text.

What visibly changes: during launch, Home no longer flashes the too-old daemon notice; it shows only when the daemon really refused.

No capture: this removes a notice that flashed for ~330 ms while the daemon was connecting at launch; a capture tour shows the settled Home, which looks the same before and after. HomeDaemonNoticeTests pins when the notice shows.

Agent session: huge-blue

🤖 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 Home flashing a "Conversations need a newer cmux daemon" notice while the Chief conversation owner is still connecting. Home now shows the notice only once the daemon actually answers with a refusal, and keeps it hidden on timeouts or closed sockets.

  • ChiefConversationOwner.refusal keeps the handshake's refusal, stays nil while connecting and after a timeout or closed socket, and clears as soon as a newer daemon's handshake succeeds so the notice takes down at once.
  • HomeHostView starts with the label hidden and shows it only for a refusal or a migration notice.
  • HomeDaemonNoticeTests pins the behavior, reports failures instead of crashing the test process, and finds the notice whether it is a ChromeLabel or an NSTextField.