A mesh node both accepts and dials. Running two separate quinn endpoints (one
listening, one dialing) in one process is fragile, so add
QuicEndpoint::node_from_der — a single dual-role endpoint that carries both a
server config and a default client config and accepts + connects on one socket
(the canonical quinn peer pattern). lockstep-node now uses it, and each dial is
bounded by a 2s timeout with retry so a stalled connect retries rather than
blocking forever.
Loopback n=4 (f=1) stays byte-identical; cross-machine n=2 still agrees.
Characterized but unresolved: on two of the test hosts the full n=4 cross-machine
mesh still does not complete — a *listening* endpoint's outbound dial to another
machine never handshakes, while a client-only endpoint from the same host dials
fine (verified with the quic_xnet example), and inbound + the network path + the
firewall are all ruled out (firewall is disabled on those hosts). The remaining
suspect is host routing on the multi-homed (10.10.x/192.168.x) machines; it needs
on-host packet capture to root-cause and is independent of the consensus and
transport code, which pass loopback-n4 and cross-machine-n2.
Co-Authored-By: Claude Opus 4.8 <[email protected]>