c6c32242e9
The chunked-welcome refactor moved welcome-timer arming into socket.onOpen, leaving the connect phase uncovered: if the relay blackholes the WebSocket handshake (no onOpen and no onClose), the timer never arms and /join hangs forever. Baseline armed the 30s timeout right after connect(); restore that so a stalled handshake still rejects the join. onOpen continues to re-arm (resetting the budget) once the socket opens.