fix(mobile): live-update open threads instead of freezing on the history fetch - #4707
Open
CryptoJones wants to merge 1 commit into
Open
fix(mobile): live-update open threads instead of freezing on the history fetch#4707CryptoJones wants to merge 1 commit into
CryptoJones wants to merge 1 commit into
Conversation
…ory fetch An open thread never updated. `threadRepliesProvider` was a one-shot paginated query that resolved once and cached, so replies arriving afterwards - including the viewer's own, and agent replies - were never in that list. The activity feed looked instant while the thread it linked to sat frozen. - Add `ThreadLiveRepliesNotifier`, a `limit: 0` subscription on the same filter (live only; history stays the paginated fetch's job), mirroring `ChannelsNotifier._subscribeLive`. - Establish the subscription BEFORE snapshotting history. An event published after `/query` returns but before the REQ registers is in neither result and is lost permanently - the same class of bug this provider exists to fix. Gated on a `Completer` that always completes, success or failure, so a thread that cannot subscribe still loads its backlog rather than hanging. - Handle relay CLOSED. `RelaySessionNotifier` drops the subscription from `_liveSubscriptions`, so it is NOT replayed on reconnect, but the notifier would still hold a non-null `_unsubscribe` and report healthy while silently receiving nothing. A generation counter stops a stale callback from tearing down a newer subscription. - Ownership of a pending local reply is released ONLY by the authoritative paginated fetch, never by a live echo. The subscription can deliver an event the relay will not return on a later query; confirming on the echo hands the row back, and if the refetch then fails nothing is left holding the message on screen - the viewer's own reply disappears. Costs one redundant entry that `_mergeReplies` de-duplicates by id. Auto-dispose is load-bearing on both new providers and is commented as such: a keep-alive family would leak one live subscription per thread opened for the whole app session, and the relay caps subscriptions. Tests: two new cases - a live reply arriving after the history fetch, and ownership held across a failed refetch. Full mobile suite 906 pass; the single remaining failure (`ChannelDetailPage keeps follow mode off while a tall newest message stays visible`) reproduces on a clean tree and is unrelated. `flutter analyze` clean, `dart format` clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012xHDhHGPwDTtBCGb8Sjn6Z Signed-off-by: Aaron K. Clark (CryptoJones) <cryptojones@owasp.org>
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.
An open thread never updated.
threadRepliesProviderwas a one-shot paginated query that resolved once and cached, so replies arriving afterwards — including the viewer's own, and agent replies — were never in that list. The activity feed looked instant while the thread it linked to sat frozen.What changed
ThreadLiveRepliesNotifier— alimit: 0subscription on the same filter (live only; history stays the paginated fetch's job), mirroringChannelsNotifier._subscribeLive./queryreturns but before the REQ registers is in neither result and is lost permanently — the same class of bug this provider exists to fix. Gated on aCompleterthat always completes, success or failure, so a thread that cannot subscribe still loads its backlog rather than hanging.RelaySessionNotifierdrops the subscription from_liveSubscriptions, so it is not replayed on reconnect — but the notifier would still hold a non-null_unsubscribeand report healthy while silently receiving nothing. A generation counter stops a stale callback tearing down a newer subscription._mergeRepliesde-duplicates by id.Auto-dispose is load-bearing on both new providers and is commented as such: a keep-alive family would leak one live subscription per thread opened for the whole app session, and the relay caps subscriptions.
Tests
Two new cases — a live reply arriving after the history fetch, and ownership held across a failed refetch.
Full mobile suite 906 pass. The single remaining failure (
ChannelDetailPage keeps follow mode off while a tall newest message stays visible) reproduces on a clean tree and is unrelated to this change.flutter analyzeclean,dart formatclean.Proudly Made in Nebraska. Go Big Red! 🌽 https://xkcd.com/2347/