Root cause of the beta_31 periodic 1-2s freezes with Wi-Fi on: every
received mesh packet pushes an RX-log frame to all connected TCP/WS
companion clients from the loop thread, and writeAllBytes called
WiFiClient::write() unguarded — against a stale peer (phone asleep,
half-open socket) that blocks in the framework's 1s select() retries.
The 120ms app timeout only bounded attempts, not the first call.
- TCP+WS servers: probe writability (zero-timeout select on the client
fd) before every write; lwIP reports writable only with ~2.8KB free,
a whole frame is ~180B, so probed writes complete instantly.
- Reap clients whose writes fail continuously for 10s (half-open
sockets previously stayed "connected" forever, eating the write
budget on every pushed frame).
- Chat-history ring: chunked writer + wider flush spacing (same
treatment saveContacts got in beta_30).
- Stall tracer: 16-entry ring of >=0.2s loop stalls, shown in About.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>