Skip to content

Remember unread across restarts, from the server's read markers - #1105

Merged
grytchat merged 2 commits into
mainfrom
claude/read-state-client
Oct 27, 2026
Merged

grytchat merged 2 commits into
mainfrom
claude/read-state-client

Conversation

@grytchat

Copy link
Copy Markdown
Contributor

Client half of server#346, finding 2 from the beta.12 testing. Unread used to be counted only in memory from when the window connected, so it reset on every restart and on a new machine.

  • Sending: read:set goes out when a channel is opened, when a message lands in the channel you have open, and from Mark as read. Mark as read covers a channel, a folder and the whole server. Opening a channel and Mark as read send no message id, and the server reads up to its newest message. That's in One Tailwind utilities layer, not two (GRYT-858) #346 too.
  • Receiving: read:list is asked for on reload and on rejoin, as mentions already are. Its counts replace this window's only for conversations the server has a marker for. A channel you've never opened keeps what the window counted.
  • DMs: the client sends them like channels, and the server drops them, so a DM never gets a marker.
  • check-unread-tracker gets cases for the merge.

The first commit is from the Windows session, which started this and handed it over unfinished. The second finishes it.

Things to check:

  • Merge order: this does nothing until One Tailwind utilities layer, not two (GRYT-858) #346 is on the server. An older server ignores both events, so merging this first is harmless, but there's no point to it.
  • Rate limit: in a busy channel, one read:set per arriving message can hit the server's limit of 60 a minute. Dropped ones are harmless, because the next one moves the marker past them. But every accepted one sends back a full read:list.
  • Window focus: a message counts as read when it lands in the open channel, even if the window isn't focused. That's the same as the local count today.
  • Not tried in the app.

🤖 Generated with Claude Code

sivert-io and others added 2 commits October 27, 2026 17:36
Pairs with Gryt-chat/server#346. Pushed as a branch rather than a PR because it
is incomplete, and handed over rather than carried on.

Done:

- useUnreadTracker gains setServerUnread(host, counts), which replaces what the
  window had counted. A conversation the server leaves out has no marker and
  reads as caught up, not as everything unread. The doc comment no longer says
  counting starts when the window connected, because it no longer does.
- registerServerSocketEvents asks for read:list on the same two moments it asks
  for mentions -- a reload and a rejoin -- and applies the reply.

Not done:

- Nothing emits read:set yet, so nothing is ever recorded as read. The site is
  serverView's channel-opened effect, which calls markChannelRead; the newest
  message id has to come from useChat, which is destructured below it, so the
  emit needs its own effect further down rather than a line in that one.
- check-unread-tracker still tests the old model and will need rewriting.
- Mark as read, in MarkAsReadItem.tsx, has no message id to send. Either the
  server accepts read:set without one as "everything here", or the client finds
  the newest id for a conversation it may not have open.
- Channels only, by the same argument as the server side: a DM's marker would be
  a read receipt on an encrypted message.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Pairs with Gryt-chat/server#346. read:set goes out when a channel is
opened, when a message lands in the open one, and from Mark as read.
Without a message id the server reads up to its newest message, so
opening a channel and marking it read need no id. It ignores a DM.

The server's counts replace this window's only for conversations it
has a marker for. A channel never opened keeps what the window counted,
where before the reply wiped it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@grytchat
grytchat merged commit 4e88428 into main Oct 27, 2026
20 checks passed
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