Repository navigation
Description
Before submitting
- I searched existing issues and did not find a duplicate. Related: [Bug]: iOS relay resume repeatedly waits on reconnection; Paseo comparison and recovery references #16418 (same symptom, no root cause), [Bug]: One slow foreground health probe tears down a live session and disables the composer #7231 / fix(client-runtime): slow foreground probes keep live sessions connected #24309 (the 15 s desktop foreground probe; fix(client-runtime): slow foreground probes keep live sessions connected #24309 leaves network signals and native mobile resume unchanged, which is the path described here).
- I included enough detail to reproduce or investigate the problem.
Area
apps/mobile (shared logic in packages/client-runtime)
Steps to reproduce
- Pair the iOS app with a desktop host over Tailscale, using the host's tailnet IP or MagicDNS name (not the T3 relay).
- Leave home WiFi so the phone is on cellular. In this setup the tailnet path ran through a DERP relay, whose round trips spike past 3 s:
pong via DERP(mia) in 3.421s, then a timeout, then160ms. - Use the app normally: switch apps for a few seconds, pull down Control Center, receive notifications, move between cells.
It reproduces without a phone. Run the real EnvironmentSupervisor and RpcSessionFactory over a real WebSocket against a local t3 serve, through a TCP proxy that holds server→client bytes for 3.5 s. Pair each spike with an application-active-probe or network-changed wakeup:
| Route kind | Code | Spikes | Sessions replaced |
|---|---|---|---|
tailnet (*.ts.net) |
main | 6 | 6 |
| tailnet | with the fix below | 6 | 0 |
LAN (192.168.x) |
with the fix below | 2 | 2 (fast detection kept) |
Expected behavior
A live session on a remote route survives a single slow round trip after a foreground or network-change wakeup, as it does on a LAN.
Actual behavior
The app keeps showing Reconnecting, then Syncing threads…. Host traces show the phone's /ws sessions living 6–45 s, each followed by a new wsTicket and a new session.
EnvironmentSupervisor probes the live session on application-active-probe (also fired on inactive → active) and on network-changed with QUICK_CONNECTION_PROBE_TIMEOUT (3 s), in probeTimeoutFor in packages/client-runtime/src/connection/supervisor.ts. A late reply replaces the session, which reloads the shell snapshot and marks threads synchronizing. Three seconds is reliable for loopback and LAN, not for DERP-relayed tailnet, VPN or public routes.
Impact
On the go, the mobile app is effectively unusable over Tailscale: the user only gets a stable session on the same WiFi as the host.
Version or commit
iOS app 2.0.0; desktop host 0.1.0 at the time of measurement; reproduced against main at 8f26ed7.
Environment
iPhone 16 Pro, iOS 26, cellular in Colombia. macOS host on wired Ethernet behind a router without UPnP/NAT-PMP, so Tailscale fell back to DERP.
Logs or stack traces
Host server trace: phone sessions ending after 45.0 s, 18.7 s (client abort, 499), 17.6 s and 45.0 s, each reconnect authenticating a fresh websocket ticket for the same session.
A fix that keeps the 3 s budget for loopback and LAN and uses the existing 15 s CONNECTION_PROBE_TIMEOUT elsewhere follows in a PR.
Prepared with Claude Opus 5.5 in Claude Code, at the user's request; the measurements were taken on the user's own host and phone.
Activity