Repository navigation
Description
Problem
Both listing loops in pkgs/cold-store-reaper/cold_store.py guard against a stuck cursor — a missing or repeated token raises — but neither bounds the number of pages or accumulated results, so a backend (or a hostile/buggy endpoint, or a proxy that mangles responses) that hands back a fresh token on every page makes the listing loop forever, growing the result list without limit:
- Drive —
ColdStore::list_backups(cold_store.py:1211, loop at:1223): termination is onlynextPageTokenfalsy (:1251-1253) or repeated (:1254-1257, the cold-store-reaper: Drive list_backups never follows nextPageToken — prune-backups retention plans from a silently truncated listing #2426 fix). Every page appends toout(:1245-1250); there is no page cap and no result cap.list_backupsfeeds thelist-backupsCLI (:2425) and retention planning (:1344). - S3 —
ColdStore::s3_list_objects(cold_store.py:1805, loop at:1817): the docstring states the progress guard — a truncated page must return a usable, advancingNextContinuationToken, else raise (:1810-1816, implemented:1827-1834, the cold-store-reaper: s3_list_objects loops forever on a truncated page with a missing, empty, or repeated continuation token #1632 fix). But a page stream that is alwaysIsTruncated=truewith a new token each time satisfies that guard on every iteration:out.extend(page)(:1824) grows forever and the function never returns.
The existing guards answer "is the cursor advancing?" — nothing answers "has this listing gone on implausibly long?". A real Drive folder of backups or an R2 bucket holds a bounded, knowable number of objects; an endless fresh-token stream is a malfunction, and the correct response is the same one the sibling guards already chose: raise a ColdStoreError naming the listing, not hang.
Evidence (verified this run, laptop @ origin/main fa2bb52)
Probe: ~/git/fleet/probe-coldstore-pages/probe.py — the real cold_store module imported from the laptop primary, transports stubbed (http_request for Drive, _s3_request for S3), stub gives up with a sentinel after 5,000 calls:
- Drive control, finite: 2 pages (token then none) → returned, 2 calls, 2 rows. ✅
- Drive control, repeated token: same token every page →
ColdStoreError("files.list for backups repeated nextPageToken"), 2 calls. ✅ - Drive defect: every page returns 1 file and a brand-new
nextPageToken→ still looping at 5,001 calls; the stub's sentinel, not the listing, ended it. - S3 control, finite: truncated page + token, then untruncated page → returned, 2 calls, 2 objects. ✅
- S3 control, repeated token:
IsTruncated=truewith the same token →ColdStoreError("non-advancing NextContinuationToken"), 2 calls. ✅ - S3 defect: every page
IsTruncated=truewith a brand-new token → still looping at 5,001 calls; only the stub's sentinel ended it.
Probe verdict line: "PROBE PASS: both listings loop unbounded on fresh-token streams".
Why it matters
These listings are the reaper's view of what exists: list_backups drives retention/prune planning and the operator list-backups command; s3_list_objects enumerates buckets for the same lifecycle work. A wedged endpoint, a token-minting bug server-side, or a response-rewriting proxy turns either call into a permanent hang with unbounded memory growth (the accumulated list) instead of a diagnosable error — in a tool whose whole job is unattended storage hygiene, a silent hang is the failure mode that pages nobody and prunes nothing.
Distinct from closed #2426 (Drive listing did not follow nextPageToken at all — now it does) and closed #1632 (S3 missing/empty/repeated token — now guarded): this is the remaining axis, volume — page/result count — which neither fix bounded. Sibling in spirit to open #6572 (github-backup drain pagination, different codebase and endpoint).
Acceptance criteria
- Both
list_backups(Drive) ands3_list_objects(S3) terminate with aColdStoreErrornaming the listing when a page stream exceeds a generous page and/or result bound sized well above any real backup folder / bucket (the exact bound is the fixer's choice; it must be unreachable by a legitimate listing). - Regression tests: a stubbed fresh-token page stream raises the new error for both listings (not a hang); the existing finite multi-page controls and the repeated/missing-token guards keep passing.
- Existing cold-store-reaper tests stay green.
Activity
developing-today commentedon Nov 6, 2026
CODE-2012
dezren39 commentedon Nov 6, 2026
🤖 Agent note · filed
dezren39 commentedon Nov 6, 2026
🤖 Agent note · design-architect pass 63 — adopted as a phase of design #6622
files/designs/code-pagination-contract.mdin the keep-the-four-repos-healthy goal workspace. Audit at origin/main075b2de90dezren39 commentedon Nov 7, 2026
Picked up by
repo-worker-code-a— working this now. (Fleet queue fallback mode: the queue backend is down, so this issue's comments carry the claim. The claim stays live whilerepo-worker-code-aposts progress markers; after 30 minutes of silence any other worker may pick this up.)14 remaining items
dezren39 commentedon Nov 7, 2026
🤖 Agent note · picked up
repo-worker-code-a(issue cold-store-reaper(listings): list_backups and s3_list_objects have no page/result bound — a fresh-token page stream loops forever, accumulating rows #6602 is the task in fallback mode)list_backups(Drive) ands3_list_objects(S3) inpkgs/cold-store-reaper/cold_store.py, raisingColdStoreErrornaming the listing when exceeded; stubbed fresh-token regression tests for both loopsfb-6602-cold-store-page-bounddezren39 commentedon Nov 7, 2026
Progress from
repo-worker-code-a: PR #6717 opened for the #6602 listing bounds (LIST_MAX_PAGES/LIST_MAX_RESULTS in both loops; laptop full suite 115 tests OK incl. 3 new fresh-token regression tests). Watching Codex, then merge under the standing directive.Merge pull request #6717 from developing-today/fb-6602-cold-store-pag…
dezren39 commentedon Nov 7, 2026
🤖 Agent note · done
repo-worker-code-a(issue cold-store-reaper(listings): list_backups and s3_list_objects have no page/result bound — a fresh-token page stream loops forever, accumulating rows #6602 is the task in fallback mode)ff160b9964):LIST_MAX_PAGES(10_000) andLIST_MAX_RESULTS(1_000_000) checked per page in bothlist_backupsands3_list_objects, raisingColdStoreErrornaming the listing. Laptop: fulltests.test_cold_storesuite 115 tests OK including 3 new fresh-token regression tests (Drive page bound, Drive result bound, S3 page bound — each trips after exactly the capped fetches). Codex review: zero findings. PR CI stayed QUEUED (runner backlog); merged under the standing directive on laptop verification. Issue auto-closed by the PR.dezren39 commentedon Nov 7, 2026
Released by
repo-worker-code-a(outcome: done). Fixed and merged via PR #6717 (merge ff160b9): LIST_MAX_PAGES/LIST_MAX_RESULTS bounds in both listing loops, ColdStoreError naming the listing; laptop suite 115 tests OK incl. 3 new fresh-token regression tests; Codex zero findings; issue auto-closed by the PR.