Evidence ledger 21 sources Checked 01 Oct 2026

Evidence ledger

One row per claim in The cursor is a lease, not a bookmark: paginating the unbounded list: who published it, what grade it carries, when it was written, when the link was last checked, and the quote or figure it rests on. Nothing in the guide is cited from memory, so anything not in this table is not in the guide.

One row per claim. Tier grades follow the skill's hierarchy (postmortem > source > adr > casestudy > paper/talk > blog > vendor). Checked dates are when the URL was fetched in this session. This session's network egress allowed code hosts (github.com, gitlab.com, raw.githubusercontent.com) and a few registry and documentation hosts; engineering-blog platforms, USENIX, arXiv and video hosts were refused by the egress proxy, so the guide is built from the repository-native and vendor-documentation record and discloses that.

# Org Title Tier Published Checked URL Claim I take from it Supporting quote or figure
1 GitLab Production incident 5843: silent change to offset pagination limit impacted a customer postmortem 2021-11-02 2026-10-01 https://gitlab.com/gitlab-com/gl-infra/production/-/issues/5843 Tightening an offset limit behind a feature flag broke a paying customer's tooling; the pagination contract is an API contract. "The feature flag lower_relation_max_count_limit has been temporarily set to false, while the affected customer re-writes their tooling to deal with the lack of total count & page information in our billable_members API responses."
2 Kubernetes Issue 98423: kube-apiserver high memory usage on pending pods storm postmortem 2021-01-26 2026-10-01 https://github.com/kubernetes/kubernetes/issues/98423 An operator's production record of list-driven memory explosion: ~90 GB apiserver spike and OOM during a 400-node upscale with thousands of pending pods. "The kube-apiserver consumed memory spiked to ~90G the moment we upscaled the cluster with +400 nodes while having thousands of pending pods."
3 Kubernetes Issue 114276: apiserver builds up high memory after serving a few large LIST requests source 2022-12-04 2026-10-01 https://github.com/kubernetes/kubernetes/issues/114276 Reproduction with numbers: twenty sequential ~50 MiB LIST responses leave the apiserver holding 1.5 GiB. "The apiserver process has 1.5 GIB memory usage after sequentially serving a few large LIST requests (about 50MiB in response size)."
4 Kubernetes Design proposal: consistent API chunking adr merged 2017-08-29 2026-10-01 https://github.com/kubernetes/design-proposals-archive/blob/main/api-machinery/api-chunking.md The continuation-token design: opaque token encoding a snapshot version plus a position, served natively by the store's range reads. "Our primary consistent store etcd3 offers support for efficient chunking with minimal overhead, and mechanisms exist for other potential future stores such as SQL databases or Consul to also implement a simple form of consistent chunking."
5 Kubernetes community PR 896: design for consistent API chunking adr opened 2017-08-11, merged 2017-08-29 2026-10-01 https://github.com/kubernetes/community/pull/896 The recorded design argument: tokens must be opaque, and a reviewer objected that tokens embedding store keys could leak names the caller cannot see. Review record: clients "must consider the continue token as opaque"; reviewer raised that continue tokens containing etcd keys could expose namespace and object names to users lacking permission.
6 Kubernetes KEP-3157: watch list, streaming lists adr KEP in kubernetes/enhancements, checked state 2026-10-01 https://github.com/kubernetes/enhancements/blob/master/keps/sig-api-machinery/3157-watch-list/README.md Even paginated LISTs cost about five times the etcd response in temporary memory, and the project's answer is to stop paginating and stream instead. "The bottom line is around O(5*the_response_from_etcd) of temporary memory consumption. Neither priority and fairness nor Golang garbage collection is able to protect the system from exhausting memory."
7 Kubernetes KEP-3157: watch list, streaming lists adr KEP in kubernetes/enhancements, checked state 2026-10-01 https://github.com/kubernetes/enhancements/blob/master/keps/sig-api-machinery/3157-watch-list/README.md The measured goal: from O(watchers × page-size × object-size × 5) down to a ~2 MB constant per watcher. "considerably reduce (temporary) memory footprint of LISTs, down from O(watchers*page-size*object-size*5) to O(watchers*constant), constant around 2 MB."
8 Kubernetes Docs: API concepts (list pagination semantics) vendor current, checked state 2026-10-01 https://github.com/kubernetes/website/blob/main/content/en/docs/reference/using-api/api-concepts.md A continue token is a lease, not a bookmark: it expires in about five minutes and the server answers 410 Gone, offering an inconsistent restart. "a continue token will expire after a short amount of time (by default 5 minutes) and return a 410 Gone if more results cannot be returned"
9 Kubernetes kubectl get source source current master 2026-10-01 https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/kubectl/pkg/cmd/get/get.go The flagship client pages by default: chunk size 500. "NewGetOptions returns a GetOptions with default chunk size 500."
10 Elasticsearch IndexSettings.java source current main 2026-10-01 https://github.com/elastic/elasticsearch/blob/main/server/src/main/java/org/elasticsearch/index/IndexSettings.java The default refusal point for offset-style paging is 10,000 hits per index. MAX_RESULT_WINDOW_SETTING = Setting.intSetting("index.max_result_window", 10000, 1, ...)
11 Elasticsearch Docs: paginate search results vendor current main 2026-10-01 https://github.com/elastic/elasticsearch/blob/main/docs/reference/elasticsearch/rest-apis/paginate-search-results.md Why the window exists: every shard must materialise all previous pages, so depth converts directly into memory and CPU on every shard. "Each shard must load its requested hits and the hits for any previous pages into memory. For deep pages or large sets of results, these operations can significantly increase memory and CPU usage, resulting in degraded performance or node failures."
12 Elasticsearch Docs: paginate search results vendor current main 2026-10-01 https://github.com/elastic/elasticsearch/blob/main/docs/reference/elasticsearch/rest-apis/paginate-search-results.md The sanctioned deep walk is search_after plus a point-in-time, because a refresh between pages reorders results. "If a refresh occurs between these requests, the order of your results may change, causing inconsistent results across pages. To prevent this, you can create a point in time (PIT) to preserve the current index state over your searches."
13 GitLab Issue 8754: Elasticsearch results jumping to last page gives HTTP 500 source 2018-12-07 2026-10-01 https://gitlab.com/gitlab-org/gitlab/-/issues/8754 GitLab.com hit the 10,000 window in production search; the team's reading was to fix pagination, not raise the window. "Result window is too large, from + size must be less than or equal to: [10000] but was [36920]. ... setting index.max_result_window to a higher value probably won't perform well so we should really be looking at implementing an efficient pagination strategy."
14 GitLab MR 251701: cap search pagination at the Elasticsearch result window (closed unmerged) source opened 2026-08-24, closed 2026-09-18 unmerged 2026-10-01 https://gitlab.com/gitlab-org/gitlab/-/merge_requests/251701 Eight years after issue 8754 the same window still surfaces as user-facing 500s, and a capping fix was attempted and closed without merging; the close reason is not visible to this session. "Searching merge requests past the Elasticsearch result window returns 400 Bad Request from the indexer, which surfaces to the user as a 500"
15 GitLab MR 256256: encode an offset in policy store pagination cursors (closed unmerged) source opened 2026-09-17, closed 2026-09-18 unmerged 2026-10-01 https://gitlab.com/gitlab-org/gitlab/-/merge_requests/256256 A recorded cursor-design bug: a cursor that encodes a page number silently depends on the previous request's page size, skipping or repeating rows when the client changes it. "The cursor encoded a page number, so the rows a cursor pointed at depended on the page size used for the previous request. A client that changed first mid-walk skipped or repeated policies"
16 GitLab Docs: REST API pagination vendor current master 2026-10-01 https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/api/rest/_index.md Keyset is positioned as the scale path: offset was deprecated on the users endpoint in 16.5 and keyset is enforced there beyond 50,000 records since 17.0. "The users endpoint enforces keyset-based pagination when the number of requested records is greater than 50,000 in GitLab 17.0." and "runtime is independent of the size of the collection."
17 GitLab Docs: REST API pagination (response headers) vendor current master 2026-10-01 https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/api/rest/_index.md The count, not the page, is what gets rationed: beyond 10,000 records GitLab stops sending totals and the last-page link. "For performance reasons, if a query returns more than 10,000 records, GitLab doesn't return the following headers: x-total, x-total-pages, rel=\"last\" link"
18 GitLab Development guidelines: pagination adr current master 2026-10-01 https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/database/pagination_guidelines.md The internal engineering rule: offset cost grows with the page number, which makes it unsuitable for large tables; keyset reads only the page it returns. "When requesting a large page number, the database needs to read PAGE * PAGE_SIZE rows. This makes offset pagination unsuitable for large database tables." and "this query read only 5 rows (offset-based pagination would read 10 rows)"
18b GitLab Development guidelines: pagination adr current master 2026-10-01 https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/database/pagination_guidelines.md Switching schemes is formally a breaking change, and keyset cannot express page numbers, so UX decides as much as the database does. "Removing one type of pagination entirely is a breaking change." and "Keyset pagination cannot provide page numbers because the paging logic might depend on different columns."
19 GitHub Docs: using pagination in the REST API vendor current main 2026-10-01 https://github.com/github/docs/blob/main/content/rest/using-the-rest-api/using-pagination-in-the-rest-api.md The navigation contract is the Link header, with rel next, prev, first and last supplied by the server. "You can use the link header from the response to request additional pages of data." Example shows rel=\"last\" pointing at page 515.
20 GitHub Docs: REST search API vendor current main 2026-10-01 https://github.com/github/docs/blob/main/content/rest/search/search.md Search is capped outright: the API serves at most the first 1,000 results of any query. "the GitHub REST API provides up to 1,000 results for each search."
21 Mastodon API guidelines: pagination vendor current main 2026-10-01 https://github.com/mastodon/documentation/blob/main/content/en/api/guidelines.md A third shape in the wild: cursoring by entity ID (max_id, min_id, since_id) with Link headers, no offsets and no totals. "Many API methods allow you to paginate for more information, using parameters such as limit, max_id, min_id, and since_id."
22 PostgreSQL Docs: LIMIT and OFFSET (queries.sgml) vendor current master 2026-10-01 https://github.com/postgres/postgres/blob/master/doc/src/sgml/queries.sgml The storage engine's own statement of offset cost: skipped rows are still computed. "The rows skipped by an OFFSET clause still have to be computed inside the server; therefore a large OFFSET might be inefficient."
23 npm registry API docs (search endpoint) vendor current main 2026-10-01 https://github.com/npm/registry/blob/main/docs/REGISTRY-API.md A deliberately offset-paginated API at registry scale, with a small hard page cap: size default 20, max 250, offset via from. "size ... how many results should be returned (default 20, max 250)"; "from ... offset to return results from"
24 npm live search endpoint record source fetched 2026-10-01 2026-10-01 https://registry.npmjs.org/-/v1/search?text=kubernetes&size=3&from=3 The live endpoint honours from/size and returns a total (6,364 for this query on the check date), so offset plus counts is a working choice at bounded result sizes. Response JSON: "total": 6364 with 3 objects returned at offset 3.
25 Docker Hub live tags endpoint record source fetched 2026-10-01 2026-10-01 https://hub.docker.com/v2/repositories/library/python/tags/?page_size=2 A page-number API that hands the client a ready-made next URL and a full count (3,923 tags on the check date). Response JSON: "count": 3923, "next": "https://hub.docker.com/v2/repositories/library/python/tags/?page=2&page_size=2"

Sources located but not usable in this session

Ahmet Alp Balkan's measured write-up of Kubernetes list performance (ahmet.im), the Kubernetes blog post on API streaming (kubernetes.io), engineering-blog accounts of cursor pagination at Slack, Shopify and Stripe, and all conference talks and papers on the topic were located via search, but their hosts were refused by this session's egress proxy. None of them is cited and none of their content is used; the gap is disclosed in the guide. The guide therefore contains no blog, paper or talk tier sources, and its two postmortems are the incident records publicly readable on the code hosts.