Skip to content

Fix gap-loading for Mastodon timelines#482

Merged
dahlia merged 3 commits into
fedify-dev:mainfrom
dahlia:feature/gap-loading
May 14, 2026
Merged

Fix gap-loading for Mastodon timelines#482
dahlia merged 3 commits into
fedify-dev:mainfrom
dahlia:feature/gap-loading

Conversation

@dahlia
Copy link
Copy Markdown
Member

@dahlia dahlia commented May 14, 2026

#479 reports that clients like SubwayTooter cannot fill missing posts between cached ranges when talking to Hollo's timeline endpoints.

The four timeline endpoints (/api/v1/timelines/public, /api/v1/timelines/home, /api/v1/timelines/list/:list_id, and /api/v1/timelines/tag/:hashtag) treated min_id the same as since_id: a descending query with posts.id > cursor and LIMIT n. A request with min_id inside a gap larger than limit returned the newest posts above the cursor, not the posts immediately above it, so the middle of the gap was skipped and gap-loading never converged.

Hollo now handles min_id the same way Mastodon does. When min_id is set, the query switches to ORDER BY id ASC with the same LIMIT, then reverses the fetched rows before returning them. The response contains the limit posts immediately newer than the cursor, still ordered newest-first, so a follow-up request with the new rel="prev" cursor walks up through the gap.

The endpoints now also apply since_id, which the validator already accepted but the timeline queries ignored. When both min_id and since_id are set, min_id wins. Timeline responses now include a rel="prev" entry in the Link header alongside the existing rel="next", following the pattern already used by src/api/v1/notifications.ts. The Link header now tells clients which cursor parameter to send next.

The TIMELINE_INBOXES subqueries on /home and /list/:list_id apply the same ascending-order path internally, so they select the right post IDs before the outer query runs over them.

src/api/v1/timelines.test.ts adds five tests against /public covering bidirectional Link headers on a default fetch, large-gap convergence with min_id, since_id with descending timeline order, min_id precedence over since_id, and Link header cursor sanitisation. pnpm test passes.

Closes #479.

The four timeline endpoints (/api/v1/timelines/{public,home,
list/:list_id,tag/:hashtag}) treated min_id the same as since_id by
running a DESC query with a "newer than" filter, so a request with
min_id pointing into a large gap returned the newest posts above the
cursor instead of the posts immediately above it. Gap-loading clients
such as SubwayTooter could not converge.

Switch min_id to Mastodon's ASC-and-reverse semantics so the response
is the limit posts immediately newer than the cursor, still ordered
newest-first. Also honour since_id (previously declared in the
validator but never applied) and make min_id win when both are
supplied. Timeline responses now include a rel="prev" Link entry
alongside the existing rel="next" so clients no longer have to guess
the cursor parameter name.

The INBOXES sub-queries on /home and /list/:list_id apply the same
ASC switch so they pick the right post IDs before the outer query
runs.

Fixes fedify-dev#479

Assisted-by: Claude Code:claude-opus-4-7
@dahlia dahlia added this to the Hollo 0.9 milestone May 14, 2026
@dahlia dahlia self-assigned this May 14, 2026
@dahlia dahlia added the enhancement New feature or request label May 14, 2026
@dahlia
Copy link
Copy Markdown
Member Author

dahlia commented May 14, 2026

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Can't wait for the next one!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@dahlia
Copy link
Copy Markdown
Member Author

dahlia commented May 14, 2026

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements Mastodon-compatible pagination semantics for the public, home, list, and hashtag timeline endpoints. Key changes include the introduction of a buildTimelineLinkHeader helper for bidirectional Link headers and updated query logic to correctly handle min_id and since_id parameters. Feedback suggests optimizing the Link header helper by reusing the base URL object and refactoring the repeated pagination logic across endpoints into a shared utility to improve maintainability.

Comment thread src/api/v1/timelines.ts Outdated
Comment thread src/api/v1/timelines.ts Outdated
dahlia added 2 commits May 14, 2026 16:40
The helper now strips max_id, min_id, and since_id once on a base URL
and clones it for each rel link, instead of building two URLs and
running the same three deletes twice.

fedify-dev#482 (comment)

Assisted-by: Claude Code:claude-opus-4-7
Each of the four timeline endpoints derived the same useMinId /
lowerBound pair from the query: a literal copy of the Mastodon
precedence rule (min_id wins over since_id). Move the derivation into
a single helper so a future change to the precedence stays consistent
across endpoints.

fedify-dev#482 (comment)

Assisted-by: Claude Code:claude-opus-4-7
@dahlia
Copy link
Copy Markdown
Member Author

dahlia commented May 14, 2026

/gemini review

@dahlia
Copy link
Copy Markdown
Member Author

dahlia commented May 14, 2026

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the min_id handling for the public, home, list, and tag timeline endpoints to strictly follow Mastodon's pagination semantics. Key changes include the introduction of resolveTimelineCursor for consistent parameter priority and buildTimelineLinkHeader for generating bidirectional Link headers. The query logic was modified to use ascending sorts when min_id is present to support gap-loading, and comprehensive tests were added to ensure correct behavior across various cursor combinations. I have no feedback to provide.

@dahlia dahlia merged commit 0ebf4ad into fedify-dev:main May 14, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support gap-loading for timelines (SubwayTooter compatibility)

1 participant