Repository navigation
fix(web): show the room gap marker when only thread replies follow the hole - #58
Conversation
…e hole The room view anchored a gap marker only to a rendered event inside the timeline right after the hole. In agent rooms that timeline is usually all thread replies (filtered out of the room view), and their roots are fetched on their own and sit in no timeline, so the marker was dropped and whole threads vanished with no indication. Anchor to the first rendered event below the hole instead: one in the gap's timeline or a later one, or a fetched root newer than everything loaded above it. This mirrors what ZNC103 did for the thread view. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
zooidbot
left a comment
There was a problem hiding this comment.
Reviewed against ZNC103 (D3 anchor rule, D4 fill in place) and the surrounding use-timeline.ts / use-fill-gap.ts.
The anchoring change is right. roomGapBeforeEventIds applies the thread view's "this timeline or any later one" rule to the room view, and the timestamp fallback for fetched roots is the only signal there is for an event that belongs to no timeline. The repro test fails on main and the dedupe test covers two holes that resolve to one anchor. No objections to the hook.
Blocking: the marker this PR adds can't be clicked to fill the hole
The PR doesn't touch use-fill-gap.ts, and fillGap starts like this:
const anchored = room.getUnfilteredTimelineSet().getTimelineForEvent(eventId);
if (!anchored) return;In the case this PR exists for (the #product repro, test 1, and the WithHistoryGapBeforeFetchedThread story), the anchor is a fetched root that belongs to no timeline. So getTimelineForEvent returns null and the click does nothing: no spinner, no pagination, and the marker never retires. "Load more" pages the oldest timeline, so it doesn't fill the hole either. We'd go from no marker to a marker that does nothing when clicked. ZNC103 D4 (inherited from clients#22) says a marker fills its hole in place and retires on join.
Fix: have fillGap paginate the hole, not the anchor's timeline. Smallest change: when the anchor has no timeline, pick the gap-start timeline nearest above it. That's the latest gap whose hole start (holeStart as computed in roomGapBeforeEventIds) is before the anchor's ts. A gap-start timeline has no backward neighbour, so it's already its own chain head. Do it either by sharing that resolution from use-timeline.ts or by returning an anchor → gap timeline mapping next to gapBeforeEventIds, whichever reads cleaner. Keep the existing chain-head path for anchors that do have a timeline (room and thread views both rely on it).
Test: a use-fill-gap.test.tsx case with a fetched-root anchor (same setup as test 1) that asserts paginateEventTimeline gets called with the gap timeline, backwards. Ideally a second step joins the timelines and checks that gapBeforeEventIds goes empty.
Non-blocking
- Test 3 (fetched root older than the hole, only replies after it) correctly shows no room marker per D3. The hole is still real for that thread, and the thread view's marker covers it. Nothing to change.
… thread root Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
zooidbot
left a comment
There was a problem hiding this comment.
Re-reviewed dca0afe. The blocking finding is fixed. When the anchor has no timeline, fillGap falls back to gapTimelineAbove, and holeStart is now shared, so the marker and the fill find the same hole. Anchors that do have a timeline still take the chain-head path. The new use-fill-gap test covers the fetched-root anchor end to end: it paginates the gap timeline backwards, and the marker goes away once the timelines join. No blocking findings. Merging.
Problem
In #product on zooid.zoon.eco, the 06:00 standup thread and the 21:00 nightly-bugs thread were missing from the room view. A newer thread and an older one showed up next to each other with no "Load messages" marker between them.
The room view put a gap marker only before a rendered event inside the timeline right after the hole (
use-timeline.ts). In an agent room that timeline is usually:ensureRootFetched). Those roots belong to no timeline, sogetTimelineForEventreturns nothing.With no anchor, the marker was dropped. "Load more" pages the oldest timeline (#54), so it never filled the hole either.
Fix
roomGapBeforeEventIdsputs each gap marker before the first rendered event below the hole:This matches the "this timeline or any later one" rule ZNC103 (#55) added for the thread view. Holes that resolve to the same event share one marker.
Tests
use-timeline.test.tsx:main.Structures/TimelinePanel › WithHistoryGapBeforeFetchedThread, checked in light and dark mode. The marker sits between the two threads.🤖 Generated with Claude Code