⚠️ Definition of Done: this issue must be completed in full, in a single PR. Do not split this
work across multiple PRs, and do not defer any Deliverable below to a follow-up issue. A PR that
satisfies only some of the Deliverables, stubs a required test, or leaves a checkbox
partially-done does NOT resolve this issue and will be closed.
Context
src/github/backfill.ts:4406's syncLabels (for (let page = 1; ; page += 1)) and :1790/:1845's supplementOpenIssuesFromGraphQl/supplementOpenPullRequestsFromGraphQl (both for (;;)) have no bound. Every other pagination loop in this file is explicitly bounded (PR_DETAIL_MAX_PAGES = 10, RECONCILE_OPEN_PRS_MAX_PAGES = 10, REVIEW_THREAD_MAX_PAGES = 10, PR_DETAIL_GRAPHQL_MAX_PAGES = 10), with comments stating the bound exists "so a pathological repo can't turn one webhook into an unbounded fetch loop." These three functions -- used to correct REST undercounts, i.e. triggered exactly for the largest/worst-behaved repos -- have neither a limit parameter nor a MAX_PAGES constant; termination depends entirely on GitHub eventually returning hasNextPage: false.
Requirements
Add a MAX_PAGES bound to all three loops, consistent with the file's existing 10-page convention, converging on a capped-style status/warning the same way githubPaged already does.
Deliverables
All of the above Deliverables are required in the same PR unless the deliverable text itself states otherwise.
Test Coverage Requirements
src/** -- 99%+ patch coverage, branch-counted, on all three new bounds.
Expected Outcome
A pathological repo triggering syncLabels or either GraphQL supplement function can no longer turn one call into an unbounded fetch loop, matching every other pagination loop in the same file.
Links & Resources
src/github/backfill.ts:1790,1845,4406
Context
src/github/backfill.ts:4406'ssyncLabels(for (let page = 1; ; page += 1)) and:1790/:1845'ssupplementOpenIssuesFromGraphQl/supplementOpenPullRequestsFromGraphQl(bothfor (;;)) have no bound. Every other pagination loop in this file is explicitly bounded (PR_DETAIL_MAX_PAGES = 10,RECONCILE_OPEN_PRS_MAX_PAGES = 10,REVIEW_THREAD_MAX_PAGES = 10,PR_DETAIL_GRAPHQL_MAX_PAGES = 10), with comments stating the bound exists "so a pathological repo can't turn one webhook into an unbounded fetch loop." These three functions -- used to correct REST undercounts, i.e. triggered exactly for the largest/worst-behaved repos -- have neither alimitparameter nor aMAX_PAGESconstant; termination depends entirely on GitHub eventually returninghasNextPage: false.Requirements
Add a
MAX_PAGESbound to all three loops, consistent with the file's existing 10-page convention, converging on acapped-style status/warning the same waygithubPagedalready does.Deliverables
syncLabelshas aMAX_PAGESbound matching the file's existing 10-page conventionsupplementOpenIssuesFromGraphQlhas the same boundsupplementOpenPullRequestsFromGraphQlhas the same boundhasNextPage: false) and surfaces acappedsignalAll of the above Deliverables are required in the same PR unless the deliverable text itself states otherwise.
Test Coverage Requirements
src/**-- 99%+ patch coverage, branch-counted, on all three new bounds.Expected Outcome
A pathological repo triggering
syncLabelsor either GraphQL supplement function can no longer turn one call into an unbounded fetch loop, matching every other pagination loop in the same file.Links & Resources
src/github/backfill.ts:1790,1845,4406