1# Connection runtime
2
3Web, the desktop renderer, and mobile share one connection owner per environment
4in `packages/client-runtime`. Platform code supplies storage, credentials, network
5signals, and application lifecycle events. React views consume the runtime.
6Keeping retries and session lifetime here prevents competing reconnect loops when
7several views need the same environment.
8
9## One transport retry owner
10
11The [supervisor](../../packages/client-runtime/src/connection/supervisor.ts) owns
12transport retry policy; resolving an endpoint and opening an RPC session are single
13attempts. Transient failures retry with jittered exponential backoff, capped at
14five minutes, that resets only after a connection stays up. Without jitter, every
15client of a restarted server reconnects in the same second; with a short cap, a
16client that can never connect retries all day. Offline states and authentication
17failures wait for a wakeup instead of spending attempts on unchanged conditions.
18
19Foregrounding, an explicit retry, and an offline report probe the established
20session, and only a failed probe reconnects. Offline reports are often wrong, for
21example for a loopback server. A long mobile background suspension is the one
22exception: it replaces the session at once, because the OS can kill a socket
23without reporting closure, and a probe would hold a dead socket in "Resuming"
24until it times out. That fresh attempt runs even while the network reports
25offline. Foregrounding also wakes a pending retry immediately and
26leaves an ordinary in-flight attempt alone.
27
28The [registry](../../packages/client-runtime/src/connection/registry.ts) scopes
29connections by environment. An involuntary disconnect retains the registration
30and cached data. Explicit removal closes the scope and clears credentials,
31projections, and platform-owned state such as drafts. Cloud-account changes apply
32to relay registrations; they must not discard directly paired environments.
33
34## HTTP authorization
35
36RPC sessions authenticate at socket upgrade, while HTTP requests need current
37credentials from the
38[authorization service](../../packages/client-runtime/src/authorization/service.ts).
39Replacing a healthy socket for HTTP renewal would interrupt conversations and
40change the transport generation without a transport failure. Credential expiry
41does not close the socket, and refresh failure belongs to the HTTP operation.
42
43Session listings must retain unrevoked connected sessions after credential expiry
44so an open connection does not disappear from connection management. This does
45not extend the credential's lifetime. New HTTP requests and socket upgrades still
46require valid credentials.
47
48## Transport health and data freshness are separate
49
50A socket opening is insufficient evidence that the environment is usable. The
51[RPC session](../../packages/client-runtime/src/rpc/session.ts) waits for the
52initial server configuration before becoming ready. Shell and thread data then
53have their own synchronization state. A failed shell subscription can coexist
54with a healthy connection; labeling that state "reconnecting" promises a
55transport retry that will never happen.
56
57Cached projections remain readable offline. They must neither imply a live
58connection nor overwrite newer live data during a reconnect. Loading and
59resuming snapshots belongs to the shared state services, so every view agrees
60on which data is current.
61
62[Thread detail](../../packages/client-runtime/src/state/threads.ts) separates
63subscription lifetime from cache lifetime. Mounted consumers share one live
64stream, which stops when the last consumer unmounts; hidden mounted routes still
65count. A registry-local cache retains state and its replay cursor for five idle
66minutes so back navigation can resume without another snapshot download.
67
68The desktop app adds one consumer: a
69[keep-alive](../../apps/web/src/state/threads.ts) mounts every thread whose
70session is starting or running, in each enabled environment. Opening a running
71thread then needs no replay. The shell and detail streams are independent, so
72the shell can report a stop before the detail loads or catches up. A stopped
73thread stays mounted until its own stream is live and shows the stop, and the
74stream then closes and saves the settled state.
75Web and mobile do not keep threads alive.
76
77Retain state and cursor together only after an update finishes. Cancellation must
78not advance the cached cursor beyond the applied data, and an old scope must not
79overwrite its successor's cache. Preserve pagination data on reuse, but clear
80canceled loading state.
81
82The [RPC boundary](../../packages/client-runtime/src/rpc/client.ts) resolves
83requests against the current session at execution time. Durable subscriptions
84follow replacement sessions. After a transport failure they wait for the
85supervisor; an expected domain failure may resubscribe on the same healthy
86session. Reconnection does not automatically replay mutations, whose retry and
87idempotency rules belong to the operation.