Fix Dependabot CI gate: read checks authoritatively, don't misread API blips as "no CI"#12
Merged
Merged
Conversation
gated_merge.sh discovered the PR's checks via `gh pr checks` (the GraphQL status rollup) and mapped empty stdout to "no checks reported". Under a simultaneous multi-PR Dependabot batch the rollup can transiently return nothing, so a check that was attached and already green was misread as "this repo has no CI" -- and after the 300s APPEAR window the gate parked healthy patch/minor bumps with `needs-manual-review` (#11). Read checks authoritatively from the REST check-runs + commit-status APIs for the PR head SHA instead, and distinguish an API failure from a genuine empty result: a failed read now yields a "__ERR__" sentinel so the loops retry rather than concluding "no CI". The genuine-no-CI, red-CI, and exit-0-on-every-path guarantees are preserved. Adds test_gated_merge.sh (stubbed `gh`) covering: API blips then green -> merge, no CI -> human, red CI -> human, self-run exclusion; and a tooling-tests workflow running shellcheck + the tests on tooling changes. Closes #11 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
bbkrr
added a commit
that referenced
this pull request
Jul 15, 2026
The CI gate (gated_merge.sh, #12) now reads checks authoritatively from the REST Checks API (commits/{sha}/check-runs) and legacy commit statuses (commits/{sha}/status). The workflow's `permissions:` block did not grant `checks`/`statuses`, and with a permissions block present any unlisted scope defaults to `none`. On a PRIVATE repo those reads then 403, which the gate treats as an unreadable-checks error -- so it fails safe and never merges (observed on realrate/EBA#100: gate looped on `__ERR__` until timeout). Granting both read scopes lets the gate see the PR's checks and merge green patch/minor bumps as intended. Both are read-only. Refs #11. Co-authored-by: Claude Opus 4.8 <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 & why
The Dependabot auto-merge CI gate (
gated_merge.sh) was parking healthy patch/minor bumps for manual review because it could not tell "this repo has no CI" apart from "I couldn't read the checks right now."It discovered checks via
gh pr checks(the GraphQL status rollup) and mapped empty stdout → "no checks". When several Dependabot PRs open in the same instant, their auto-merge runs poll the API concurrently and the rollup can return nothing for the whole 300s "appear" window — even though the PR'stestscheck is attached and already green. The gate then fired its fail-safe and labeledneeds-manual-review.Confirmed in
realrate/EBA: PRs #99 (pmdarima, minor) and #100 (openpyxl, patch) opened in the same 10-second batch and both got "no CI checks registered within 300s", while the REST check-runs API shows theirtestscheck completingsuccessin 38s — green the whole time the gate saw nothing. Full diagnosis in #11.The fix
commits/{sha}/check-runs(+commits/{sha}/statusfor legacy statuses), excluding this workflow's own run by run-id. These return a well-formed body with a reliable count even while checks are pending, and a real non-zero exit on a genuine error.__ERR__sentinel so the loops keep polling instead of concluding "no CI". Only a successful empty result pastAPPEARstill routes to a human.Tests
test_gated_merge.shruns the real script against a stubbedghand pins:A new
tooling-tests.yamlworkflow runsshellcheck+ these tests on any change under.github/review-tooling/. Both areshellcheck-clean and green locally.Caveats / scope
numpy#101 failure from the same batch was a separate issue (AI verdict step raisedPermissionDeniedError) and is out of scope here.pull_request_targetworkflow still never checks out the bump.Closes #11. Hardens the #2244 CI gate (epic RealRate-Private#2229).
🤖 Generated with Claude Code