fix(scheduler): hold pre-review branch updates while current-head checks are in flight - #1937
Merged
Merged
Conversation
…cks are in flight A scheduler run that executes after a 2h+ queue wait finds its scanned PR behind main and merges main into the head before any review is dispatched (inspect_pr, pre-review path). That push cancels every queued check on the old head (22/28 on #1926, 21/30 on #1484) and requeues the PR at the back, so under a saturated queue no head ever finishes its checks: 76 of the 77 PRs merged since 2026-09-04 had 0/12 required contexts satisfied at merge. has_in_flight_check_runs() reuses latest_check_runs()/running_check_state(); the pre-review path now decides "wait" while any newest current-head check run is still queued or running. No age cap on purpose: a cap would restart the loop. The post-approval update path is unchanged (main is strict=true). CLAUDE.md described only the post-approval update; it now names both paths. Refs #1935 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Warning Review limit reachedNext included review available in 7 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (4)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
seonghobae
deleted the
fix/scheduler-hold-update-while-checks-in-flight
branch
September 5, 2026 14:17
seonghobae
added a commit
that referenced
this pull request
Sep 5, 2026
…trator-integration Conflict: tests/test_pr_review_merge_scheduler.py -- both sides appended tests at end of file (this branch: two SchedulerAdmissionGate reconcile cases; main: the #1935 pre-review update hold). Kept both. Gate after merge: 2930 passed, coverage 100%, interrogate 100%. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This was referenced Sep 5, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the self-cancelling loop measured in #1935.
What changes
scripts/ci/pr_review_merge_scheduler_core.py: newhas_in_flight_check_runs(pr)(one expression over the existinglatest_check_runs/running_check_state), and one guard in the pre-review branch ofinspect_pr: when the PR is behind, unreviewed, and any newest current-head check run is stillQUEUED/IN_PROGRESS/PENDING/…, the decision iswaitinstead ofupdate_branch. The reason string keeps the existing prefix so log consumers that match onbranch is outdated before review dispatchstill match.tests/test_pr_review_merge_scheduler.py: contract test with the positive case (queued + in-progress + one success →wait, both reason fragments), the negative control (all terminal →update_branch, prefix unchanged, hold fragment absent), and the empty-rollup case.CLAUDE.md: the governance paragraph said the scheduler updates a branch only after approval; it now describes both update paths (post-approval, and pre-review when no check is in flight).CHANGELOG.mdentry.Why this is the smallest root-cause change
Under the current queue a scheduler run executes 2h+ after it was created, picks one behind PR from its scan (its own PR or another one — a
codex/originweave-mv3-ownerrun updated #1857), and mergesmaininto that head before dispatching any review (core.py:4774-4792,UPDATE_BRANCHEStrue forpull_request_targetatpr-review-merge-scheduler.yml:139). Withmainmoving every ~28 minutes almost every completing run finds a behind PR, so the scheduler's completion rate becomes the PR cancellation rate. Each push cancels every queued check on the old head — 22/28 on #1926, 21/30 on #1484 with 8 successes orphaned — and requeues the PR at the back. Reconstructed atmerged_at, 76 of the 77 PRs merged here since 2026-09-04 had 0/12 required contexts satisfied.The guard removes the pre-review self-cancellation without touching the post-approval update, which
main'srequired_status_checks.strict=truestill requires. Alternatives considered: droppingpull_request_targetfromUPDATE_BRANCHES(only makes theschedule/pushsweeps do the same thing less often); an age cap on the hold (reintroduces the loop); dispatching the review on the behind head (wasted understrict=true, since the post-approval update changes the SHA and invalidates a same-head approval).Not claimed
mainmoves faster than a head's checks can complete — it stops the scheduler from being the thing that resets them, and lets each head accumulate evidence. Post-approval updates understrict=trueare a separate, bounded cost.base_shadrift), or codeql-scan-dispatch.yml has never run: env: cannot hold the client_payload matrix array (0 success / 136 failures since #1776) #1925 (CodeQL dispatch).CheckRunnodes are considered (latest_check_runsfilters on__typename == "CheckRun"); a legacy commitStatusContextthat is still pending does not hold the update. All 12 required contexts on this repository'smainare Actions check runs, so nothing here depends on it — a docstring line for the helper is a follow-up, kept out of this head so the merge procedure does not restart.needs:are created only when their upstream completes, so for a few seconds between an upstream job finishing and its dependants appearing every existing check run is terminal and the hold does not apply. With one scheduler run per hour per PR that window is negligible, and landing in it reproduces today's behaviour rather than anything worse.Verification
Full gate on this head with
GITHUB_ACTIONS=true(the env gate atcore.py:4172is what makes these tests run the same code CI runs): 2893 passed / 1 skipped / 21 subtests,coverage report --fail-under=100→ 100%,interrogate→ 100%; negative control: the new test fails (1 failed) withorigin/main'spr_review_merge_scheduler_core.pyswapped in.Chicken-and-egg note for the merger: this PR's own required contexts are produced by the queue this change unblocks; its head cannot self-validate. Same category as #1932 and #1926.
🤖 Generated with Claude Code