fix(acpmux): a removed peer releases its waiting uploads at once (carry #30771)
Carries #30771 (a ChatGPT draft), rebased onto current feat-cmux-next with its commits unchanged.
Leo: "oh btw i talked with chatgpt and they raised a bunch more drafts and issues across cmuxterm-hq, cmux, and cmux-platform. some stuff worth looking at"
What
An upload forwarded to a peer that is reconnecting waits up to 30 s for the link (await_upload_link). On base it woke only when a connect attempt settled or when the deadline passed. Peer::stop() (remove/replace) bumped neither, so every pending upload to a removed peer sat for the full 30 s.
Peergets astop_changedwatch channel thatstop()latches to true. A stopped peer is never restarted: re-adding a peer makes a newPeer.await_upload_linkalso waits on that channel and reports not ready once the peer has stopped.forward_innerreturnspeer.unreachable_error()when the wait ends without a link. Before, it fell through to the feature checks against a cleared link.- Regression test:
server::peer_forward::tests::removed_peer_wakes_all_waiting_uploads_without_a_connect_attempt.
Leo-ask: ask-e06a62154f
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 uploads waiting on a removed or replaced peer so they stop immediately instead of sitting for the full 30-second reconnect timeout.
Peer::stop()now broadcasts via a watch channel that the peer is stopped;await_upload_linkwakes on that signal and reports not ready.forward_innerreturnspeer.unreachable_error()when the wait ends because the peer stopped, rather than falling through to feature checks against a cleared link.- Adds a regression test that verifies removal wakes all pending uploads without any connect attempt.