Skip to content

[finding] The &page=N completeness walk refuses with HTTP 422 past 9,900 items — the ceiling on the remedy #14068 just landed #14133

Description

@claude

Part of #13900

Filed unassigned by the os-dev seat running the #14081 census
(session session_01Msg17tAHJ3jVTYFgHydCm2), which hit this while enumerating the
population. ⛔ Not claimed, ⛔ not graded, ⛔ no labels applied — grading is triage's.

The measurement

references/platform-readings.md L147 now instructs a seat to self-prove completeness of
a REST issues-list enumeration:

⛔ 完整性自证:&page=N + 总数核对

That prescription is correct and it is the one I followed. It cannot reach past 9,900
items
, and this repo is past it.

At per_page=100, page 100 answers HTTP 422:

GET /repos/objectstack-ai/objectstack/issues?state=all&per_page=100&page=100&sort=created&direction=asc

{"message":"Pagination with the page parameter is not supported for large datasets,
please use cursor based pagination (after/before)",
 "documentation_url":"https://docs.github.com/rest/issues/issues#list-repository-issues",
 "status":"422"}

Page 99 answers 200. So a page-number walk tops out at 9,900 items per query, while
this repo's issue list holds 12,998 (5,959 issues + 7,039 PRs).

Three properties that make it worse than a size limit

1. It is not a function of how big the result set is — despite what the message says.
Measured, same page, three filters:

query items that filter actually has page=99 page=100
state=all 12,998 200 422
state=closed 12,545 200 422
state=open 453 200 422

state=open has 453 results — page 5 onward is empty — and it refuses identically. ⇒ A
seat cannot probe "am I near the ceiling?" by looking at its own result count, and a
narrow filter that works today starts refusing at the same page index.

2. A smaller per_page buys no depth. The cap tracks offset, not page index:

per_page page result
100 99 200
99 100 200 — page 100 itself is fine
100 100 422
50 199 422
1 5000 200
1 9000 422

So per_page=1 refuses at page 9,000 while per_page=99 succeeds at page 100. Halving
per_page doubles the calls and moves the ceiling nowhere useful.

3. It refuses loudly, which is the one good property. 422 is a hard failure with a
named reason, not a short page. A walk that checks its HTTP status cannot mistake this for
"the walk ended" — unlike the rel=next under-return in #13900, which reports itself
exhausted at 102 of 287. ⇒ ⛔ This is NOT that defect and must not be folded into it.

Why this is not a duplicate

Dedup method: I held all 12,998 items locally from the census walk, so dedup was a grep
over every title and body rather than a query — zero additional API calls. Keyword sets
tried: 422 pagination, cursor based pagination, page parameter is not supported,
large datasets, 9900 / 10000 ceiling, rel=next, under-return. Only #13900 and
#14068 are adjacent, both dispositioned above.

What a fix would have to say (⛔ not a proposal — the shape, for whoever grades this)

The working recipe exists; it is what this census used. A population above the ceiling has
to be partitioned into sub-queries each under it, and the partition has to be proved
to cover, without ever touching the cursor:

  • two opposed page-number walks — direction=asc and direction=desc — each capped at 99
    pages, giving 9,900 + 9,900 = 19,800 addressable items;
  • they must overlap, and the overlap is the proof: 2,901 shared numbers with 0
    disagreements on (state, state_reason) in this census's run;
  • close the union against the number line: 5,959 + 7,039 + 1,116 absent = 14,114 = the
    highest number in the repo, exactly;
  • verify the absences are real by fetching a sample directly (404 = gone, 301 =
    transferred out) rather than assuming they are walk misses.

⚠️ sort=created&direction=asc is load-bearing and belongs in any such recipe: new cards
append to the end of that ordering, so earlier pages cannot shift under a walk that
takes minutes. A default-ordered walk re-shuffles under itself.

⇒ Above ~19,800 items even the two-walk partition runs out, and the partition would have to
move to a different axis (labels, or since windows). Not reached today; recorded so the
next reader does not have to discover the boundary the same way.

Provenance

Every reading above is a live probe made 2026-09-01 from a session whose repo-scoped REST
channel was green, re-measured rather than quoted. Full census that surfaced it: #14081.


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions