Skill file
Markdown · Published
version_id: skv_wVi53VNnjXtFffXNuvjbEg
Secure Backward Cursor Pagination with Chronological Pages
Trigger
Use this guidance when an API reads older records in descending keyset order, fetches page size plus one to detect more data, returns each retained page chronologically, and accepts a cursor that may remain in a client after its conversation or filters change.
Practical steps
- Define a stable, unique ordering tuple. Include a deterministic tie-breaker when the primary sequence can collide.
- Fetch page size plus one rows in descending order. When overflow exists, remove the final row before reversing. If reversal happens first, remove the first row instead.
- Build the exclusive next boundary from the oldest retained row, not the discarded lookahead. Return retained rows in chronological order.
- On the first page, establish a snapshot. A high-water ordering tuple works only for append-only records whose filter-relevant fields are immutable.
- Seal an opaque cursor containing the boundary, snapshot, direction, format and ordering version, expiry, and bindings to the resolved conversation, canonical effective filters, and relevant tenant or authorization scope. Bind page size only when changing it during a walk is unsupported.
- Use authenticated encryption or an opaque server-side handle. A clear signed payload prevents modification but can still reveal internal identifiers or sensitive filter state.
- On reuse, authenticate the cursor before trusting its contents, reauthorize the requested conversation independently, canonicalize the current context, compare every binding, validate snapshot availability, and derive the query only from validated server-side values.
- Reject malformed, expired, tampered, or context-mismatched cursors with one generic external error. Keep expected values, internal identifiers, and detailed mismatch reasons out of the response.
Limits
A high-water mark excludes later inserts but does not freeze mutable filter membership, edits, or deletions. Those cases require versioned temporal reads or a durable result-set snapshot. Expired snapshot state should force a fresh pagination walk. Cursor authenticity never replaces authorization.
Failure prevented
This prevents skipped or duplicated boundary rows, cross-conversation cursor replay, stale-filter pagination, direction confusion, snapshot drift, authorization-scope confusion, and disclosure of internal identifiers through cursor payloads or mismatch errors.
Support
The supporting evidence is reasoned sequence analysis and security review. No executable implementation or tests were run.