feat(feed): cursor pagination for the inbox — scroll-end loads older conversations - #5860
Draft
thomaspblock wants to merge 2 commits into
Draft
feat(feed): cursor pagination for the inbox — scroll-end loads older conversations#5860thomaspblock wants to merge 2 commits into
thomaspblock wants to merge 2 commits into
Conversation
…conversations PR #5834 windowed the mentions feed per conversation, which fixed starvation but capped the inbox at the newest N conversations with no way to reach older ones. This adds an inclusive `until` cursor across the whole path so scroll-end loads the next page of older conversations. Relay/DB: - build_mentions_query takes `until` bounding conv_latest (the conversation's newest activity), NOT event time: pages are whole conversations, and no conversation whose latest activity falls between an event-time cursor and its conv_latest can be skipped. The candidate CTE stays unbounded by the cursor so page membership is stable. - needs_action / activity queries bound event time directly (flat feeds). - All Db wrappers and routed variants (replica/writer/fallback) thread `until`; the bridge feed path parses `filter.until` into all three. Desktop: - get_feed accepts `until`; e2e bridge mirrors the wire shape. - getOldestConversationActivity derives the cursor as min(conv_latest) across conversations in hand, mirroring the relay's conversation key (dm:<channel> / NIP-10 thread root) — pagination is gated on the channel list so DM keys resolve. - useHomeFeedPagination layers fetched-once older pages under the live 30s-polled first page; merge dedupes the inclusive boundary overlap by event id; `exhausted` stops fetching when a page adds nothing. - InboxListPane triggers fetchOlder within one viewport of scroll-end, re-checked on items growth so short pages chain; tail spinner (testid home-inbox-loading-older). Verification: - buzz-db feed suite 31/31 (incl. new Postgres paging test: 9 conversations, limit 3, cursor walks pages with inclusive boundary); SQL-shape test asserts the cursor does not leak into the candidate scan. - buzz-relay lib suite: 870 passed, 9 failures pre-existing on the base commit (api::media/admin/telemetry, verified via stash). - desktop: check/typecheck/test 4778 green; tauri tests 2415 green. - New Playwright spec inbox-pagination-screenshots.spec.ts proves scroll-end pages older conversations in against a live isolated relay (before/after screenshots); the windowing spec's "after" test now step-scrolls the virtualized list and tolerates sibling-spec conversations on a shared relay. Depth is bounded by FEED_WINDOW_SCAN_CAP (2000 events) — acceptable: the cursor reaches conversations far beyond the first window, and the cap keeps the scan predictable. Co-authored-by: Thomas Petersen <thomasp@squareup.com> Signed-off-by: Thomas Petersen <thomasp@squareup.com>
The cursor pagination `until` parameter pushed query_feed_mentions_routed and query_feed_needs_action_routed to 8 args, tripping clippy::too_many_arguments under -D warnings. Same allow already used on the neighboring routed wrappers in this file. Co-authored-by: Thomas Petersen <thomasp@squareup.com> Signed-off-by: Thomas Petersen <thomasp@squareup.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Cursor-based pagination for the Inbox, stacked on #5834 (per-conversation feed windowing). Scrolling to the end of the inbox list now loads the next page of older conversations instead of stopping at the newest window.
Why
#5834 fixed one chatty thread starving the inbox, but capped the inbox at the newest N conversations — anything older was unreachable. Follow-up agreed with @Thomasp: an inclusive
untilcursor that pages by conversation.How
Cursor semantics (the load-bearing decision): the cursor bounds conv_latest — each conversation's newest activity — not event time. Pages are whole conversations at-or-older than the cursor. An event-time cursor would skip every conversation whose latest activity falls between the oldest event in hand and that conversation's conv_latest. The boundary conversation intentionally reappears on the next page (inclusive nostr
until) and the client dedupes by event id.buzz-db/src/feed.rs):build_mentions_querygainsuntilon conv_latest; the candidate CTE stays unbounded by the cursor so page membership is stable. Flat feeds (needs_action, activity) bound event time directly. Threaded through all routed Db wrappers and the bridge feed path (filter.until).get_feedacceptsuntil;getOldestConversationActivityderives the cursor as min(conv_latest) across conversations in hand, mirroring the relay's conversation key (dm:<channel>/ NIP-10 root — gated on channel list load for DM keys);useHomeFeedPaginationlayers fetched-once older pages under the live 30s-polled first page;InboxListPanefetches within one viewport of scroll-end with a tail spinner.until; newinbox-pagination-screenshots.spec.tsproves scroll-end paging against a live isolated relay; the windowing spec's "after" test now step-scrolls the virtualized list (rows outside the viewport aren't in the DOM) and tolerates sibling-spec conversations.Pagination depth is bounded by
FEED_WINDOW_SCAN_CAP(2000 events) — documented, acceptable.Proof (Playwright, isolated relay on :3030)
60 single-message conversations seeded; page 1 holds the newest 50 — the oldest markers are beyond it. Scroll-end pages them in.
Before scrolling — first page only (marker 0 absent, asserted):
After scroll-end pagination — oldest conversation (
paged mention 0) loaded:Verification
check+typecheck+ tests 4778/4778; tauri tests 2415.Deliberately out of scope (unchanged from #5834): needs-action promotion for open PRs, participated-threads recall.