Repository navigation
fix(ci): let the DCO gate be republished instead of only refreshed in place - #7408
Conversation
|
/ok to test |
|
This PR has been automatically converted to draft because all PRs must start as drafts. When you are ready for review, click Ready for Review to begin the review process. This will:
See the contribution guide for more details. |
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
a83af2a to
65525be
Compare
65525be to
4ef0016
Compare
A check run created through the Checks API is pinned by GitHub to the first check suite for its head SHA. For a fork pull request that suite is keyed to the contributor's branch name, which does not exist in this repository, and when a merge box fails to bind it the required context reports "Expected — waiting for status to be reported" indefinitely. That state is unrepairable through the API: a check run cannot move between suites, so neither updating the existing gate nor publishing a replacement clears it. Both were tried against four stuck pull requests and changed nothing. A commit status is not an answer either, because the required context is pinned to app 15368 and a status published by anything else is not counted. Report the gate the way `Nemo_CICD_Test` and `multi-approval-bot-summary` report theirs instead — as a job on the `pull-request/<n>` mirror push, whose check run lands in a suite keyed to a real branch of this repository. The job only reads the trusted DCO App verdict, waits for it when it has not landed yet, and fails closed if it never does. Delete the Checks API publisher and its reconcile sweep rather than leaving them alongside. Two producers of one context race: branch protection reads whichever check run is newer, so an API-published gate landing last would put the unbindable run back in front of the merge box and reintroduce the bug. Dropping the sweep also removes ~950 API requests every six hours. `dco-gate-merge-group.yml` still owns the gate for merge-queue refs, which this job does not run for. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: oliver könig <okoenig@nvidia.com>
4ef0016 to
50d7e34
Compare
|
🔄 Merge queue validation started! You can track the progress here: https://github.com/NVIDIA/Megatron-LM/actions/runs/35217238977 |
|
🔄 Merge queue validation started! You can track the progress here: https://github.com/NVIDIA/Megatron-LM/actions/runs/35217283399 |
|
🔄 Merge queue validation started! You can track the progress here: https://github.com/NVIDIA/Megatron-LM/actions/runs/35217310563 |
Background / motivation
mergeable_state: blockedwith the merge box reporting the required
DCO gateas "Expected — waiting for statusto be reported", while a green
DCO gatecheck run exists on the head SHA andgh pr checks <n> --requiredlists it aspass.verdict the DCO App has since revised could never be corrected:
reconcile_pull_requestreturned
presentfor any head that already had a gate, whatever it said.What changed
a missing one — new
refreshedoutcome.dco-gate.ymltakes a pull-request number instead of only a SHA, so a manual refreshdoes not need a head-SHA lookup.
publish_gategainsrecreate, which POSTs a replacement check run rather than PATCHing.Details
.github/scripts/dco_gate.pycreate_gate— the shared POST path;publish_gate(..., recreate=True)routes to it.head_sha_of_pull_request+_requested_sha— resolveDCO_GATE_PULL_REQUESTto thecurrent head, fall back to
DCO_GATE_SHA, fail loudly on a dispatch with neither.gate_conclusion— extracted fromgate_payloadso the sweep can compare a publishedgate against the current verdict.
.github/workflows/dco-gate.yml—pull_request/sha/recreateinputs, pluspull-requests: readfor the head lookup.Read budget — why a passing gate is not re-verified
The repo has 954 open pull requests and the sweep already spends ~1 request per PR against
the hourly
GITHUB_TOKENbudget (the 12:37 UTC run took 5m46s). Re-reading every verdict woulddouble that and push the sweep over the limit. So the sweep re-reads a verdict only behind a
gate that is not already passing — the class that actually blocks a PR. A verdict that flips
after a gate has passed stays with the event-driven publisher, which fires on that flip.
test_reconcile_reads_a_passing_gate_exactly_oncepins the invariant.Negative result: recreating the check run does not clear a stuck merge box
Measured across all 954 open PRs, exactly 4 were approved with all three required contexts
green and still
BLOCKED: #7354, #7350, #7347, #7329.A one-off Actions run published a brand-new
DCO gatecheck run for each(
104905317481,104905333508,104905352882,104905366800). All four stayedblocked,and #7329 still rendered "Expected — waiting for status" afterwards. Closing and reopening
#7329 did not clear it either.
Every API-visible attribute of a stuck PR matches a
CLEANone:statusCheckRollup.stateSUCCESSSUCCESSreviewDecisionAPPROVEDAPPROVED1536815368skippedsuccess/skippedmainmainRuled out: check-run identity, check-run or merge-box staleness (a
CLEANPR untouched since2025 exists), check-suite shape, base branch, labels, auto-merge, unresolved threads, required
deployments, conversation resolution, linear history, commit signatures.
Durable fix worth considering separately
Nemo_CICD_Testandmulti-approval-bot-summaryare never stuck, and they differ from the gatein exactly one way: they are real Actions jobs in the
pull-request/<n>mirror suite, whileDCO gateis an API-created check run filed into the fork-branch suite. Publishing the gateas a job on the mirror push — polling briefly for the DCO App verdict — would put it on the same
delivery path as the two contexts that never fail to bind. That is a larger change and is not
attempted here.
Tested
python3 .github/scripts/test_dco_gate.py→ 23 passed (was 20; 3 new, 2 adjusted).ruff check .github/scripts/dco_gate.py .github/scripts/test_dco_gate.py→ clean.104581997123) changed onlycompleted_at; POST of fourreplacement gates changed the IDs and nothing else. Both recorded above.
🤖 Generated with Claude Code