nandi/frqpublic Fork 0
a5354cb
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.

Know a replayed line the server sent no tags for

The backlog is well tagged — of a hundred and one lines the server
replayed on JOIN, a hundred carried both `time` and `msgid`, and every
one of those timestamps parses. One did not. No tags at all, mid-replay,
sitting between two that had them.

A line with no msgid is one `seen?` cannot recognise, so it is appended
again on every rejoin; a line with no `time` is stamped `now`, because
there is nothing else to stamp it with, and is therefore always newer
than the read marker. Together that is a buffer that grows a copy per
reconnect and a room that cannot be finished reading — three rejoins of
a three-line backlog left five messages, all five unread. The doubling
is as old as dedupe-by-msgid; the marker is what turned the rest of it
into a room that stays unread however often it is opened.

An untagged line still has a sender and words, and for a line the server
declined to name that is identity enough. Ours and the system's are left
out: they have no msgid either, and a second "ok" from this client or a
second "alice joined" is an event rather than a replay. What it costs is
that one person saying one thing twice, untagged both times, shows once
— which only arises when the server has already lost the tags.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandi committed 2026-09-06T02:17:43-07:00 Browse files
a5354cb parent: 234c54f
modified src/frq/state.jolt +24 -2
@@ -340,8 +340,30 @@
340340 ;; what keeps a rejoin from doubling the buffer and what
341341 ;; keeps a replayed *pre-edit* row from landing under a line
342342 ;; already showing the current text.
343- seen? (and id (some #(= id (:id %))
344- (get-in m [channel :messages])))]
343+ ;; And sometimes it replays a line with no tags at all
344+ ;; no msgid to know it by and no time to place it. That
345+ ;; line has no identity, so it arrives new on every rejoin:
346+ ;; appended again, timestamped `now` because there is
347+ ;; nothing else to timestamp it with, and therefore always
348+ ;; newer than the read marker. Left alone it is a buffer
349+ ;; that grows a copy per reconnect and a room that cannot
350+ ;; be finished reading.
351+ ;;
352+ ;; What it does have is a sender and words, which for an
353+ ;; untagged line is identity enough. The cost is that the
354+ ;; same person saying the same thing twice both times
355+ ;; untagged shows once. Ours and the system's are left
356+ ;; out of it: those have no msgid either, and a second
357+ ;; "ok" from this client, or a second "alice joined", is
358+ ;; a real event rather than a replay.
359+ seen? (if id
360+ (some #(= id (:id %)) (get-in m [channel :messages]))
361+ (and (not= "*" from)
362+ (not= from @form-nick)
363+ (some #(and (nil? (:id %))
364+ (= from (:from %))
365+ (= text (:text %)))
366+ (get-in m [channel :messages]))))]
345367 (cond
346368 ;; The copy we already hold is the pre-edit one, and this is
347369 ;; the server's collapsed row saying so. Same message, later
@@ -340,8 +340,30 @@
340 ;; what keeps a rejoin from doubling the buffer and what340 ;; what keeps a rejoin from doubling the buffer and what
341 ;; keeps a replayed *pre-edit* row from landing under a line341 ;; keeps a replayed *pre-edit* row from landing under a line
342 ;; already showing the current text.342 ;; already showing the current text.
343- seen? (and id (some #(= id (:id %))343+ ;; And sometimes it replays a line with no tags at all
344- (get-in m [channel :messages])))]344+ ;; no msgid to know it by and no time to place it. That
345+ ;; line has no identity, so it arrives new on every rejoin:
346+ ;; appended again, timestamped `now` because there is
347+ ;; nothing else to timestamp it with, and therefore always
348+ ;; newer than the read marker. Left alone it is a buffer
349+ ;; that grows a copy per reconnect and a room that cannot
350+ ;; be finished reading.
351+ ;;
352+ ;; What it does have is a sender and words, which for an
353+ ;; untagged line is identity enough. The cost is that the
354+ ;; same person saying the same thing twice both times
355+ ;; untagged shows once. Ours and the system's are left
356+ ;; out of it: those have no msgid either, and a second
357+ ;; "ok" from this client, or a second "alice joined", is
358+ ;; a real event rather than a replay.
359+ seen? (if id
360+ (some #(= id (:id %)) (get-in m [channel :messages]))
361+ (and (not= "*" from)
362+ (not= from @form-nick)
363+ (some #(and (nil? (:id %))
364+ (= from (:from %))
365+ (= text (:text %)))
366+ (get-in m [channel :messages]))))]
345 (cond367 (cond
346 ;; The copy we already hold is the pre-edit one, and this is368 ;; The copy we already hold is the pre-edit one, and this is
347 ;; the server's collapsed row saying so. Same message, later369 ;; the server's collapsed row saying so. Same message, later