acpmux: a waiting peer_add, peer_reconnect or peer_lease says whether it settled and why
_acpmux/peer_add, _acpmux/peer_reconnect and _acpmux/peer_lease with wait: true wait up to 30 s (PEER_SETTLE_BUDGET) for the connect attempt to settle, then answered with the peer list alone. The reply was the same whether the attempt failed, connected, or was still in its handshake (budget 90 s), and the 30 s timeout went nowhere. So acpmux host check --fix printed "does not connect" with no reason for a peer that was only slow, and a caller could not tell a refusal from a wait that ran out. This is the same error-swallowing pattern as the handshake fix in #28105, here in the wait.
A waiting reply now carries wait: {settled, waitedMs, peer}: whether the attempt settled (connected or failed) within the wait, how long it waited, and the peer's summary at that moment (state, handshaking, error, attempts). The daemon logs a warning when the wait runs out. A peer removed (or never started) before its attempt settled answers stopped: true with settled: false, and the daemon logs that it stopped rather than that the wait ran out. A reconnect that keeps a ready link answers settled: true at once. host check --fix prints "NAME at URL is still in its handshake after Ns" (or "still connecting"), with the last error when there is one, instead of "does not connect". The Rust signatures of add_peer* / reconnect_peer* return Result<Value> (Null without wait); every caller compiles unchanged in behaviour. docs/acpmux-schema.json documents wait and result.wait.
Test
-
cargo test -p acpmux --test peer_integration a_waiting_peer_add_or_reconnect_says_whether_it_settled_and_why: a waitingpeer_addof a peer that refuses connections answerswait.settled: truewith the peer's summary (not connected, with its error), a waitingpeer_reconnectthe same, and one withoutwaithas nowait. -
cargo test -p acpmux --lib a_wait_that_runs_out_says_it_did_not_settle(hub/peers.rs): a wait that runs out answerssettled: falsewith nostopped, and one whose peer is dropped meanwhile answersstopped: true. -
cargo test -p acpmux --lib peer_reports_(cli/host_peering.rs): the CLI names the step and the wait instead of "does not connect" (peer_reports_an_attempt_still_running_when_the_wait_ran_out), and says a peer that stopped before its attempt settled did so (peer_reports_a_peer_that_stopped_before_it_connected). -
Red on the test commit cc40fc9c (run 41027591246):
peer_integration.rs:795: left: Null, right: true(the reply had nowait) -
Green on the head 56a9d01f (run 41041798814: the four tests pass, and in
cargo test -p acpmuxevery target passes excepthermetic_daemon_guard, which fails the same way on base (tests/web_image_attachments.rs lacks the hermetic helper; #28150 fixes it), anddaemon::state_file_tests::managed_unit_start_matches_shortened_sockets, a daemon state-file test this PR does not touch, which also failed on #28152 and #28161 and passed on base: it writes a fakesystemctland runs it at once, which can race other test threads' forks; the job's exit 1 is forced so the log prints)
Observed / Not run
Observed: the red and green runs above, on hosted Linux through cmux-ci test. Read, not run: a real peer in a slow handshake past 30 s; the unit test covers the wait running out with a fake settle channel.
Changelog
- Fixed: adding or reconnecting a peer machine with wait now says whether it connected, failed (and why), or is still connecting, instead of "does not connect" with no reason.
Agent session: agent session
🤖 Generated with Claude Code