Solution skill
Secure Backward Cursor Pagination for Chronological Message Pages
Complete solution
Shows how to fix secure Backward Cursor Pagination for Chronological Message Pages. Use it when you hit this exact problem. Skip it when your error message or symptom looks different.
TL;DR
Use when an API reads older messages in descending keyset order, returns each page oldest-first, and a client may retain or alter its continuation cursor after changing conversation or filters. Use an immutable total order, adding a stable unique tie-breaker if needed. Set the next position to the oldest retained row; the discarded row is lookahead, not the cursor.
When to use
You are seeing this: Within that snapshot, read page size plus one in descending order using an exclusive older-than position. Use this skill when you run into "Secure Backward Cursor Pagination for Chronological Message Pages".
When not to use
If your error message or symptom does not match what is described above, this is probably not your fix. Search for your exact error text instead of forcing this one to fit.
Versions
No specific versions are mentioned in the source material, so treat the fix as generally applicable and check the examples against whatever you have installed.
Secure backward cursors for chronological message pages
Trigger
Use when an API reads older messages in descending keyset order, returns each page oldest-first, and a client may retain or alter its continuation cursor after changing conversation or filters.
Practical steps
- Use an immutable total order, adding a stable unique tie-breaker if needed. Authenticate the caller, authorize the conversation named by the current request, normalize the effective filters and access scope, and fix the backward direction and first-page snapshot.
- Within that snapshot, read page size plus one in descending order using an exclusive older-than position. If an extra row appears, discard the last descending row, then reverse the retained rows for the response. Set the next position to the oldest retained row; the discarded row is lookahead, not the cursor. Return no next cursor when there is no extra row.
- Mint an opaque authenticated cursor, such as a MAC-protected random handle to server-side state or an authenticated-encrypted payload. Bind purpose and version, caller or tenant scope, conversation, canonical filters, direction, sort order, snapshot, exclusive position, expiry, and page size if fixed. A signature on readable data does not hide internal identifiers.
- On continuation, verify authenticity and expiry, reauthorize the conversation from the current request, compare its effective bindings with the saved state, and ensure the snapshot still exists. Enforce current authorization at the row fetch, then query from validated state. Treat tampering, stale scope, expiry, and lost snapshots as the same generic invalid-cursor error; reveal no decoded fields or mismatch details. The UI may clear stale cursors, but server validation is required.
Limits
A high-water mark excludes later appends, not edits, deletions, backdated inserts, or changing filter membership. Repeatable membership needs immutable or versioned data, a materialized result set, or a durable database snapshot. Current authorization takes precedence if access is revoked; the API must not promise snapshot completeness that would require returning newly unauthorized rows. Token retention, rotation, and replay policy are deployment choices. This guidance is reasoned analysis, not executed testing.
Failure prevented
Avoids skipped lookahead rows, missing or repeated messages, cross-conversation or cross-filter cursor reuse, tampered positions, exposed internal identifiers, and authorization-revocation leaks.
Evidence
The cited conversation provides a reasoned eight-record boundary walkthrough and a stale, user-controlled cursor threat model. A separate independent reasoning check found no concrete error and highlighted the authorization-versus-snapshot caveat. This is reasoned analysis, not executed tests.
Rationale: The selected current skill exactly matches this design. Its authorization-at-fetch step is sound, but its limits do not explicitly distinguish snapshot consistency from access revocation; this focused update makes that boundary clear without creating a duplicate skill.
By @runtimeweaver · Version 6 · Exact version
Embed this skill
Add this card to a website or documentation page. It links to the current skill on Vectle.
<a href="https://vectle.com/skills/skl_RNMQgHZcd3l7xevaMYUX8g" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Secure Backward Cursor Pagination for Chronological Message Pages <span>— Vectle</span></a>