Skip to content

Count unread in channels you haven't opened, from when you joined (GRYT-1977) - #352

Merged
sivert-io merged 1 commit into
mainfrom
claude/GRYT-1977-unread-unopened
Oct 31, 2026
Merged

sivert-io merged 1 commit into
mainfrom
claude/GRYT-1977-unread-unopened

Conversation

@grytchat

Copy link
Copy Markdown
Contributor

The server only counted unread from a read marker, and you only get a marker by opening the channel. So a channel you'd never opened showed no badge however much arrived in it.

Now the moment you joined is the starting point. Older messages count as read and newer ones as unread. Opening the channel creates a marker, and the normal count takes over. This is all on the server, so desktop and web get it with no client change, because setServerUnread already takes a count for a channel with no marker. The phone needs mobile#462, which adds read:list.

I didn't write a marker per channel at join. That would need a write on every join and on every new channel. This reads users.created_at instead and writes nothing.

Look at:

  • server_config.unread_from is new, in db/sqlite/connection.ts, which is why this needs your review. The migration sets it to the time of the upgrade, so people who are already members count from then. Without it, everyone's unopened channels would fill up with old messages on day one. A fresh database leaves it null and uses the join date.
  • sendState now also runs the unopened count and visibleChannelIds, and that happens on every read:set, so once per message landing in an open channel. I haven't measured it on a big database. The query goes through idx_messages_conv_time.
  • Someone who leaves and rejoins keeps their old created_at, so an unopened channel counts from their first join. That can be a big number. I left it.

Tested: readMarkers.test.ts on a real database: messages before and after joining, your own messages, thread replies, a DM id, handing over to the marker, and unread_from. The socket test checks a channel you can't read stays out of the reply, and it fails if I remove that filter. I ran the migration on a database without the column: it sets the time once and keeps it on the next start.

Not tested: the badge on a real client. mobile#462 isn't merged, and I haven't run this with the desktop app.

GRYT-1977

🤖 Generated with Claude Code

…YT-1977)

The server only counted unread from a read marker, and a marker only exists
once you've opened the channel. So a channel you'd never opened showed no badge
however much arrived. It now counts from when you joined. Anybody who joined
before this upgrade counts from the upgrade, so old messages don't light up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@grytchat
grytchat requested a review from sivert-io as a code owner October 31, 2026 13:40
@sivert-io
sivert-io merged commit ebd1177 into main Oct 31, 2026
8 checks passed
@sivert-io
sivert-io deleted the claude/GRYT-1977-unread-unopened branch October 31, 2026 13:57
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