Secure Backward Cursor Pagination for Chronological Message Pages
Paginate older messages without gaps while keeping user-controlled cursors bound to the authorized query, opaque, and snapshot-stable.
Secure Backward Cursor Pagination
Trigger
Use this skill when an API reads older messages in descending order, returns each page chronologically, and accepts a user-controlled cursor that can remain after the conversation or filters change.
Practical steps
- Define a stable total order. If sequence is not unique, use the full immutable ordering tuple with a unique tie-breaker.
- Authenticate and authorize the conversation from the current request, canonicalize its effective filters, fix backward direction, and establish a high-water snapshot on the first page. Never let cursor claims select request scope.
- Query within the original snapshot and before the exclusive position, ordered descending, for page size plus one rows.
- If overflow exists, remove the final descending row before reversal. Reverse only the retained rows for chronological output.
- Set the next exclusive position to the oldest retained row. The discarded overflow row is lookahead evidence, not the cursor boundary.
- Bind purpose, format version, effective authorization scope, keyed conversation and filter digests, direction, sort definition, snapshot, position, and expiry.
- Keep internal identifiers opaque. Sign a random server-side handle that resolves to bound state, or use authenticated encryption for self-contained state. A readable signed payload provides integrity but not confidentiality.
- On continuation, verify authenticity and expiry, independently reauthorize and recompute current bindings, compare them safely, and query only after every check succeeds. Preserve the original snapshot and advance only the position.
- Reject signature, expiry, scope, direction, snapshot, and position failures with one generic invalid-cursor response. Do not reveal decoded values or mismatch details.
Limits
A high-water snapshot excludes later appends but does not freeze deletions, edits, backdated inserts, or changing filter membership. Strict repeatability requires immutable or versioned records, a materialized result set, or durable database-snapshot semantics. Page-size binding, key rotation, replay policy, and token storage are deployment choices.
This guidance is supported by reasoned analysis and an independent reasoning audit, not executed tests.
Failure prevented
Prevents skipped overflow messages, duplicate or missing pages, tampered boundaries, cross-conversation or cross-filter cursor reuse, direction confusion, authorization-scope mistakes, snapshot drift from later appends, and disclosure of internal identifiers.