be818467ddf46430609e153a9c2c50f56e484664
Field test of the long-outage path failed: ~31s into a Wi-Fi drop the peer
vanished with no "Reconnecting..." indicator and never came back. Logs showed
the chain `Gossip NeighborDown -> Removed peer -> Transport: stopped
supervising peer`.
Root cause: a transient gossip NeighborDown was routed to RoomEvent::PeerLeft,
same as a graceful leave, so core called disconnect_peer -> supervisor.abort().
That aborted the very reconnect supervisor that was meant to redial -- before
its own reconnect loop (which re-emits Connecting and re-dials the retained
09acefd address with backoff) ever ran. The supervisor + retained-address fix
were effectively dead code in the field, which is also why the loopback tests
(they drive the supervisor directly) never caught it.
Fix: decouple a transient drop from a graceful leave.
- gossip.rs: NeighborDown now emits the new RoomEvent::PeerConnectionLost
instead of PeerLeft. A graceful GossipMessage::Leave still emits PeerLeft.
- core: on PeerConnectionLost, do NOT disconnect the peer. Keep its supervisor
alive (it redials the retained address and drives the yellow indicator) and
arm a per-peer reconnect grace timer (RECONNECT_GRACE = 45s, comfortably past
the ~30s QUIC idle timeout). The peer is evicted only if the link hasn't
recovered when the timer fires. A gossip rejoin (PeerJoined/PeerUpdated) or a
transport reconnect (ConnEvent::Connected) cancels the timer first; session
shutdown aborts all pending timers so none fire a stray eviction.
Builds clean, clippy clean, 3 transport tests pass. NOT yet field-verified --
re-test the long-outage path on a real call.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Releases
10
Languages
Rust
98.8%
Shell
0.4%
Nix
0.4%
Python
0.2%
Inno Setup
0.2%