Repository navigation
feat(dashboard): Keep each reader's place in a Conversation - #2513
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
7faecc3 to
87a442c
Compare
3dc1599 to
21b49b6
Compare
2ebbecc to
7ac0f0b
Compare
Store one forward-only read position per user and Conversation, so all their devices share it. Detail returns the viewer's position, and the transcript reports the last row the reader saw. When a Conversation opens, rows that were unread get a "New" marker and the transcript opens there. A browser setting can open at the latest message instead. Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
Search results skip rows, so the transcript does not report reads while a search is active. A detail poll that started before a read report finished could put an older read position back in the cache. Keep the higher position, since read positions only move forward. Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
7ac0f0b to
bd958a7
Compare
|
4 screenshot changes — 3 changed · 1 added · 0 removed Review screenshots in Frameshift
|
A reopen showed the cached detail and froze the unread range from it, so messages that arrived while the reader was away got no New marker. Fetch the detail on each visit, take the last unread row from that fetch, and move to the marker when it appears before the reader scrolls. Leaving the page right after a scroll also dropped the pending read report. Send the measured row when the page unmounts or hides.
The unread range waited for the deferred render to catch up with the fetched detail. A poll could land first and add replies that arrived after open, so a reader at the latest message jumped to a late New marker. Take the last unread row from the first fetched detail, not the deferred copy.
Transcript entries are in seq order. Find the first seq after the read position once, then put the marker before the first row that reaches it, instead of checking each row and each activity group entry against the whole unread range.
BYK
left a comment
There was a problem hiding this comment.
I see a few optimizations we can have and am not sure are already in this code:
- On initial conversation loads, we can cap how far into the present we fetch initially based on the known "last read state" and then load piece meal in the background after the initial load/paint. We should also cap how much further back into the past we load and do virtual lists.
- To track positions we probably should leverage IntersectionObserver instead of relying on scroll events etc.
- When updating last read position, we should at least check locally that if it is larger than the last value we read from the server before making the request, right?
The read reporter measured rows on each scroll. An IntersectionObserver now keeps the set of rows in the viewport, and a MutationObserver adds rows as they mount. Reports send the highest seq in that set. A report at or before the cached server position is not sent. The New marker seq uses a binary search over the sorted transcript entries.
|
Replies to the review, in order. The code changes are in da0d25b.
|
An activity group row keeps its node and raises data-transcript-seq as tools arrive. Watch that attribute so the read reporter sees the new seq while the row stays in view.
…osition # Conflicts: # packages/junior-dashboard/src/client/conversations/transcriptBottomPinning.ts # packages/junior-dashboard/src/client/pages/settings/SettingsPage.tsx # packages/junior/migrations/meta/0071_snapshot.json # packages/junior/migrations/meta/_journal.json # packages/junior/src/api/conversations/AGENTS.md Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f3f9504. Configure here.

Like Slack, the dashboard now remembers how far each person has read a Conversation. It opens there and marks the spot with a "New" line.
Screenshots
Server
junior_conversation_read_positionstable (migration0071). It keeps one row per user and Conversation.PUT /api/conversations/:id/read-position. The stored value only moves forward (greatest(existing, new)). It is also capped at the last event, so devices can report in any order, and a bad client cannot hide messages that come later.readPositionfor the signed-in viewer. Other viewers never see it.Dashboard
data-transcript-seq. While the page is visible, the transcript reports the last row that reached the viewport, 750 ms after scrolling or layout changes stop. It reports only forward. A hidden tab and search results do not report. Leaving the page or hiding the tab sends the pending report at once.role="separator"). Rows that arrive later get no marker, so a reader who is following live replies does not see one.Known limits
Validation
read-position,detail, andarchiveintegration tests: 10 passed.conversation-send"hands web and external messages… without gaps" failed once under full-suite load, then passed alone and with--repeat-each 2.via @BYK.
--
View Session in Sentry