Heal the inbox after a missed broadcast (chats--refresh-inbox)#2
Conversation
The inbox already receives Turbo 8 page refreshes (broadcast_refresh_later_to), but Action Cable has no replay: a refresh sent while the client's socket was down (backgrounded tab/app, network blip, laptop asleep) is lost and the inbox sits stale until the user navigates. The thread got stale-catch-up in 0.1.1 (the single biggest reliability pattern from the Campfire review); the inbox was the remaining gap. Add a tiny chats--refresh-inbox controller that re-runs the same page refresh on the two moments we might have missed one — cable reconnect and return-to-visible — reusing the thread's channel-free reconnect detection (observe the <turbo-cable-stream-source> `connected` attribute; no new Action Cable channel). The recovery action is Turbo.session.refresh() rather than the thread's `?since=` delta, because inbox broadcasts already ARE page refreshes. Auto-registered via the engine importmap pin, so hosts need zero changes. It guards against morphing the list out from under someone typing in search. - engine_test: assert the new controller is pinned for auto-registration - conversations_flow_test: assert the inbox stream source is wrapped by the reconciler
|
Added a second commit (adb1c4f) that closes the other inbox-staleness case, distinct from the missed-broadcast one this PR started with.
Fix: The two mechanisms are complementary (missed live broadcast vs. stale restored snapshot), so this PR now covers inbox freshness on both axes. |
Gap
The thread got stale-catch-up in 0.1.1 — the reliability pattern
docs/campfire_review.mdcalls "the single biggest ... in [Campfire's] codebase," because mobile WebViews reap sockets constantly. The inbox never got the same treatment.The inbox updates via Turbo 8 page-refresh broadcasts (
Chats::Broadcasts.refresh_inbox_of→broadcast_refresh_later_to). Action Cable has no replay: a refresh broadcast sent while this client's socket was down (backgrounded tab/app, network blip, laptop asleep) is lost, and the inbox silently sits at its last render until the user happens to navigate. Same failure mode the thread already guards against — just on the other list.(Found while auditing a production host app whose inbox is a native tab root with pull-to-refresh disabled, so there was no user-reachable recovery at all.)
Fix
A tiny
chats--refresh-inboxcontroller that re-runs the same page refresh on the two moments we might have missed one:connectedattribute turbo-rails toggles on<turbo-cable-stream-source>; no new Action Cable channel), andThe recovery action is
Turbo.session.refresh()(not the thread's?since=HTTP delta) because inbox broadcasts already are whole-page refreshes — idempotent, morphing, scroll-preserving. It skips refreshing while the search box is focused so it never yanks the list out from under someone typing.Auto-registered via the engine importmap pin, so hosts need zero changes; a host can still override it by pinning the same key.
Tests
engine_test: the controller is pinned undercontrollers/chats/for stimulus auto-registration.conversations_flow_test: the inbox stream source is wrapped by the reconciler.Full suite green (the one unrelated red in my local run is a pre-existing asset-path assertion that hard-codes the checkout dir name
chats; it passes in CI / a normally-named checkout).Docs
CHANGELOG (Unreleased), README (both surfaces self-heal now), and the
campfire_review.mdledger updated to note inbox parity.