cmux NEXT: the words for updating other machines' daemons to the app's build
Part 3 of the rebuild of #23199 and #24070 (adopted by hb-acpmux): the vocabulary for keeping other machines' daemons on the app's build. Nothing uses it yet. The queue that does is the next PR, then acpmux ssh peers, then Cloud machines.
Leo: "BRO CANT YOU JUST LIKE SUSPEND SHIT AFTER A TOOL CALL/TURN THEN JUST GO AND AUTOUPDATE OUR TEAMMATES NEED ACPMUX UPDATING TOO..."
Leo: "OUR SHIT IS HARDLY EVER GOING TO GO IDLE. IT JUST WONT. YOU'LL JUST HAVE TO ACCEPT IT BREAKING AT SOME POINT BUT IT RESUMES WHATEVER IT INTERRUPTED. END OF STORY FOR THE DAEMON UPDATE."
Leo-ask: ask-48bbaec1d4
Leo-ask: ask-061e3574a6
Change (all new, from #24070 at bd4892c8)
DaemonUpdateTarget: a machine whose daemon follows the app's build. It reports its build and updates itself when asked, idle-only or also mid-turn.DaemonUpdateOutcomeandDaemonUpdateEventgo with it.DaemonBuildCommit: reads<hash>[+dirty.x] <date>. Builds are the same by commit only. New since #24070: it keeps the build's day, andisNewer(than:)orders two builds of different commits. The queue uses that to never move a machine back. Since #24070, a Linux host keeps itself on the newest feat-cmux-next build with its ownacpmux-update.timer(#24232, channel #24256), which is often newer than the app's.DaemonUpdateLedger: one attempt per machine and build, kept across launches in the build's own Application Support (daemon-update/attempted.json).DaemonUpdateBoard: each machine's latest state, for the surfaces that will show it. The tooltip and notice strings come with the PR that shows them.- Debug Settings toggle
agent.updatePeers(default on; nothing reads it yet).
No timers or observers.
Tests
DaemonUpdateTargetTests (new types, so they fail on base by not compiling):
- the build string's hash, dirty mark and day, and
isNewer(than:)(a later day only; one day, or no date, orders nothing); - the ledger round trip, and a new build starting empty;
- the board keeping a machine's latest state and forgetting a cleared one;
- the toggle on by default and in Debug Settings.
Observed / Not run
Observed (cmux-next run 40293047950 at 68f6a283): DaemonUpdateTargetTests passed, anUnreadableLedgerBlocksItsBuildNotTheNext included; Release compile (Xcode 26), checks and both fast tiers green.
Base reds, not this PR's: swift test (the test process is killed before its summary line, BrowserTabMirrorTests, ActionRunCreated/ActionBatch deadline tests, and aChildPastItsDeadlineIsKilled timing out on a loaded runner; none touch these files) and generated files (remote.openRemote: open-remote in ActionContractTests, and three GENERATED.md files, the same on other PRs' runs).
Review (codex gpt-6-astra xhigh): BLOCK at c19a092e (three findings, fixed test-first), SHIP at dab2a56c, SHIP at 68f6a283 (compile fix only).
Not run: nothing here runs in the app yet; the policy that uses it is #25387.
No capture: no visible UI.
Agent session: big-red
š¤ Generated with Claude Code