# Verify Pagination

Prove the next page of a list, or the next batch of an infinite scroll, loads NEW rows...

- Repository: https://github.com/reticlehq/reticle (1299 stars)
- Category: Engineering
- License: Apache-2.0
- Last updated: 2026-11-01
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add reticlehq/reticle --skill verify-pagination -g -a claude-code -y`
Codex: `npx skills add reticlehq/reticle --skill verify-pagination -g -a codex -y`
Cursor: `npx skills add reticlehq/reticle --skill verify-pagination -g -a cursor -y`
Gemini CLI: `npx skills add reticlehq/reticle --skill verify-pagination -g -a gemini-cli -y`
Claude Code plugin marketplace: `/plugin marketplace add reticlehq/reticle`

## Description

Prove the next page of a list, or the next batch of an infinite scroll, loads NEW rows from the server, repeats none, and that the end of the list is handled. Use when pagination or infinite scroll was added or changed, when a list shows the same rows twice or skips some, or when the last page still offers a next control.

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# The second page is where lists break

A list that renders its first page proves the first request works. The second page is where the offset is off by one, the cursor is reused, the same rows come back, or the append replaces what was there. The last page is where the "Next" button still fires a request for rows that do not exist.

**Reticle** can check all of that in the running app, against the requests the page really made. Not set up? Follow the [`reticle`](https://github.com/reticlehq/reticle/blob/main/skills/reticle/SKILL.md) skill: it installs Reticle, asks the user before `init` changes the app's files, and proves one flow.

## Confirm the session can observe

```
reticle_session({ action: "list" })
```

A hidden or throttled tab can accept a click and render nothing, and an infinite scroll that loads on an intersection observer may never fire at all. If the session is not healthy, get a context that is, for example a leased tab (`reticle_run({ tool: "reticle_lease", args: { action: "acquire", url } })`). Otherwise report the run as **blocked**, not passed.

## 1. Record the first page

Write down what is on screen before you touch anything, or you have nothing to compare the next page against:

```
reticle_look({ action: "find", sessionId, by: "role", value: "row" })
```

Use whatever the rows really are (`row`, `listitem`, `article`, or a `testid`). Keep the visible text of **every** row, not a sample: a repeat from the middle of page 1 is as much a bug as one from the top. If the result says it was truncated, scope the find to the list (`scope: "<the list's ref>"`) until it is not, or say which rows you could not see.

## 2. Load the next page, and name the consequence first

Name what must happen before the click, not after. For **numbered or next/previous pagination**, the page is replaced, so the first page's rows must be gone once the new request has answered:

The rest: https://github.com/reticlehq/reticle/blob/HEAD/skills/verify-pagination/SKILL.md
