Skip to content

Fix a bunch of cases where the read marker wasn't being updated - #3513

Closed
ruka-hamanasu wants to merge 3 commits into
krille-chan:mainfrom
ruka-hamanasu:repost-read
Closed

Fix a bunch of cases where the read marker wasn't being updated#3513
ruka-hamanasu wants to merge 3 commits into
krille-chan:mainfrom
ruka-hamanasu:repost-read

Conversation

@ruka-hamanasu

@ruka-hamanasu ruka-hamanasu commented Aug 28, 2026

Copy link
Copy Markdown

These cases would cause the dark blue dot to remain on a room (non-notifying events):

  • Push-rule-gated rooms: Read markers are no longer blocked when a room’s push rules match nothing (e.g. channels set to mentions-only). The marker targets the latest real message-like event instead.
  • Stuck unread indicator: If room.hasNewMessages is still true despite room.fullyRead already pointing at the latest event, the marker is re-posted to refresh receipt timestamps and clear the channel unread state. Note that this only happens if you are using another client such as Cinny that posts m.read or m.private_read but not m.fully_read.
  • Failed marker requests no longer wedge the room: _setReadMarkerFuture is released in whenComplete() even when the request fails.
  • Detached views not treated as at-bottom: When no scroll client is attached, the function falls back to the cached _scrolledUp flag instead of assuming the user is at the latest message.
  • Context slices protected: When viewing a sliced timeline (timeline.allowNewEvent == false), the newest loaded event is not treated as the room’s latest and the marker is not auto-advanced.

Tested by doing all the stuff CI does locally on my machine and by running an APK build on my phone. My homeserver/account are highly prone to this issue and I had several stuck rooms previously.

This interacts with a couple of Tuwunel bugs that I have also put up PRs for: matrix-construct/tuwunel#564 and matrix-construct/tuwunel#565 . Also now matrix-construct/tuwunel#566 which only impacts rooms with only backfilled events (like when the user is the first joiner from the local homeserver).

I am happy to split out the Cinny interaction fix into a separate PR if you like; that's the most impactful one for people who use multiple clients.

Pull Request has been tested on:

  • Android
  • iOS
  • Browser (Chromium based)
  • Browser (Firefox based)
  • Browser (WebKit based)
  • Desktop Linux
  • Desktop Windows
  • Desktop macOS

Comment thread lib/pages/chat/chat.dart
Comment thread lib/pages/chat/chat.dart
Comment thread lib/pages/chat/chat.dart
Comment thread lib/pages/chat/chat.dart
Comment thread lib/pages/chat/chat.dart Outdated
@ruka-hamanasu
ruka-hamanasu marked this pull request as draft August 28, 2026 21:49
@ruka-hamanasu

Copy link
Copy Markdown
Author

I'm going to try to figure out the minimal set of changes that fixes the problems, since I think a couple of these are too aggressive and could mark rooms as read when there are genuinely unread messages in them.

@ruka-hamanasu

Copy link
Copy Markdown
Author

Ok, I've made it less aggressive about updating the read marker, so it shouldn't mark events are read that the user hasn't actually seen or at least scrolled past.

@krille-chan

Copy link
Copy Markdown
Owner

@ruka-hamanasu can you please tell me how to reproduce the original problem on main branch? Because every time I mark a room as read on main branch it works perfectly fine so I thought the problem was already fixed

@ruka-hamanasu

Copy link
Copy Markdown
Author

@ruka-hamanasu can you please tell me how to reproduce the original problem on main branch? Because every time I mark a room as read on main branch it works perfectly fine so I thought the problem was already fixed

the repro is: on any Continuwuity or Tuwunel homeserver, use FluffyChat in rooms that are set up as "mentions only", wait for dark blue dot to appear, read room, observe dark blue dot never goes away.

DMed you a reg token for my homeserver which has a couple additional fixes for cases where Tuwunel's behavior exacerbated the problems, but they cover 1 niche case (room with only backfilled events), a case where if someone reacts to something while you're reading the room won't be marked read, and an interaction with other clients where the read marker can move backwards. This fix should show improvement on any Tuwunel or Continuwuity server because it makes FluffyChat advance the read marker even if there are only non-notifying events (messages but no mentions) in the room. Not sure why same doesn't happen with Synapse honestly (or even that it doesn't since I don't have a Synapse account).

@ruka-hamanasu

ruka-hamanasu commented Aug 29, 2026

Copy link
Copy Markdown
Author

Due to a report by a user who only uses FluffyChat that this wasn't happening to them, I investigated possible interactions with other clients. I've confirmed that the problem only occurs if you are also using a client that doesn't post m.fully_read. Cinny only posts m.read or m.private_read, never m.fully_read. So Cinny interacts fine with Cinny, and FluffyChat doesn't mess up Cinny, but Cinny messes up FluffyChat because FluffyChat ends up in a situation where hasNewMessages is true but m.fully_read already points at the last event in the room. In such a case, the only way to clear the dark blue dot is to post a fresh own receipt to update the timestamp.

On the bright side, that means you don't need a Tuwunel server to reproduce this; that was a red herring. All you need to do is to log Cinny into your account, read a few unread rooms with Cinny, then go and try to read those same rooms from FluffyChat.

Ruka Hamanasu added 3 commits August 30, 2026 11:25
setReadMarker() had a chain of failure modes that each left rooms
silently unmarked forever:

- The receipt target was gated on push rule evaluation, so rulesets
  that notify for nothing (e.g. mentions-only) could never mark any
  room read.
- The scroll-up banner suppressed marking even when already at the
  bottom; check the live scroll position instead of the cached
  _scrolledUp flag, which could get stuck when no scroll transition
  ever fired.
- The "nothing new" skip ignored whether the marker had reached the
  target event, so a marker left behind by another device never moved.
- A failed request left _setReadMarkerFuture set, permanently
  blocking all later attempts in that room; reset it in whenComplete
  and log failures.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants