acpmux: a peer daemon's connection hears and lists none of this host's peers
Fix-forward for #26823 (base restore). The review after the merge returned BLOCK on one finding: _acpmux/peer_state_changed went to every _acpmux/watch connection, Origin::Peer included. A peer handshake turns on _acpmux/watch, so every daemon peered with this one heard the name, link state and connection error of every one of this host's peers.
Leo's words, which this feature serves: "you can just not choose a project ... you just get a little green dot ... as if you were working on your own computer, but now it's remote."
Change
- The notes skip peer connections.
server/fanout.rssends a peer-state note only to a connection that watches and is notOrigin::Peer. This covers both the live note and the snapshot resent to a watcher that fell behind. The unix socket, the local app and Web watchers (the dashboard) still get them. - The peers lists come back empty for a peer.
_acpmux/peersanswered a peer-origin caller with the full list (requests.rsreturnedhub.peers()to anyone), and so did thepeersfield of_acpmux/statusand thepeer_*replies. Nowremote_guard::afterempties every reply'speersarray forOrigin::Peer(redact::hide_peers_from_peer). This matches_acpmux/peer_status, which already answered a peer with this machine's row only. Nothing on a peer reads these lists: the daemon's peer link never calls_acpmux/peersor readsstatus.peers, and the CLI callers all talk to their own daemon over the unix socket.
Test: fails before, passes after
tests/peer_state_origin.rs a_peer_connection_hears_and_lists_none_of_this_hosts_peers sets up one hub with a unix-socket watcher and an Origin::Peer watcher, then checks:
- a live note: the local watcher hears it, the peer watcher gets nothing;
- 600 changes on a one-thread runtime, so both watchers lag: the local one gets the snapshot and the rest, the peer one gets nothing;
_acpmux/peersand_acpmux/status: they listgoneon the unix socket and nothing to the peer.
(results being added)
Capture
No capture: no UI change. This is daemon fan-out and reply redaction only.
Risk
Low. The change only removes data from Origin::Peer connections: the peer-state notes and the peers lists. One thing still reaches a peer: a session list may still name sessions this host mirrors from its peers. That was already the case before #26823 and is outside this fix.
Agent session: agent session
š¤ Generated with Claude Code
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Fixes _acpmux fan-out so a peer daemon's connection no longer hears about or lists this host's other peers. Peer-state notes were fanning out to every _acpmux/watch connection, including Origin::Peer, and _acpmux/peers plus the peers fields in _acpmux/status and peer_* replies answered peer callers with this host's full peer list.
- Peer-state notes ā the live note and the snapshot a lagging watcher gets ā now only go to watchers that are not
Origin::Peer; the unix socket, local app, and Web watchers keep receiving them. - Peer-origin callers get an empty
peersarray from_acpmux/peers,_acpmux/status, and thepeer_*replies, matching how_acpmux/peer_statusalready answers with this machine's row only. - Adds a test covering both live and lagging note fan-out and the empty peer lists.
Risk is low: the change only removes peer-state notes and peer rows from peer connections.