fix(sessions): stop the Hub background-refresh re-render loop - #566
Open
RonenMars wants to merge 2 commits into
Open
fix(sessions): stop the Hub background-refresh re-render loop#566RonenMars wants to merge 2 commits into
RonenMars wants to merge 2 commits into
Conversation
On-device tracing of the "Showing cached data — syncing" state found ProjectsHub re-rendering continuously (hundreds of commits, ~6/sec, never settling) from two sources a why-did-this-render probe pinned down. serverFetchStatus.recordSuccess/recordReady wrote a fresh statuses object with a new Date.now() on every successful HTTP response even when the status was already ok, so every API call re-rendered every subscriber (closes #564). Guard both so an unchanged ok status returns the same state and zustand does not notify — recordReady still clears warming_up. conversation_updated WS frames each invalidated the whole conversations-eager query, re-draining every page of every server per liveness ping (closes #565). Debounce refreshEagerConversations so a burst of frames collapses into one trailing re-drain. Measured effect on-device: render rate dropped from ~6/sec to ~0.65/sec and fetchStatuses disappeared as a render driver.
…ent bundle-cache traps Two on-device tracing traps that surface as "the thing I'm tracing never happened" rather than an error, both found while verifying the Hub re-render fixes. A shell-exported EXPO_PUBLIC_* flag does not inline into the bundle — Expo reads these from .env/.env.local files, so the flag must live there and be verified by grepping the served expo-router entry bundle. The dev client serves a disk-cached bundle that ignores deep-link, /reload, and plain launch, so a reinstall is needed to force a fresh fetch from Metro. Adds both to docs/troubleshooting.md under "Measuring the wrong thing" and a pointer in CLAUDE.md.
This was referenced Aug 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #564 and #565.
Problem
On-device tracing of the Hub while it shows "Showing cached data — syncing" (both servers paired) found ProjectsHub re-rendering continuously — hundreds of commits at ~6/sec during warm-up, never settling.
A per-commit "why did this render" probe attributed the churn to two independent sources, neither addressed by the throttle/memo work in #563.
Fixes
serverFetchStatusstore (serverFetchStatus store re-renders subscribers on every HTTP response (fresh object on unchanged status) #564):recordSuccess/recordReadyallocated a newstatusesobject with a freshDate.now()on every successful HTTP response, even when the status was alreadyok, so every API call re-rendered every subscriber.Both now return the same state when nothing changed, so zustand does not notify —
recordReadystill clearswarming_up→ok.refreshEagerConversations(conversation_updated WS frames trigger a full eager-conversations re-drain per frame (sustained Hub re-render loop) #565): everyconversation_updatedWS frame invalidated the wholeconversations-eagerquery, re-draining every page of every server per liveness ping.It is now debounced (trailing 1s) so a burst of frames collapses into a single re-drain.
The long-term follow-up noted in conversation_updated WS frames trigger a full eager-conversations re-drain per frame (sustained Hub re-render loop) #565 is to patch the single affected conversation in the eager cache instead of re-draining everything.
Verification
Unit: 12 tests pass across
serverFetchStatusandeagerCacheSync, including new cases for same-identity no-op writes,warming_up→okstill clearing, and debounce/coalesce behavior.On-device (iOS simulator, two real servers,
EXPO_PUBLIC_OPEN_TRACE=1): render rate dropped from ~6/sec to ~0.65/sec andfetchStatusesdisappeared from the render-driver breakdown after the store guard.