Gate the default focus refetch on lost realtime coverage - #2278
Gate the default focus refetch on lost realtime coverage#2278vburojevic wants to merge 1 commit into
Conversation
Every window focus refetched every active query older than 2s. On a phone that meant each unlock and app switch fired a full refetch wave on top of the realtime reconnect wave: the WebSocket manager already probes the socket on visible, the reconnect watermark refetches exactly the queries whose data predates the disconnect, and changes merged while hidden flush on the next visible. The focus wave duplicated all of that in the first interactive frames after unlock. Make the default focus refetch injectable and gate it in main on wsManager's connection state: while the state is "connected", realtime owns freshness; in "connecting" or "reconnecting" the focus refetch remains the fallback. Per-query refetchOnWindowFocus policies (query-policies.ts) are unaffected and still win. Known narrow trade, called out for review: a half-open socket reports "connected" for up to the 5s pong timeout, and the handful of queries with neither realtime coverage nor a focus policy (e.g. CLI skills status) skip one focus wave when parked across an unlock; refetchOnMount still repairs them on navigation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ttach edge (#2300) Lands five mobile-performance PRs by Vedran Burojevic plus one follow-up fix. * #2277 Keep the thread panel host mounted across thread navigation * #2278 Gate the default focus refetch on lost realtime coverage * #2279 Apply urgent realtime thread changes without flushing the debounce buffer * #2280 Cache max scroll offset outside the timeline scroll hot path * #2281 Make the published plugin composer host stable across keystrokes Follow-up fix: a detached timeline viewport that a content shrink clamps onto the new, smaller maximum stayed detached, because the clamp's scroll event outruns the ResizeObserver refresh and is classified against the stale cache. The ResizeObserver path now detects that case and re-attaches. Regression test fails on the #2280 head and passes here. Verified: typecheck pass; oxlint 0 errors; @bb/app 422 files / 3,288 tests pass. Merge commits are disabled on this repository, so this squash carries the work of all five branches; co-author trailers preserve authorship. Co-Authored-By: Vedran Burojevic <vedran.burojevic@gmail.com> Co-Authored-By: Claude <noreply@anthropic.com>
|
Shipped in #2300 (squash commit 836e216). This branch's changes are on Closing as superseded rather than merged only because merge commits are disabled on this repo: a squash creates a new commit, so GitHub cannot mark this PR merged even though its changes are in Review notes: no code regression. One disclosed trade accepted by the owner — queries with neither realtime coverage nor a focus policy (Skills, plugin settings/contributions/catalog, host-path, changelog, plugin SDK Thanks — nice work on this batch.
|
What was wrong
Every window focus refetched every active query older than staleTime 2s. On phones each unlock/app-switch fired that full wave on top of the realtime reconnect wave (visible-probe + reconnect watermark + hidden-change replay), duplicating catch-up in the first interactive frames.
What changed
createAppQueryClientgains an injectableshouldRefetchOnWindowFocus; main gates it onwsManager.getConnectionState() !== "connected". While connected, realtime owns freshness; in connecting/reconnecting the focus refetch remains the fallback. Per-query policies (query-policies.ts) still win.Known narrow trade (disclosed for review)
A half-open socket reports "connected" up to the 5s pong timeout, and queries with neither realtime coverage nor a focus policy (e.g. CLI skills status) skip one focus wave when parked across an unlock; refetchOnMount repairs them on navigation.
How verified
Gated + ungated focus tests (5/5); typecheck + oxlint clean; adversarially reviewed.
🤖 Generated with Claude Code