feat(desktop): surface why a terminal can't connect + emit failure telemetry
Why
When a terminal pane can't connect, it just shows "disconnected" with no cause — which is exactly what made the recent cross-region relay bug hard to spot (control plane worked, only the terminal WS 502'd). The root difficulty: the browser WebSocket API hides the upgrade's HTTP status — a relay 502/503 only surfaces as close code 1006, so the client can't see why.
What
Both changes lean on the _whoowns preflight the client already fires before every terminal WS (its response status was thrown away until now).
1. Classify the failure (surface the why). On give-up, the pane log now says the cause instead of a generic close:
- preflight 503 → "This host is offline (not connected to the relay)."
- preflight 401/403 → "You don't have access to this host."
- preflight 200 but the WS still drops → "The host is online (region X) but the terminal stream couldn't connect — usually a relay routing issue." ← the fingerprint of the cross-region bug
- preflight unreachable → "Couldn't reach the relay service."
2. Emit terminal_connect_failed telemetry on give-up (PostHog), so this failure mode is queryable/alertable instead of silent:
{ endpoint, close_code, close_reason, preflight_status, tunnel_region, reconnect_attempts, category } (endpoint has the token stripped).
Notes
primeRelayAffinitynow returns{ status, region } | null(wasvoid); both existing callers ignore the value, so it's backward-compatible.- Fires once per give-up (max reconnect attempts reached), not on every transient blip.
- Pure classifier + probe-parsing are unit-tested and mutation-checked. Desktop typecheck + biome clean.
Follow-on ideas from the same discussion (not in this PR): a bounded error state with Retry/Copy-diagnostics buttons, and a cross-region synthetic check in the relay (today's synthetic.ts only exercises same-region).
Summary by cubic
Surface why a terminal can’t connect and emit telemetry on final failure. We classify errors using the relay _whoowns preflight (now probed with the wsUrl), show a clear message in the pane, and send a PostHog event for alerting.
-
New Features
- Show a specific reason on give-up: 503 host offline, 401/403 no access, 200-but-WS-drops = relay routing issue (with region), 502/504 = temporary relay failure, or relay unreachable.
- Emit
terminal_connect_failedon give-up with endpoint, close_code, close_reason, preflight_status, tunnel_region, reconnect_attempts, category. - Only applies to relay-host terminals (
/hosts/...); local terminals unchanged.
-
Refactors
@superset/workspace-clientprimeRelayAffinitynow returns{ status, region } | null(and exportsRelayAffinityProbe) and is used to classify failures; added unit tests for probe parsing and classification.- Probe
_whoownswith the originalwsUrl(notactualUrl); deduplicated diagnostics comments and centralized rationale inprimeRelayAffinity.
Summary by CodeRabbit
- New Features
- Terminal connections now run a relay-aware precheck for relay-routed hosts and generate more specific user-facing failure diagnoses.
- Bug Fixes
- Improved “max reconnect attempts reached” reporting with expanded diagnostic context (failure category, preflight status, tunnel region when available) and more detailed failure analytics.
- Tests
- Added/expanded automated coverage for relay affinity probing and terminal failure classification to ensure consistent categorization across common HTTP and stream-drop scenarios.