fix(unreads): remove phantom dot badges when server reports zero unreads or you sent the latest message#883
Open
Just-Insane wants to merge 5 commits into
Open
Conversation
The no-readUpToId path in getUnreadInfo returned { total: 1 } (a phantom dot)
whenever the local SDK had no read receipt cached AND there was activity from
others in the live timeline - even when the server's notification count was 0.
A server count of 0 means the server has the user's receipt and knows the room
is fully read; the local cache is just stale (common after iOS cold-start, sync
gap, or rooms outside the active sliding-sync subscription window). Trusting
the synthetic count over the server's authoritative 0 caused phantom unread
dots on both DMs and Rooms that the user had already read.
Fix: remove the hasActivity + synthetic total:1 fallback entirely. Rooms with
no local receipt but non-zero server counts already fall through to the final
return statement (with DM force-highlight applied if needed), so real counts
are still displayed correctly. Rooms where both server and local cache agree
there is nothing unread now return 0, eliminating the phantom dots.
Restrict the phantom-unread suppression to events in NOTIFICATION_EVENT_TYPES (m.room.message, m.room.encrypted, m.sticker, etc.) so that reactions, membership changes, and other non-message events no longer incorrectly zero the badge.
Guard the phantom-unread suppression path with SUPPRESSABLE_SENT_EVENT_TYPES (m.room.message, m.room.encrypted, m.sticker) so that state events such as m.room.create and reactions do not incorrectly clear notification badges. Also pass room and userId to isNotificationEvent for consistent filtering. Addresses Copilot review comment on SableClient#883.
Just-Insane
added a commit
to Just-Insane/Sable
that referenced
this pull request
May 20, 2026
- fix(phantom-unreads): restrict badge suppression to SUPPRESSABLE_SENT_EVENT_TYPES (m.room.message / m.room.encrypted / m.sticker) and pass room+userId to isNotificationEvent to prevent state events from clearing badges (SableClient#883) - fix(dm-list-group-avatars): add GroupAvatarRowHideText/GroupAvatarMiniHideText CSS classes (32px/18px) so composite DM avatars scale properly in icon-only sidebar mode instead of leaving 14px minis in a 32px container (SableClient#816) - fix(media-cache): catch downloadMedia errors in openMediaInNewTab so a failed network response does not become an unhandled promise rejection (SableClient#870) - fix(media-cache): restore touchCacheEntry LRU tracking in useBlobCache.ts that was dropped during merge; cache hits now update the access timestamp so frequently-used entries are not prematurely evicted (SableClient#870) - fix(media-cache): restore SVG_BLOB_CACHE_MAX eviction cap and non-SVG URL fast-path in AvatarImage.useProcessedAvatarSrc that were dropped during merge; prevents unbounded memory growth and avoids a redundant fetch for every .png/.jpg/.gif/.webp avatar (SableClient#870)
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.
Summary
Eliminates two sources of phantom unread dot badges in the room list:
Server reports zero unreads — if the server sends a
m.room.summaryorm.fully_readmarker that clears the unread count to zero, the client was still showing a dot badge. Now the dot is suppressed when the server-reported count is zero.You sent the latest message — rooms where the authenticated user sent the most recent message were incorrectly showing a dot badge. The dot is now suppressed in this case since you clearly read your own message.
Changes
src/app/utils/room.ts: Two targeted fixes to the unread-dot logic.Testing
Type of change
Checklist:
AI disclosure:
[DRAFT — reword in your own words]: The two suppression conditions in
room.tswere drafted with AI assistance. The first skips the dot badge when the server-reported unread count is zero, guarding against stale local state after the server has acknowledged all reads. The second skips it when the most recent event sender matches the local user ID, since a message you sent yourself can't be unread.