Skip to content

fix(queue): do not dissolve a batch whose checks do not exist yet - #742

Merged
matt82198 merged 1 commit into
mainfrom
fix/queue-batch-premature-dissolve
Aug 3, 2026
Merged

matt82198 merged 1 commit into
mainfrom
fix/queue-batch-premature-dissolve

Conversation

@matt82198

Copy link
Copy Markdown
Owner

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:

batch #741 (integrate/q-1785745378) dissolved (required check(s) absent from rollup: windows)

The batch PR was seconds old. GitHub creates check runs asynchronously after gh pr create, and the windows aggregator 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 reporting PASSED. 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:

  • Merging — absent must never read GREEN. Unchanged. required_checks_green still answers not_green for an incomplete rollup, so nothing new can merge. A test asserts a young incomplete batch is still never merged.
  • Dissolving — needs 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:

  1. no required context has actually concluded not-green,
  2. at least one required context is absent, and
  3. the batch PR is younger than 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 createdAt is 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, and createdAt is actually requested in PR_FIELDS (the check is inert otherwise). The two behavioural ones fail against the pre-fix module.

Stall series

🤖 Generated with Claude Code

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>
@matt82198 matt82198 added merge-queue Queued for the merge-queue advancer daemon merge-priority Jump the merge queue labels Aug 3, 2026
@matt82198
matt82198 merged commit cd9d8d7 into main Aug 3, 2026
12 checks passed
@matt82198
matt82198 deleted the fix/queue-batch-premature-dissolve branch August 3, 2026 08:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-priority Jump the merge queue merge-queue Queued for the merge-queue advancer daemon

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant