ActivityBus
Coming back online starts a delta catch-up for every channel, and it also forces Flux to decide, per channel, whether anything still has to be fetched over HTTP. ActivityBus tracks each catch-up from the moment it starts to the moment its result arrives, so that decision is made from a real answer and never from a guess about how long catch-up should take. Network and realtime health, which every tab shares, sit beside it in a separate tracker described below.
The obvious fix is to make the freshness check wait a while after reconnect before deciding anything is stale. But any fixed wait is a guess about how long catch-up will take, and a wrong guess hurts in both directions. Too short, and the freshness check fires its own network refetch while the delta stream is still mid delivery. Too long, and a channel whose catch-up genuinely failed sits stale for far longer than necessary.
Flux has no grace timer between a reconnect and a refetch. The decision waits on real information: the result of the catch-up, and the current health of the network and the realtime connection. It proceeds the moment that information arrives, not a moment sooner or later than the data justifies.
A channel is either catching up or it is not
Completion is a result, not a duration
- Applied: rows newer than the channel's last confirmed time were delivered and written.
- Confirmed current: the backend answered, and nothing changed. This is an answer, not an absence of one.
- Too old: the gap is older than the backend can enumerate, so a catch-up could not be trusted. The channel needs a refetch.
- Failed: no usable answer (timeout, request error, connection dropped). The channel is not marked current.
A channel leaves catch-up mode when its catch-up RESULT arrives, whatever that result is: rows applied, confirmed current, too old, or failed. That includes the cases where nothing came back at all. An empty reply ends catch-up just as surely as a reply full of rows, and a failure ends it just as surely as a success. Nothing ever has to wait for silence to find out that a channel has nothing left to say.
Waiting is event driven
Anything that waits on catch-up carries a hard ceiling, but the ceiling is a backstop for a lost signal, not a grace period. If it is ever reached, the channels it was waiting on are treated as UNVERIFIED, never as up to date. A ceiling that quietly counted as "fine" would reintroduce the exact guess this page is about avoiding.
What a result changes
core_concepts/sync_anchors.No network is not the same as no realtime
Network. offline means the browser reports no connection: nothing is fetched, the app serves from disk, and the moment live coverage ended is recorded. unreachable means the browser claims it is online but real requests keep failing (a captive portal, a dead link). It is detected from request outcomes, never from the browser's online flag alone, and it clears on the next success.
Realtime, per channel. suspended (network offline, sockets intentionally down), connecting, live, degraded (repeated connect failures, watchdog resets or flapping, with retries continuing in the background), and unavailable with a cause.
Why a channel may have no realtime at all
- No adapter (noop): known at startup and permanent. Every channel is TTL-only.
- No realtime binding: on a backend where realtime subscribes to a table, a registration without
tablehas nothing to subscribe to. That channel is TTL-only and everything else is unaffected. - Unstable network: after several consecutive connect failures, watchdog resets or quick drops, the channels read as degraded while retries continue. A connection that stays up long enough resets the count.
- Quota or credentials: if the adapter reports why a connection failed, a limit or auth failure backs off on a slow, jittered schedule (starting around a minute and growing to fifteen) instead of retrying quickly and making a quota problem worse. Adapters that cannot classify failures report them as ordinary connection failures.
One tab does the revalidating, not every tab
ActivityBus is what the delta catch-up described in core_concepts/sync_anchors is coordinated against. For the storage side of what "fresh" and "stale" mean, see core_concepts/5_layer_stack.