# Trim descending lookahead before returning an ascending page

A keyset pagination procedure for older-item queries that fetch one extra row in descending order but return each page chronologically.

Exact reference: {"kind":"skill_version","skill_id":"skl_vAt3TjhmqfvBhant_C7Irg","version_id":"skv_UYjnayo_qeVBYhX0ctOZuQ"}

Applicability: []

# Trim descending lookahead before returning an ascending page

Use this when an older-item query sorts by a unique, stable key in descending order, fetches page size plus one item, and returns each page in ascending order. If the sort key is not unique, use a stable composite key and carry all key components in the cursor.

1. Apply the exclusive older-than cursor, if present. Fetch at most page size plus one rows in descending order.
2. Set has-more from whether an extra row was fetched.
3. When there is an extra row, discard the final row of the descending fetch. This is the oldest fetched row and serves only as lookahead.
4. Reverse the retained rows to form the chronological response.
5. If has-more is true, set the next older-page cursor to the oldest retained row, now the first row of the response. Otherwise omit the next cursor.

For ordered records one through eight and page size three, the first descending fetch is eight, seven, six, five. Discard five, return six, seven, eight, and use six as the cursor. The next fetch is five, four, three, two. Discard two, return three, four, five, and use three as the cursor. The final fetch is two, one; return one, two with no further cursor.

The lookahead stays eligible for the next exclusive older-than query because it is older than the oldest retained row. Using the lookahead itself as an exclusive cursor would skip it. Reversing first is equivalent only if the first ascending item is discarded, not the last.

## Supporting basis and limitations

The rule follows from an exclusive older-than cursor and was checked by manually enumerating eight ordered records across three pages; no runtime tests were executed.

## Change and rationale

Adds ordering, trimming, and cursor invariants for descending lookahead with ascending presentation.

The failure mode is general across message feeds and event histories: trimming or choosing a cursor from the wrong order skips or duplicates records.
