fix(acpmux): stop reconnecting upload waits when a peer is removed (SW-03)
SW-03 — An explicit peer removal must end pending upload reconnect waits
Based on feat-cmux-next@4ddb627afb5f4d5f57f07c7775e0208f33610ff8, after #30581 merged. This is a targeted follow-up to the prior owner's known-limit list. HQ: https://github.com/manaflow-ai/cmuxterm-hq/issues/5599.
Reproduction
Merged #30581 lets _acpmux/file_put* wait up to 30 seconds while a peer link reconnects. server/peer_forward.rs::await_upload_link subscribes only to the peer's settled watch, which advances on completed connect attempts. But an explicit Hub::remove_peer or replacement calls Peer::stop and ends its link without necessarily completing a connect attempt. A stopped Peer is still held by the already-dispatched request, so its settled sender remains alive and settled.changed() can wait the full 30 seconds. Multiple uploads have this same problem; callers receive a late failure even though the remote connection was intentionally retired.
Fix
- Add a dedicated
Peer::stopped()watch receiver, initialized false and broadcast true inPeer::stop. This preserves the semantics of the existingsettledchannel (also consumed bypeer_add(wait:), which must distinguish a completed connect from a stopped peer). - In
await_upload_link, race completed connection attempts, explicit stop, and the existing deadline withtokio::select!. Verify the stop flag both before waiting and when returning. A removed/replaced peer now finishes its waiting uploads immediately with a refused/unreachable result; a genuinely reconnecting peer retains the existing 30-second budget. - No wire or persistent state changes, no timer polling, no lock across awaits.
Deterministic test
server/peer_forward.rs::tests::removed_peer_wakes_all_waiting_uploads_without_a_connect_attempt constructs a Peer without running its connect loop, creates two concurrent await_upload_link(30s) calls, stops it, and requires both to finish false within one second. This deliberately excludes incidental connection-attempt completion as an alternative wake path.
Test-first commit c918576974d1a19c85a89da4b89663d8db7813b5 fails on the previous code; code commits 20f24fc784738fbfda8ef20b973e862178873817, 4d0af4aebc2eedba1990738dd84cb57a3afdb0a3.
Verification
Targeted: cargo test -p acpmux --lib removed_peer_wakes_all_waiting_uploads_without_a_connect_attempt. No local Rust toolchain is present; CI execution and independent review remain pending. This remains draft until those pass. It addresses explicit stop/removal only. A request whose parameters or peer capabilities are already invalid can still wait before refusal; that is the other independent follow-up on #30581. No merges or deployments performed.