Claude Code was asked to verify that every customer record had moved to a new schema. An MCP tool returned 100 records. All 100 had the new field, so the agent reported that the migration was complete.

The tool had also returned next_cursor. Claude Code never followed it.

There were 8,742 records in the collection. The first page happened to contain recent customers, which had all passed through the new write path. Thousands of older records still needed migration.

Nothing in the first page was false. The failure was in the denominator.

Collection completeness receipt for Claude Code

Make partial results impossible to mistake for complete results

A tool response should say whether it represents a whole collection or a page. Do not bury that fact in optional metadata.

{
  "items": ["...100 records..."],
  "page": {
    "returned_count": 100,
    "next_cursor": "cur_01K4...",
    "is_complete": false
  },
  "collection": {
    "snapshot_id": "customers:2026-08-29T09:18:00Z",
    "expected_count": 8742
  }
}

The control plane should refuse any claim about the whole collection while is_complete is false. That rule belongs in the tool adapter or evaluator, not in a prompt asking the model to remember pagination.

This distinction matters beyond migrations. A security review can miss old access grants. A dependency audit can inspect the first page of repositories. A cleanup run can revoke 100 tokens while leaving the next page active. The visible records may all be correct while the conclusion remains wrong.

Pin one collection snapshot

Following every cursor is necessary, but it is not enough. If records are added or deleted while the agent scans, later pages may belong to a different collection state. Offset pagination can skip or duplicate records as rows move.

Ask the source for a snapshot token or a stable upper bound:

scan_contract:
  source: customer-registry
  query: schema_version != 3
  snapshot_id: customers:2026-08-29T09:18:00Z
  expected_count: 8742
  page_size: 100
  max_pages: 89
  max_records: 9000
  deadline_seconds: 120

Every page request must carry the same snapshot_id. If the source cannot provide snapshot semantics, use a stable ordering key and record a high-water mark before the scan. State the weaker guarantee in the review packet. Do not label a moving scan complete when records could have crossed its boundary.

The limits matter too. Blindly following cursors can create a cost loop or trap the agent in a broken sequence. Set maximum pages, records, elapsed time, and repeated-cursor tolerance before the first call. Crossing a limit should stop with coverage_unknown, not quietly return whatever has been collected.

Reconcile more than the item count

A returned count of 8,742 can still hide duplication. The scan may have read one page twice and skipped another. Reconcile identifiers as well as totals.

coverage_checks:
  pages_expected_max: 89
  pages_observed: 88
  records_expected: 8742
  records_observed: 8742
  unique_ids_observed: 8642
  duplicate_ids: 100
  missing_id_ranges:
    - customer-4100..customer-4199
  terminal_cursor_observed: true
  result: failed

Here the total count looks perfect. The unique count exposes the missing page.

For large collections, you may not want every identifier in the review packet. Keep the detailed set in durable evidence storage and attach a digest, cardinality, duplicate count, and partition summary. If the source can provide per-partition counts or a Merkle root, compare them. A single grand total is a weak proof of coverage.

Also record filters. status=active and region=eu change the denominator. If the agent describes findings for all customers after scanning only active European customers, pagination is not the only problem. The receipt must bind the conclusion to the actual query.

Produce a collection completeness receipt

The run needs one artifact that lets a reviewer check what the agent actually covered.

collection_completeness_receipt:
  run_id: cc-run-5107
  tool: customer-registry.list
  query_digest: sha256:4c19...
  snapshot_id: customers:2026-08-29T09:18:00Z
  pages_observed: 88
  records_expected: 8742
  records_observed: 8742
  unique_ids_observed: 8742
  duplicate_ids: 0
  cursor_chain_digest: sha256:97ab...
  terminal_cursor_observed: true
  limits_hit: []
  coverage_status: verified
  conclusion_scope: all_records_in_snapshot

Bind the receipt to the query, tool contract, snapshot, run, and evidence store. Fetched all pages is not useful if nobody can tell which filter or collection state those pages represented.

The cursor_chain_digest preserves the traversal without filling the packet with every token. Keep the ordered cursor events in the trace. A reviewer or evaluator can recompute the digest and detect a missing, repeated, or reordered page.

If any count disagrees, a cursor repeats, the snapshot changes, or a limit fires, set coverage_status to unknown or failed. The agent may still report page-level findings, but it cannot make a collection-wide claim.

Test the failure paths

A happy-path pagination test proves little. Add fixtures for the ways collection scans break:

fixtures:
  - name: first_page_is_clean_but_next_page_has_failure
    expected: migration_incomplete
  - name: cursor_repeats_page_three
    expected: coverage_failed
  - name: total_count_matches_but_ids_are_duplicated
    expected: reconciliation_failed
  - name: snapshot_changes_between_pages
    expected: scan_restarted_or_blocked
  - name: page_limit_is_reached
    expected: coverage_unknown
  - name: final_page_has_no_cursor
    expected: terminal_cursor_recorded
  - name: filter_changes_during_retry
    expected: receipt_rejected

Run these through the real MCP adapter and policy path. A mock that always returns one complete page trains the evaluator to miss the production failure.

Put the receipt beside the test evidence that names what did not run and the trace completeness proof used for replay. Together they answer three different questions: what data was inspected, what tests ran, and whether the run can be reconstructed.

My rule is simple: Claude Code cannot make a claim about a collection until it proves the denominator. Follow the cursor against one snapshot, reconcile unique identifiers, enforce scan limits, and attach a completeness receipt to the review packet.

Claude Code: Building Production Agents That Actually Scale covers MCP boundaries, evals, observability, rollback, cost control, permissions, and review packets for production coding agents.