Cloud start: after a refused start's update, start again on the new link
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.updatedThenRelinkedreads the handshake key, runs the update, then waits (up to 90 s) for the handshake key to change before the retry.CloudOutdatedMachine.copyalready waits this way.CloudWait.linkDroppedtreats ENOENT and ECONNREFUSED on the link socket as a dropped link, the same asconnectionClosed. The start's single relink retry covers both.- The helpers live in CmuxNextCloud. CmuxNextApp gains no lines.
Testing
CloudMachineUpdateTargetTests:aMissingOrRefusedLinkSocketIsADroppedLinkaRefusedStartsUpdateWaitsForTheNewLinkBeforeStartingAgain(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](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
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.updatedThenRelinkedwaits for the machine's handshake to change after the update before starting again.CloudWait.linkDroppedtreatsENOENTandECONNREFUSEDon the link socket as a dropped link, so the single relink retry covers them.