Summary
On a memory-constrained host, the desktop app's local ("This device") backend connection drops intermittently and is slow to recover, surfacing as <machine> is not connected. The backend process stays alive — it is the renderer↔backend WebSocket transport that drops and reconnection that lags. A device-side workaround (Electron background-throttling flags) reduces but does not fix it. The durable fix is app-side.
Environment (where observed)
- OS: Windows 11 Pro
- App: T3 Code (Alpha) 0.0.28, local build of this fork @
4ab11db4, x64
- Backend: local ("This device")
- Host is memory-constrained: 28.5 GB total, ~4 GB free at times; node + claude + VS Code + Edge/WebView2 dominate. T3 Code itself is only ~1.4 GB — the pressure comes from other tooling.
- Trigger: correlates with high host memory pressure ("when other apps take a lot of memory").
Observed behavior
- "This device" shows disconnected / "reconnecting…"; recovery takes many seconds to minutes under load.
- The backend does not crash: observed stable 2+ days, RSS ~400–575 MB, no OOM signature. The connection drops while the backend stays up.
Root cause (code, at 4ab11db4)
- No stall tolerance / liveness signal
apps/server/src/ws.ts — the WS server sets no idleTimeout / keep-alive / ping-pong.
packages/client-runtime/src/connection/ — no client heartbeat.
- Result: a stalled socket is only detected on an actual transport close, never on silence.
- Slow recovery under load
packages/client-runtime/src/connection/supervisor.ts — each reconnect attempt has a 15s establishment + 15s probe budget (CONNECTION_ESTABLISHMENT_TIMEOUT / CONNECTION_PROBE_TIMEOUT = "15 seconds") with backoff. While the host thrashes, the backend answers too slowly and attempts keep timing out before they can succeed.
- No backend headroom
apps/desktop/src/backend/DesktopBackendManager.ts — the backend child is spawned with the default V8 heap (no --max-old-space-size / NODE_OPTIONS). The readiness check is non-fatal and the backend only restarts on an actual child exit.
Current device-side workaround (insufficient)
Added --disable-renderer-backgrounding --disable-background-timer-throttling --disable-backgrounding-occluded-windows to the app's launch shortcuts. This only stops Windows from throttling the backgrounded renderer; it adds no liveness detection, no faster recovery, and no backend headroom — and it is reset by every reinstall.
Proposed durable fixes
- Add WS keep-alive / ping-pong + an
idleTimeout on the server (ws.ts) and a client heartbeat in connection/, so a stalled socket is detected quickly and proactively.
- Make reconnect more tolerant under load: probe fast to detect a truly dead socket, but retry sooner / use adaptive budgets so a briefly slow backend isn't repeatedly abandoned. Distinguish "slow" from "dead".
- Give the backend heap headroom (
--max-old-space-size) and/or a health-based restart so it isn't starved under host memory pressure.
Related upstream issues (pingdotgg/t3code)
Symptom-adjacent; likely share robustness gaps — worth cross-referencing / de-duping:
Summary
On a memory-constrained host, the desktop app's local ("This device") backend connection drops intermittently and is slow to recover, surfacing as
<machine> is not connected. The backend process stays alive — it is the renderer↔backend WebSocket transport that drops and reconnection that lags. A device-side workaround (Electron background-throttling flags) reduces but does not fix it. The durable fix is app-side.Environment (where observed)
4ab11db4, x64Observed behavior
Root cause (code, at
4ab11db4)apps/server/src/ws.ts— the WS server sets noidleTimeout/ keep-alive / ping-pong.packages/client-runtime/src/connection/— no client heartbeat.packages/client-runtime/src/connection/supervisor.ts— each reconnect attempt has a 15s establishment + 15s probe budget (CONNECTION_ESTABLISHMENT_TIMEOUT/CONNECTION_PROBE_TIMEOUT="15 seconds") with backoff. While the host thrashes, the backend answers too slowly and attempts keep timing out before they can succeed.apps/desktop/src/backend/DesktopBackendManager.ts— the backend child is spawned with the default V8 heap (no--max-old-space-size/NODE_OPTIONS). The readiness check is non-fatal and the backend only restarts on an actual child exit.Current device-side workaround (insufficient)
Added
--disable-renderer-backgrounding --disable-background-timer-throttling --disable-backgrounding-occluded-windowsto the app's launch shortcuts. This only stops Windows from throttling the backgrounded renderer; it adds no liveness detection, no faster recovery, and no backend headroom — and it is reset by every reinstall.Proposed durable fixes
idleTimeouton the server (ws.ts) and a client heartbeat inconnection/, so a stalled socket is detected quickly and proactively.--max-old-space-size) and/or a health-based restart so it isn't starved under host memory pressure.Related upstream issues (pingdotgg/t3code)
Symptom-adjacent; likely share robustness gaps — worth cross-referencing / de-duping: