nandi/frqpublic Fork 0
6b820ee
Commits
Clone
git clone https://git.rickub.com/nandi/frq.git
git clone ssh://git@rickub.com/nandi/frq.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Join a room already caught up on what was said before you

A room being joined for the first time has no marker, and a new buffer
started at zero — so the backlog the server replays on JOIN sat entirely
after the marker and was announced as unread. Being in a handful of busy
channels was enough to read as a hundred and one unread posts in one and
a hundred and ten in another, none of which anyone had missed: the
reader was not away for them, they were not there yet.

So a buffer nobody has seen before starts read rather than at the
beginning. To a minute ago, not to this instant: a live line is
timestamped by the server and this by our own clock, and where the two
disagree a message stamped a few seconds behind us would land under the
marker and never be counted at all. A minute is more skew than there
will be and far less than the age of any backlog. What it costs is that
a line said in the minute before you arrived counts as unread, which is
the direction that shows too much rather than too little.

Rooms that have been read are untouched — they come back from rooms.edn
with a marker of their own and never meet this default — and a DM that
arrives while nobody is looking still counts, because it is live and the
grace only reaches backwards.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandi committed 2026-09-06T02:26:55-07:00 Browse files
6b820ee parent: a5354cb
modified src/frq/state.jolt +18 -1
@@ -290,6 +290,22 @@
290290 :last-read-id (:id newest)
291291 :last-read-at (max (:last-read-at buffer 0) (:at newest 0)))))
292292
293+;; How far back a room nobody has seen before counts as already read.
294+;;
295+;; A room being joined for the first time replays its whole history, and none
296+;; of that is news the reader was not away for it, they were not here. So a
297+;; new buffer starts caught up rather than at the beginning, or joining a busy
298+;; channel announces a hundred unread posts from before you arrived.
299+;;
300+;; Caught up to a minute ago rather than to this instant, because a live line
301+;; is timestamped by the server and this by our clock: the two disagree by
302+;; whatever the skew is, and a live message stamped a few seconds behind us
303+;; would land under the marker and never be counted. A minute is more skew than
304+;; there will be and far less than the age of any backlog, and what it costs is
305+;; that a message sent in the minute before you joined counts as unread which
306+;; is the harmless direction.
307+(def ^:private fresh-room-grace-ms 60000)
308+
293309 (defn- ensure-channel [m name]
294310 (if (contains? m name)
295311 m
@@ -298,7 +314,8 @@
298314 ;; What has been seen, and what the count is derived from.
299315 ;; `:unread` and `:mention?` are answers, not records see
300316 ;; `recount`.
301- :last-read-id nil :last-read-at 0 :mention? false
317+ :last-read-id nil :mention? false
318+ :last-read-at (max 0 (- (clock/now-ms) fresh-room-grace-ms))
302319 :kind (if (dm? name) :dm :channel)
303320 :peer-did nil :last-activity 0
304321 ;; nick -> mode prefix, for the people panel
@@ -290,6 +290,22 @@
290 :last-read-id (:id newest)290 :last-read-id (:id newest)
291 :last-read-at (max (:last-read-at buffer 0) (:at newest 0)))))291 :last-read-at (max (:last-read-at buffer 0) (:at newest 0)))))
292 292
293+;; How far back a room nobody has seen before counts as already read.
294+;;
295+;; A room being joined for the first time replays its whole history, and none
296+;; of that is news the reader was not away for it, they were not here. So a
297+;; new buffer starts caught up rather than at the beginning, or joining a busy
298+;; channel announces a hundred unread posts from before you arrived.
299+;;
300+;; Caught up to a minute ago rather than to this instant, because a live line
301+;; is timestamped by the server and this by our clock: the two disagree by
302+;; whatever the skew is, and a live message stamped a few seconds behind us
303+;; would land under the marker and never be counted. A minute is more skew than
304+;; there will be and far less than the age of any backlog, and what it costs is
305+;; that a message sent in the minute before you joined counts as unread which
306+;; is the harmless direction.
307+(def ^:private fresh-room-grace-ms 60000)
308+
293 (defn- ensure-channel [m name]309 (defn- ensure-channel [m name]
294 (if (contains? m name)310 (if (contains? m name)
295 m311 m
@@ -298,7 +314,8 @@
298 ;; What has been seen, and what the count is derived from.314 ;; What has been seen, and what the count is derived from.
299 ;; `:unread` and `:mention?` are answers, not records see315 ;; `:unread` and `:mention?` are answers, not records see
300 ;; `recount`.316 ;; `recount`.
301- :last-read-id nil :last-read-at 0 :mention? false317+ :last-read-id nil :mention? false
318+ :last-read-at (max 0 (- (clock/now-ms) fresh-room-grace-ms))
302 :kind (if (dm? name) :dm :channel)319 :kind (if (dm? name) :dm :channel)
303 :peer-did nil :last-activity 0320 :peer-did nil :last-activity 0
304 ;; nick -> mode prefix, for the people panel321 ;; nick -> mode prefix, for the people panel