Skip to content

feat(feed): load For You pages through one composite document query - #369

Draft
QuantumExplorer wants to merge 1 commit into
PastaPastaPasta:stagingfrom
QuantumExplorer:feat/composite-feed-page
Draft

feat(feed): load For You pages through one composite document query#369
QuantumExplorer wants to merge 1 commit into
PastaPastaPasta:stagingfrom
QuantumExplorer:feat/composite-feed-page

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

What

Loads a For You feed page through ONE composite getDocuments request instead of about ten: the page, its like/repost/reply/quote counts, the posts it quotes, the authors' profiles and DPNS names, and (logged in) the viewer's own likes, reposts and bookmarks on the page, all under a single merged proof. The SDK derives every sub-query from the proven page, so the responding node cannot substitute, omit or inject any of it.

Cold anonymous /feed goes from 15 to 19 DAPI calls to about 4 (bootstrap 2, composite page 1, trending 1); a logged-in load drops by a similar amount.

Blocked on

Until then the change is inert: loadCompositeFeedPage checks for documents.composite at runtime and the v6 (refersTo-enforced) topology, and returns null so the legacy loaders run exactly as today. It also backs off for a minute after any composite failure. Bumping the evo-sdk dependency lights it up; no other switch is needed.

How

  • lib/feed/composite-feed-page.ts: builds the query from the contract topology helpers (likeIndexFor, repostIndexFor, bookmarkIndexFor, quoteFieldFor, replyCountFieldFor), decodes the result into the raw page plus a PreloadedEnrichment, seeds the DPNS and profile caches with the proven documents (including proven absences), attaches quoted posts, and stamps counts and the viewer's marks onto the posts. Anonymous pages also chain the quoted posts' authors' profiles off the join so embedded cards need no straggler hop; logged-in pages spend those request slots on the viewer's marks instead (the platform caps a request at 10 sub-queries).
  • lib/feed/load-for-you-feed.ts: tries the composite page first, for the first batch and the background top-ups. The feed paginates by document id while the composite surface paginates with a range clause on $createdAt, so the loader remembers the $createdAt of every cursor it handed out and translates; an unknown cursor takes the legacy path.
  • hooks/use-progressive-enrichment.ts: enrichProgressively(posts, preloaded?) merges the preloaded slices at once and only queries what they did not cover (per author for names/profiles/avatars, per post for stats/interactions). Same state shape, so PostCard and every per-card fallback are untouched. hooks/use-feed-data.ts passes the preload through and the viewer id down.
  • dpnsService.seedUsernames and unifiedProfileService.seedProfileDocuments: let proven lookups warm the batch resolvers; DPNS gains a five-minute negative cache so proven "no name" identities stop re-querying.

Repost attribution ("X reposted") stays on its own query: the repost count and a repost documents lookup would both read repost.byPost, which the composite rules forbid on one request, and the count is the better use of the slot. Quoted replies and blog quotes keep resolving through attachQuotedPosts, which now only runs for posts the composite did not already resolve.

Testing

  • npx tsc --noEmit clean; next lint on the touched files reports only the pre-existing warnings.
  • Not run against a network: no devnet with the composite surface exists yet. Once the evo-sdk bump lands, the query inspector should show one getDocuments for the page where it showed the page query, four grouped counts, the profile and DPNS batches and the quoted-post fetch.

🤖 Generated with Claude Code

One composite `getDocuments` request now answers a For You page and
everything a card needs to render it, under a single merged proof: the
posts, their like/repost/reply/quote counts, the posts they quote, the
authors' profiles and DPNS names, and (logged in) the viewer's own
likes, reposts and bookmarks on the page. The SDK derives every
sub-query from the proven page, so the responding node cannot steer
any of it. About ten round trips per page become one.

- lib/feed/composite-feed-page.ts builds the query from the contract
  topology, decodes the result into the page plus a
  `PreloadedEnrichment`, seeds the DPNS and profile caches, attaches
  quoted posts, and reports `null` when the surface is unavailable
  (an evo-sdk without `documents.composite`, a pre-v6 contract, or a
  recent failure with a one-minute backoff), so the legacy loaders
  keep working unchanged.
- lib/feed/load-for-you-feed.ts tries the composite page first and
  translates the feed's id cursors into the range clause the
  composite surface paginates with.
- useProgressiveEnrichment accepts the preloaded slices, merges them
  at once and only queries what they did not cover; PostCard and the
  per-card fallbacks are untouched.
- dpnsService.seedUsernames and
  unifiedProfileService.seedProfileDocuments let proven lookups warm
  the batch resolvers (with a short negative cache for proven
  absences).

Needs an evo-sdk release carrying the composite surface
(dashpay/platform#4601 and its stack) and nodes serving it
(dashpay/platform#4599); until then the capability check keeps this
change inert.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant