fix(review): stop charging a regate-repair attempt before readiness is confirmed#5482
Conversation
…s confirmed regatePullRequest recorded a REGATE_REPAIR_ATTEMPT_EVENT_TYPE audit event as soon as the job cleared GitHub rate-limit admission, before ever calling reReviewStoredPullRequest -- so a PR legitimately still waiting on a missing branch-protection-required check (which prReadyForReview defers unconditionally and indefinitely by design, #3947) got charged a full repair attempt on every ~2-minute sweep tick even though nothing was actually wrong. The fixed 5-attempt cap exhausted in ~10 minutes, an order of magnitude shorter than realistic required-CI latency, firing a false "repair exhausted" alert for a review that was never broken. reReviewStoredPullRequest now returns whether it actually got past prReadyForReview (there is no early return anywhere after that point, so every exit before it returns false and the function's natural end returns true); regatePullRequest only records the repair attempt when that's true. A swallowed (non-retryable) exception past that point still counts as a real executed attempt, same as before -- only the clean "declined before ever reaching readiness" path is now excluded. Fixes GITTENSORY-1E
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #5482 +/- ##
=======================================
Coverage 94.73% 94.73%
=======================================
Files 561 561
Lines 44794 44800 +6
Branches 14667 14667
=======================================
+ Hits 42437 42443 +6
Misses 1622 1622
Partials 735 735
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
|
Warning 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 ⏸️ Gittensory review result - manual review recommendedReview updated: 2026-07-12 23:40:27 UTC
⏸️ Suggested Action - Manual Review Review summary Blockers
Nits — 5 non-blocking
Concerns raised — review before merging
📋 Copy for AI agents — paste into your coding agent
Review context
Contributor next steps
Signal definitions
[BETA] Chat with GittensoryAsk Gittensory a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://gittensory.aethereal.dev/docs/gittensory-commands 🟩 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.
|
… then throws Gittensory review flagged that regatePullRequest only recorded REGATE_REPAIR_ATTEMPT_EVENT_TYPE after reReviewStoredPullRequest returns, so a retryable error (GitHub rate limit / actuation-lock contention) surfacing from real post-readiness work skipped the charge entirely and could let a stuck repair reselect indefinitely. reReviewStoredPullRequest now exposes an onReachedReadiness callback that fires the instant its own readiness gate passes, before any further throwable work -- a side channel that survives a later throw, unlike the boolean return value. regatePullRequest uses it in a try/catch/finally: the retryable branch still rethrows for the queue's own retry, but the finally block charges the attempt first whenever readiness was genuinely reached, regardless of whether the call returned or threw. This also closes the symmetric gap the review's own nit raised: an error thrown BEFORE readiness (the callback never fires) correctly still does NOT charge the budget.
Summary
Sentry issue GITTENSORY-1E (
regate_repair_exhausted, 88 occurrences across many different PRs/head SHAs) is a false-positive alert, not a genuinely broken repair mechanism.regatePullRequestcharged a repair "attempt" the instant a job cleared GitHub rate-limit admission — before ever callingreReviewStoredPullRequest, and therefore before the review pipeline's own readiness gate (prReadyForReview) had any chance to decide whether there was a real opportunity to review at all.prReadyForReviewlegitimately, by design (#3947), defers unconditionally and indefinitely whenever a branch-protection-required status check hasn't posted yet — there's no finalize escape for that specific case (unlike the sibling "genuinely stuck, non-required pending" case, which does eventually finalize). So a perfectly healthy PR sitting on a queued-but-not-yet-run required check got charged a full repair attempt on every ~2-minute sweep tick, burning the fixed 5-attempt cap in ~10 minutes — an order of magnitude shorter than realistic CI queue latency — and firing a "repair exhausted" alert for a review that was never actually broken.Confirmed concretely for the cited example:
main's branch protection requires thevalidatestatus check, and PR #5429's cited head SHA never got avalidatecheck-run at all during its ~33-minute life (only Workers-Builds/CodeQL/Security-Scan/Analyze ran) before being superseded by a force-push — every one of its 5 repair "attempts" was doomed from the start by design, not by a real failure.Changes
reReviewStoredPullRequest(src/queue/processors.ts) now returns whether it actually got pastprReadyForReview— there is no early return anywhere in the function after that point, so every exit before it returnsfalse, and the function's natural end (once readiness passed) returnstrue.regatePullRequestonly records theREGATE_REPAIR_ATTEMPT_EVENT_TYPEaudit event when that'strue— moved from unconditionally-before-the-call to conditionally-after-it. A swallowed (non-retryable) exception past the readiness check still counts as a real executed attempt, same as before this fix; only the clean "declined before ever reaching readiness" path is now excluded.Test plan
npm run typecheck— cleannpm run test:ci(full local gate, unsharded coverage) — green#orb-retry-stormregression tests (which exercise a PR that DOES reach readiness) still pass unchangedFixes GITTENSORY-1E