ci: paginate the merge-group authority check, and never call a short read absent - #822
Merged
Merged
Conversation
…read absent #820 was ejected from the merge queue with: pull request #820 at 8f0b523...: no authenticate-console-authority run on the queued head It had one. The job ran on that exact SHA and concluded success. The gate could not see it because `repos/{repo}/commits/{sha}/check-runs` returns 30 check runs per page by default and the call passed neither `--paginate` nor `per_page`. That pull request had 32, so the authority check sorted onto page two and vanished. This is not a #820 problem. Any pull request with more than 30 check runs can be ejected, and whether it is depends on where the check happens to sort -- so the gate gets less reliable with every job added to CI. The merge-group half of `authenticate-console-authority` is exactly the gate that must not produce false negatives: its verdict evicts work that already passed. Two changes, because the pagination bug was only half of it: 1. Fetch with `--paginate` and an explicit `per_page=100`. 2. Prove the read was complete rather than assume it. The gate now also reads the API's own `total_count` and refuses when it holds fewer runs than that, with a DIFFERENT message: read only 30 of 32 check runs on the queued head; the list is incomplete, so absence of a run cannot be concluded A filter over a short list and a filter over a list that genuinely lacks the run return the same empty set, and reporting both as "no such run" is what turned a missing PAGE into a missing GATE. Those two demand opposite responses -- retry versus refuse -- so they must not share a message. Kept deliberately permissive where uncertainty is harmless: an unreadable `total_count` does not manufacture a failure, and MORE runs than the reported total is not treated as short (check runs can appear between the two calls). Mutation-proven: removing the short-read guard turns "an incomplete read is not reported as a missing run" red; restoring it passes. 14 tests pass (5 pre-existing, 9 new); 12 gates swept, 0 failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
What happened
#820 was ejected from the merge queue with:
It had one. The job ran on that exact SHA and concluded success:
Root cause
repos/{repo}/commits/{sha}/check-runsreturns 30 check runs per page by default. The call passed neither--paginatenorper_page. #820 had 32 — so the authority check sorted onto page two and disappeared.Reproducible directly:
Why this matters beyond #820
Any PR with >30 check runs can be ejected, and whether it is depends on where the check happens to sort. The gate gets less reliable with every job added to CI. This is the gate whose verdict evicts work that already passed — it must not produce false negatives.
The fix — two parts
Paginate:
--paginatewith an explicitper_page=100.Prove completeness rather than assume it. The gate now also reads the API's own
total_countand refuses a short read with a different message:A filter over a short list and a filter over a list that genuinely lacks the run return the same empty set. Reporting both as "no such run" is what turned a missing page into a missing gate. They demand opposite responses — retry vs. refuse — so they must not share a message.
Deliberately permissive where uncertainty is harmless: an unreadable
total_countdoes not manufacture a failure, and more runs than the reported total is not treated as short (check runs can appear between the two calls).Verification
🤖 Generated with Claude Code