Context
packages/loopover-miner/lib/http-retry.js:51 retries only 5xx (if (response.status < 500 || attempt >= maxAttempts) return response;). ci-poller.js's githubGetJsonResponse and pr-disposition-poller.js's equivalent fetchPullRequest both throw immediately on any non-2xx, including 429/403, which fetchWithRetry already returned without retrying — and neither poller's attempt loop wraps this call in try/catch, so the throw aborts the whole poll on attempt 1 rather than consuming a backoff attempt. test/unit/miner-ci-poller-failure-modes.test.ts:23-27 pins this as known, deliberately-deferred behavior. A single transient GitHub rate-limit response aborts an entire poll cycle for an autonomous fleet making many API calls.
Requirements
- Extend
http-retry.js's retry predicate (or add a distinct policy) to retry on 429 and secondary-rate-limit 403 responses, respecting Retry-After/x-ratelimit-reset when present, still bounded by maxAttempts.
- Explicitly decide and document whether plain 403 (sometimes a permanent auth failure) should be retried the same way or excluded.
Deliverables
Test Coverage Requirements
99%+ Codecov patch coverage on every changed line and branch, plus a regression test that reproduces the exact failure mode described above and asserts it's fixed.
Expected Outcome
A transient GitHub rate-limit response is retried within the existing backoff budget instead of aborting the whole poll and, by extension, the miner run.
Links & Resources
packages/loopover-miner/lib/http-retry.js:51, packages/loopover-miner/lib/ci-poller.js:209-211, packages/loopover-miner/lib/pr-disposition-poller.js:151-153.
Context
packages/loopover-miner/lib/http-retry.js:51retries only 5xx (if (response.status < 500 || attempt >= maxAttempts) return response;).ci-poller.js'sgithubGetJsonResponseandpr-disposition-poller.js's equivalentfetchPullRequestboth throw immediately on any non-2xx, including 429/403, whichfetchWithRetryalready returned without retrying — and neither poller's attempt loop wraps this call in try/catch, so the throw aborts the whole poll on attempt 1 rather than consuming a backoff attempt.test/unit/miner-ci-poller-failure-modes.test.ts:23-27pins this as known, deliberately-deferred behavior. A single transient GitHub rate-limit response aborts an entire poll cycle for an autonomous fleet making many API calls.Requirements
http-retry.js's retry predicate (or add a distinct policy) to retry on 429 and secondary-rate-limit 403 responses, respectingRetry-After/x-ratelimit-resetwhen present, still bounded bymaxAttempts.Deliverables
http-retry.jsRetry-Afterheader honored when presentci-poller.jsandpr-disposition-poller.jsasserting a 429 is retried to successminer-ci-poller-failure-modes.test.tscomment/assertionTest Coverage Requirements
99%+ Codecov patch coverage on every changed line and branch, plus a regression test that reproduces the exact failure mode described above and asserts it's fixed.
Expected Outcome
A transient GitHub rate-limit response is retried within the existing backoff budget instead of aborting the whole poll and, by extension, the miner run.
Links & Resources
packages/loopover-miner/lib/http-retry.js:51,packages/loopover-miner/lib/ci-poller.js:209-211,packages/loopover-miner/lib/pr-disposition-poller.js:151-153.