fix(github): classify backfill permission 403s as errors, not rate limits#1747
Conversation
…mits (JSONbored#1746) GitHubApiError flagged every 403/429 as rate-limited, so a genuine permission 403 — "Resource not accessible by integration", a missing scope, branch protection — with x-ratelimit-remaining still above 0 and no Retry-After was recorded as a rate limit: backfillRepositorySegment set the segment waiting_rate_limit and backed off, and the metadata path set repo status rate_limited, instead of surfacing the error. Mirror app.ts's isRateLimitedResponse with a shared isRateLimitedGitHubFailure predicate (403/429 plus Retry-After / exhausted x-ratelimit-remaining / secondary-limit body), threading the retry-after header and response body into GitHubApiError. Covered by predicate unit tests and a backfill regression test. Co-authored-by: Cursor <[email protected]>
|
Warning 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 ⏸️ Gittensory review result - manual review recommendedReview updated: 2026-06-29 17:36:14 UTC
⏸️ Suggested Action - Manual Review
Review summary Nits — 6 non-blocking
Review context
Contributor next steps
Signal definitions
🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1747 +/- ##
=======================================
Coverage 95.59% 95.59%
=======================================
Files 204 204
Lines 22316 22320 +4
Branches 8067 8069 +2
=======================================
+ Hits 21332 21336 +4
Misses 408 408
Partials 576 576
🚀 New features to boost your workflow:
|
Summary
Fixes #1746.
GitHubApiErrorinsrc/github/backfill.tsflagged every failure as rate-limited withstatusCode === 403 || statusCode === 429 || remainingHeader === "0", so a genuine permission403—Resource not accessible by integration, a missing scope, or branch protection — withx-ratelimit-remainingstill above0and noRetry-Afterwas misclassified as a rate limit. That pushed it into the rate-limit branches:backfillRepositorySegment(:1246) set the segmentwaiting_rate_limitand applied backoff, and the metadata path (:1692) set repo statusrate_limited/dataQuality.rateLimited: true, instead of surfacing the permission error to the operator.src/github/app.tsalready solved this for the live-review path withisRateLimitedResponse(a 403/429 is a rate limit only with aRetry-After, an exhaustedx-ratelimit-remaining, or a secondary-limit/abuse body), but the backfill REST/GraphQL path uses rawfetchand its own error class and was never aligned. This adds a sharedisRateLimitedGitHubFailurepredicate mirroring that logic and threads theretry-afterheader and response body intoGitHubApiError.Scope
type(scope): short summaryConventional Commit format, for examplefix(api): restore profile access checks.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Validation
git diff --checknpm run actionlintnpm run typechecknpm run test:coveragelocally;codecov/patchrequires ≥97% coverage of the lines AND branches you changed (aim for 98%+ on your diff so CI variance does not fail near the threshold). Global coverage is a non-blocking trend with a loose 90% backstop, not the gate.npm run test:workersnpm run build:mcpnpm run test:mcp-packnpm run ui:openapi:checknpm run ui:lintnpm run ui:typechecknpm run ui:buildnpm audit --audit-level=moderateRan the full
npm run test:ci(green) plusnpm audit --audit-level=moderate(0 vulnerabilities). Added unit tests forisRateLimitedGitHubFailure(permission 403, exhausted-remaining, Retry-After on 403 and 429, secondary-limit body, bare 429, non-403/429) and a backfill regression test asserting a permission 403 yields anerrorsegment withdataQuality.rateLimited: false, notrate_limited.Safety
UI Evidencesection below with screenshots.Backend-only error-classification change; no auth/CORS/session/OpenAPI/UI surface is touched (
ui:openapi:checkpasses), so no UI evidence applies. The new behavior is exercised by the negative-path predicate tests and the backfill regression test.Notes
app.ts'sisRateLimitedResponserather than a refactor ofapp.ts, keeping this PR scoped to the backfill error path.429now requires a rate-limit signal (matchingisRateLimitedResponse); GitHub 429s carryRetry-After, so live behavior is unchanged for real secondary limits.