Cloud start: after a refused start's update, start again on the new link

Merged
TE
21h ago
+93-7

Summary

Start-matrix run 42125025387 failed at row no-folder with a socket ENOENT. A new machine's older cmux-tui refused the no-folder start (app.folder_needed). The app then updated the daemon (updateMachine) and retried right away. The update restarts the daemon, and the server carrier deletes and rebinds cmux-link-<id>.sock, so the retry dialed during that gap and got connectFailed(ENOENT). Before this fix, retriedOnce retried only connectionClosed.

  • CloudWait.updatedThenRelinked reads the handshake key, runs the update, then waits (up to 90 s) for the handshake key to change before the retry. CloudOutdatedMachine.copy already waits this way.
  • CloudWait.linkDropped treats ENOENT and ECONNREFUSED on the link socket as a dropped link, the same as connectionClosed. The start's single relink retry covers both.
  • The helpers live in CmuxNextCloud. CmuxNextApp gains no lines.

Testing

  • CloudMachineUpdateTargetTests:
    • aMissingOrRefusedLinkSocketIsADroppedLink
    • aRefusedStartsUpdateWaitsForTheNewLinkBeforeStartingAgain (handshake change, no update, unchanged handshake).
  • Red at d14e410c (test only), green at the fix commit. Results from the fleet test run follow in a comment.
  • The pre-push gate passes.

Changelog

  • Fixed: starting a Cloud chat with no folder on a machine with an older daemon no longer fails with a missing socket after the automatic update.

Agent session: agent session

🤖 Generated with Claude Code


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Fixes a cloud start that could fail with a missing link socket when an older daemon refused the start, updated itself, and restarted before the retry dialed the link again.

  • CloudWait.updatedThenRelinked waits for the machine's handshake to change after the update before starting again.
  • CloudWait.linkDropped treats ENOENT and ECONNREFUSED on the link socket as a dropped link, so the single relink retry covers them.