Repository navigation
acpmux: _acpmux/peer_state_changed pushes each peer link state change to watchers (peerStateEvents) - #26823
Conversation
|
Owned by an agent session · session |
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Unclear: CI failed on
Failures:
Matched log linesNot re-run automatically: Written by red: web / Web status; base red: the same failure on the base 3e1acf6; does not block Gallery before/after for
States
Pick other states with a |
|
Bead |
|
Found 39 test failures on Blacksmith runners: Failures
...and 29 more test failures. View all on Blacksmith: run 40675938063, run 40675938010
|
… to watchers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
…val and a lagging watcher Codex review: a replaced or removed instance could speak after its successor, a reconnect repeated the state, and a watcher that lagged the feed lost a transition. PeerStates keeps each name's speaker and last note under one lock, and a lagging watcher gets every name's last note again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
A burst of peer state notes shared the 64-slot harness feed and could push a harness reload out of a lagged watcher's buffer. The notes now have their own 256-slot feed, still delivered through watch_note, and a watcher that falls behind it gets each peer's last note again. Removed names keep their last note up to 64, the oldest removal going first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a
907be1d to
e18a690
Compare
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
|
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40680723578 at 627df29 failed: cmux-next generated files. |
|
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40682236069 at 8114288 failed: cmux-next generated files. |
|
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40681979402 at d6c40eb failed: cmux-next checks (god files, concurrency, crash safety, l10n), cmux-next generated files. |
|
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40681192502 at 3da6f43 failed: cmux-next checks (god files, concurrency, crash safety, l10n), cmux-next generated files. |
|
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40680828380 at dcba69e failed: cmux-next checks (god files, concurrency, crash safety, l10n), cmux-next generated files. |
|
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40680946738 at 0339b44 failed: cmux-next checks (god files, concurrency, crash safety, l10n), cmux-next generated files. |
|
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40683834325 at 2645001 failed: cmux-next checks (god files, concurrency, crash safety, l10n), cmux-next generated files. |
|
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40683016589 at 9fbc12e failed: cmux-next checks (god files, concurrency, crash safety, l10n), cmux-next generated files. |
|
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40680929292 at 9a6044d failed: cmux-next generated files. |
|
Shipped in:
|
…s peers (#26860) * test(acpmux): a peer connection hears and lists none of this host's peers (failing) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a * acpmux: a peer daemon's connection hears and lists none of this host's peers A peer handshake turns _acpmux/watch on, so every daemon peered with this one heard _acpmux/peer_state_changed for all of this host's peers: their names, link states and connection errors (#26823). The notes, and the snapshot a lagging watcher gets, now skip Origin::Peer connections. _acpmux/peers, _acpmux/status and the peer_* replies give a peer an empty peers list, as _acpmux/peer_status already gave it this machine's row only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-1288bbb2b5d2f5c6b66a --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: cmux-bot[bot] <348531757+cmux-bot[bot]@users.noreply.github.com>
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Leo's ask (manaflow-ai/cmuxterm-hq#4770, plan row 3, one machine-state feed for the composer strip and the sidebar):
Today the composer and the sidebar can only read a peer's state by polling
_acpmux/peers. This PR adds a push. It follows #26756 (merged, 85748f3), which made the state honest: connected only after the handshake.Contract
Notification
_acpmux/peer_state_changed, sent to every watching connection (_acpmux/watch):When it is sent:
PeerState(peer_link.rs). It never repeats while the state stays the same, so a peer whose retries keep failing sends onereconnecting, not one per attempt.Linkchange goes throughPeer::with_link, which sends the note under the link's lock, so notes go out in order. No timer, no polling.peer_add, config, lease, reconnect) sends its first state.peer_remove, an invalid saved ssh URL, a lease that ends) sends a lastofflinewitherror: "removed".What each field means:
stateis the same string asstatein_acpmux/peers.connectedmeans the handshake finished (acpmux: a peer reads connected only after its handshake, and a request queued on a dropped or stalled link fails as not sent #26756).degradedmeans the handshake is running or a ping went unanswered.erroris why the link is down. It is null while connected.How a client finds it:
peerStateEventsis in the daemon'sinitializefeature list, next toharnessUpdatePlan.peer-state-events-v1is ininitialize/_acpmux/status/acpmux capabilities.Registration:
protocol/peer_state.rs(PeerStateChanged,PeerLinkState) and registered inprotocol/mod.rs.docs/acpmux-schema.json.Ordering across instances:
src/peer_states.rskeeps, per name, the instance that speaks for it and its last note, under one lock. Because of that:reconnectingsends no repeat;offline/removedgoes out only while the removed instance still speaks.The notes have their own 256-slot feed, kept apart from the harness feed so a burst of notes never pushes a harness reload out of a slow watcher's buffer. A watcher that falls behind that feed (
RecvError::Lagged) gets every name's last note again, so a client that sees the same state twice may ignore the second one. The table keeps one entry per running peer and the last note of at most 64 removed names; the oldest removal is dropped first.Fan-out uses the same delivery path as
_acpmux/harnesses_changed:server/fanout.rsreads the feed and passes each note toserver/harness_admin.rswatch_note, which sends a payload markedpeerStateChangedas_acpmux/peer_state_changedto connections that watch.Test: fails before, passes after
tests/peer_state_events.rsa_watcher_hears_each_peer_state_change_oncesets up two hubs, with A's link to B going through a TCP relay that the test drops. A watching connection on A must hear:connecting,degraded(the handshake), thenconnected, each once, withlastSeen/atset anderrornull;reconnectingonce with anerror, and nothing more over 6 s while at least one more retry fails;remove_peer,offlinewitherror: "removed", and then nothing;peerStateEventsininitialize's features.Before (#26756's head, 6fb3ca5 in that run, plus only this test), cmux-ci run https://github.com/manaflow-ai/cmux/actions/runs/40655109455:
After (this branch, 969ac56 in that run; the next commit is rustfmt only), cmux-ci run https://github.com/manaflow-ai/cmux/actions/runs/40666930100:
At the head (907be1d, after the review fixes): cmux-ci run https://github.com/manaflow-ai/cmux/actions/runs/40671765409 passed fmt, peer_state_events 3 out of 3, peer_integration 50 out of 50 and clippy. In that run, lib had one failure in an unrelated test,
cli::codex_auth_broker. Run https://github.com/manaflow-ai/cmux/actions/runs/40672480655 then passed lib 1624 out of 1624, including the new unit testremoved_names_are_kept_up_to_a_bound.Review
An independent Codex review (gpt-6-astra, high effort, fast mode) ran in four rounds, and each blocking finding was fixed:
The last round, at 907be1d, found nothing and returned
VERDICT: SHIP.Capture
No capture: no UI changes. The only webview files are the regenerated protocol types (
generated/methods.ts,generated/types.ts), which add a type for the new notification. Nothing renders it yet; the composer lane consumes it.Overlap
pr-overlapnames #26747, #26700 and #24797, all from the same account. They share only the registry, spec, capability and feature-list lines, plusPeer's field list. The second one to land rebases and re-blesses the IR. None of them adds a peer-state push.Risk
Medium-low. This adds one notification to watchers and changes no existing message.
with_linknow also locks thePeerStatestable, in the order link, then table (withPeer::states/last_errorread inside). Nothing takes them in the other order, and the table never takes another hub lock.readyandconnectedtogether under the link lock, and only while the link's epoch is still current. A link that dropped mid-handshake is therefore never marked ready (this tightens acpmux: a peer reads connected only after its handshake, and a request queued on a dropped or stalled link fails as not sent #26756).last_erroris set before the link goes down, so thereconnectingnote names the reason.Agent session: agent session
🤖 Generated with Claude Code