# Bind backward pagination cursors to request context

Safely paginate older records with a descending lookahead and chronological response when continuation tokens are user-controlled and UI context can change.

Exact reference: {"kind":"skill_version","skill_id":"skl_vAt3TjhmqfvBhant_C7Irg","version_id":"skv_MF0r6-M7qplMeGamCCWcdA"}

Applicability: []

# Bind backward pagination cursors to request context

Use this when an API selects older records in descending order with a one-row lookahead, returns each page chronologically, and accepts a user-controlled continuation token. Assume a unique stable ordering key; otherwise use a stable composite key in both the query and cursor.

## Preserve the page boundary

Fetch the requested page size plus one in descending order. The extra oldest row establishes whether another page exists but is not returned. Reverse the retained rows for presentation. When another page exists, the next cursor carries the oldest retained ordering key, not the lookahead row. The following query uses a strict older-than predicate.

## Issue an opaque authenticated cursor

Authorize the initial request, normalize every query-affecting filter and default, and choose a server-issued snapshot. Store the authorization scope, resource binding, canonical filter fingerprint, direction, snapshot reference, retained boundary key, token version, and expiry in server-side cursor state. Give the client a random handle with a server message authentication code. The handle reveals no internal resource or row identifiers. A standard authenticated-encrypted stateless token is an alternative, but a plain signed readable payload is not confidential.

Bind the page size too if changing it during traversal is disallowed. Sign with a managed key and allow bounded key rotation. Limit token length and lifetime. A token is a continuation hint, never an authorization grant.

## Validate before any page query

Authenticate the caller and reauthorize access to the requested resource. Check token format, authentication tag, version, and expiry; then compare its bound scope, resource, normalized filters, direction, page-size policy, and snapshot with the current request. Reject a mismatch or invalid token using one generic invalid-cursor response. Do not echo the token, internal identifiers, or which comparison failed. Do not build a data query from unverified fields.

The client should clear its cursor when the selected resource, filters, or direction changes. If an old cursor is nonetheless sent and rejected, restart from a fresh first page and snapshot rather than silently repurposing it.

## Define snapshot semantics explicitly

For immutable append-only records with immutable filter membership, a first-page high-water ordering key can exclude later inserts. It is not a full snapshot if records may be edited, deleted, or move into or out of filters. In that case use a database-supported as-of version or equivalent immutable view, and reject expired snapshot references.

## Basis

This combines the exclusive older-than ordering invariant with a trust-boundary analysis of user-controlled cursors. It is design reasoning only; no code was run or inspected and no runtime tests were executed.

## Supporting basis and limitations

Reasoned analysis of exclusive keyset boundaries and untrusted-token replay across request contexts. No runtime tests, repository inspection, or configuration inspection were performed.

## Change and rationale

Extends the ordering procedure with opaque signed cursor construction, context and snapshot binding, validation, authorization, and generic mismatch handling.

The prior guidance selected the correct page boundary but did not prevent a valid cursor from being replayed against another resource, filter set, direction, or snapshot. That omission matters whenever a UI retains a cursor across context changes.
