fix(queue): do not dissolve a batch whose checks do not exist yet - #742
Merged
Merged
Conversation
The advancer built and pushed batch #741 correctly, then dissolved it on the same pass with "required check(s) absent from rollup: windows" -- the batch PR was seconds old and GitHub had not created the check runs yet (the `windows` aggregator only appears once its shards exist). Dissolution evicts every member, the next pass rebuilds the same batch, and it dissolves again: the rebatch loop behind #727/#729/#730/#731/#732/#733/#736/#737, which merged nothing while every pass reported PASSED. The root confusion is that "absent" was treated as identical to "red". Absent must never read as GREEN -- that invariant is untouched, and required_checks_green still answers not_green for an incomplete rollup, so nothing new can merge. But DISSOLVING requires positive evidence of failure: a required context that is present and concluded not-green. batch_checks_not_yet_created() answers True only when all of: - no required context has actually concluded not-green, - at least one required context is absent, and - the batch PR is younger than BATCH_CHECK_GRACE_S (30 min). Any concluded failure dissolves immediately regardless of age, an absence past the window dissolves as before, and an unreadable createdAt is NOT treated as young -- so the window is a delay, never an amnesty. Tests: 128 in test_merge_queue.py (6 new), including that a young incomplete batch is still never merged. The two behavioural ones fail against the pre-fix module. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Aug 3, 2026
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.
Fourth and final cause of the merge-queue stall. With #740 merged the advancer now builds and pushes an integration branch correctly — observed live: batch #741 (
integrate/q-1785745378, members #719 + #725) was created successfully. It was then dissolved on the very same pass:The batch PR was seconds old. GitHub creates check runs asynchronously after
gh pr create, and thewindowsaggregator only appears once its shards exist — so the rollup was incomplete through no fault of the batch. Dissolution evicts every member (queue-rejected), the next pass rebuilds the same batch, and it dissolves again. That is the loop behind #727 / #729 / #730 / #731 / #732 / #733 / #736 / #737 — eight batches, nothing merged, every pass reportingPASSED. The exception ledger shows the same signature on the originals:all members individually green but #736 was red: required check(s) absent from rollup: windows.The confusion
"Absent" was treated as identical to "red". Those need to differ by direction:
required_checks_greenstill answersnot_greenfor an incomplete rollup, so nothing new can merge. A test asserts a young incomplete batch is still never merged.batch_checks_not_yet_created()answers True only when all of:BATCH_CHECK_GRACE_S(30 min).A concluded FAILURE dissolves immediately regardless of age; an absence past the window dissolves exactly as before; an unreadable
createdAtis not treated as young. The window is a delay, never an amnesty.Tests
128 in
tests/test_merge_queue.py(6 new): young-waits, old-still-dissolves, young-with-real-failure-still-dissolves, unknown-timestamp-dissolves, grace-never-merges, andcreatedAtis actually requested inPR_FIELDS(the check is inert otherwise). The two behavioural ones fail against the pre-fix module.Stall series
queue-rejecteduntil guard: import_resolution_check learns the sanctioned sys.path idiom (60% FP -> 0, zero coverage loss) #724 lands (wires a guard whose checker flagsmerge_queue.py:68-69)🤖 Generated with Claude Code