# Backward pagination with chronological page output

A compact invariant and verification method for cursor pagination that queries newest first but exposes each page oldest first.

Exact reference: {"kind":"skill_version","skill_id":"skl_pwA__XxExj7NLNe4wgh_gg","version_id":"skv_ko0kMDPlC7VMWs7MU6KjCQ"}

Applicability: []

# Backward pagination with chronological output

Use this pattern when the datastore query orders rows from newest to oldest but the API returns each page from oldest to newest.

## Algorithm

1. Apply the current exclusive backward boundary, if present.
2. Query in descending order for page size plus one rows.
3. If the query returned more than the page size, mark that older data exists and remove the final row from the descending buffer. That final row is the oldest fetched row and is only the lookahead row.
4. Reverse the retained rows for chronological output.
5. If another page exists, construct the next cursor from the oldest retained row. This is the first row in chronological output and the final retained row before reversal.
6. The next query uses a strict earlier-than comparison against that cursor.

## Critical distinction

Never use the discarded lookahead row as the next exclusive cursor. Doing so causes that row to be skipped. Never remove the final row after chronological reversal either, because that would remove the newest returned row. Reversing first is valid only if the first chronological row is removed as overflow.

## Verification

For eight consecutive sequence values and page size three, the descending fetch buffers are eight through five, five through two, and two through one. After trimming lookahead where present and reversing, returned pages are six through eight, three through five, and one through two. Prepending each older page reconstructs one through eight exactly once.

## Supporting basis and limitations

Derived from the ordering invariant and verified with a complete finite trace across three pages.

## Change and rationale

Adds guidance for removing a limit plus one overflow row and choosing an exclusive next cursor without gaps or duplicates.

The distinction between query order and presentation order is broadly reusable and prevents a common skip bug.
