Skip to content

Keep hidden channels out of the channel list when member or channel updates arrive - #6697

Draft
gpunto wants to merge 4 commits into
v6from
fix/v6-hidden-channel-not-removed
Draft

gpunto wants to merge 4 commits into
v6from
fix/v6-hidden-channel-not-removed

Conversation

@gpunto

@gpunto gpunto commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Goal

A channel hidden via channel.hidden is put back into the channel list by a channel.updated or
member.updated for the same channel, and stays there until the app restarts. The remove itself works: in the
reported logs the displayed grouped list empties and then has the channel back 38ms later, inside the same event
batch. Neither add path checks whether the channel is hidden.

Closes AND-1530

Implementation

  • Skip the add in DefaultChatEventHandler.addIfMembershipUpdated when the cached channel is hidden. This is the
    member.updated path, and it is the only one that applies to plain channel lists, since the base handler
    already skips channel.updated.
  • Skip it in GroupAwareChatEventHandler.routeByGroup when the cached channel is hidden, and remove the channel if
    it is still listed. This is the channel.updated path; the default group resolver always resolves a channel into
    the all sentinel group, so an all grouped query took the add unconditionally.

hidden is per-user and absent from channel.updated payloads, so both guards read the cached channel. Per-channel
event handling runs before query handling in the same batch, so for a channel whose state is active in memory the
flag is current. parseChatEventResults falls back to the database for channels that are not active, and the
database is only written after query handling, so on that fallback the guard sees the pre-batch value and does not
fire. Narrowing that gap means filtering hidden where the query map is written rather than per event, which is a
wider change than this fix.

The new-message add paths stay unguarded: a non-shadowed message clears hidden in ChannelEventHandler, which is
what makes a hidden channel resurface legitimately.

ChannelMutableState.toChannel() now resolves the current user from the userFlow it already holds instead of the
ChatClient singleton. Same value (StateRegistry is constructed with clientState.user), and it lets the state
layer be exercised without a built client.

Testing

  • New EventHandlerSequentialHiddenChannelTest drives EventHandlerSequential over the real StateRegistry and
    LogicRegistry. It replays the reported batch (notification.mark_read, channel.hidden, channel.updated,
    member.updated) against a grouped query, and covers a plain query hidden in one batch and updated in the next.
    Both fail without the guards. A third case asserts the same batch without the hidden event still adds the channel,
    so the assertions cannot pass vacuously, and a fourth asserts a new message brings a hidden channel back.
  • Unit coverage for each guard in DefaultChatEventHandlerTest and GroupAwareChatEventHandlerTest, including a
    hidden channel already in the list being removed.
  • Verified by hand against a real app: the Stream CLI reproduces it end to end (HideChannel, then
    UpdateMemberPartial or UpdateChannelPartial). After each of those calls the backend still excludes the channel
    from that user's QueryChannels response, so a list that shows it is out of sync with the server.

@gpunto gpunto added the pr:bug Bug fix label Sep 14, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled (or ignored for dependabot PRs).

🎉 Great job! This PR is ready for review.

@github-actions

Copy link
Copy Markdown
Contributor

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 5.26 MB 5.32 MB 0.05 MB 🟢
stream-chat-android-offline 5.49 MB 5.54 MB 0.05 MB 🟢
stream-chat-android-ui-components 10.64 MB 10.76 MB 0.11 MB 🟢
stream-chat-android-compose 12.87 MB 13.15 MB 0.28 MB 🟡

@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:bug Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant