Repository navigation
ci: fail held merge-queue pull requests before the lane legs run #10747
Copy link
Copy link
Closed
Labels
priority: mediumReal value, no hard deadline; normal backlog flow.Real value, no hard deadline; normal backlog flow.status: confirmedA maintainer confirmed the item is real and in scope; ready to be worked.A maintainer confirmed the item is real and in scope; ready to be worked.work-class: scopedA briefed fix or small feature; blast radius bounded by the brief, tests exist.A briefed fix or small feature; blast radius bounded by the brief, tests exist.
Description
Problem
About 20-26 merge-group runs a day fail on a designed hold (hold label, body or member hold, a pr-unblock stop on the head, pr-verify not passed, needs-human, kill switch, hold path). ci-status checks these holds only after every lane leg in the merge_group run has finished, which is about 32 job-minutes per run. The queue then ejects the pull request.
#10737 stops pr-merge's enable-auto-merge from queuing a head a pr-unblock lane stopped. It moves that rule into merge-holds.mjs as unblockStops and readStatuses. Two parts were left for after it merges.
Remaining
- ci-status calls the shared rule. The
Fail a head a pr-unblock lane stoppedstep inpr-require-checks.ymlstill applies its own jq and awk rule. ci-status loadsmerge-holds.mjsfrom the base commit ($BASE_CONFIG), so it can importunblockStopsonly once fix(pr-pipeline): end designed stops cleanly and keep held pull requests out of the merge queue #10737 is on main. Switch the step toholds_js unblockStopsand updatescripts/ci-hold-pr-unblock-status.test.shto match. - Check holds early in merge_group runs. Run the hold checks that cost no lane work (hold labels, pr-unblock stops, kill switch) in a merge_group-only step of
select-tests, which every legneeds. A held pull request then fails in seconds and its legs skip. ci-status keeps its own hold steps, so the final aggregate still fails on the hold. To avoid a second copy of each rule, both places call one script or composite action. Two things to check first:select-testsruns pull request code withcontents: readandpull-requests: readonly, so confirm a commit-status read works with those permissions. And make sure the legs skipping does not turn a skip into a pass in theCheck each skipped lane against scopestep.
Done when
- A merge_group run for a held pull request fails before any lane leg starts.
- Every state that fails ci-status today still fails it.
- The pr-unblock rule is stated once, in
merge-holds.mjs.
Related
Refs: #10737
Metadata
Metadata
Assignees
Labels
priority: mediumReal value, no hard deadline; normal backlog flow.Real value, no hard deadline; normal backlog flow.status: confirmedA maintainer confirmed the item is real and in scope; ready to be worked.A maintainer confirmed the item is real and in scope; ready to be worked.work-class: scopedA briefed fix or small feature; blast radius bounded by the brief, tests exist.A briefed fix or small feature; blast radius bounded by the brief, tests exist.
Type
Fields
No fields configured for Task.
Activity
github-actions commentedon Oct 28, 2026
The triage sweep dispatched intake triage for this issue (attempt 1 of 2).
github-actions commentedon Oct 28, 2026
Proposed work class: work-class: scoped
Basis: automated intake triage; the lanes App applied this class.
Size: Small
Complexity: Medium
Uncertainty: Knowable
Flags: none
Blocked by: #10737
I read this as two changes to pr-require-checks.yml. First, the ci-status pr-unblock step calls the shared
unblockStopsrule in merge-holds.mjs. Second, a merge_group-only select-tests step runs the no-lane-cost hold checks, so a held pull request fails before any lane leg starts. Both would call one shared script or composite action.Item 1 waits on #10737 merging, since
unblockStopsis not on main yet. To confirm first: whether a commit-status read works with select-tests' current permissions (or needsstatuses: read), and that skipped legs cannot turn into a pass inCheck each skipped lane against scope.No duplicate found among the open issues.
Automated triage, applied by the lanes App.
melodic-automation-lanes commentedon Oct 28, 2026
Not admitted to the issue lane: a criterion names .github/workflows/pr-require-checks.yml, .github/workflows, which the issue lane cannot push (patch-protected-path); a builder session takes it. Admission takes the issue once each of those is met, when intake triages it again (
.github/actions/resolve-config/admission-rules.json).melodic-automation-lanes commentedon Oct 28, 2026
The latest triage verdict holds nothing: admission moved the issue to
status: confirmed; its comment says why.melodic-automation-lanes commentedon Oct 28, 2026
Refinement. A read-only run explored this repository, searched its issues and pull requests, and read the allowed docs to draft what follows. On an issue a listed human filed, it counts as the issue's spec once posted, while unedited; it is still model text, so check it.
Intended outcome: ci-status's pr-unblock step calls the shared unblockStops rule in merge-holds.mjs, and a merge_group-only step in select-tests runs the no-lane-cost hold checks so a held pull request fails before any lane leg starts.
Acceptance criteria
Fail a head a pr-unblock lane stoppedin .github/workflows/pr-require-checks.yml callsholds_js unblockStopsand holds no jq or awk copy of the pr-unblock rule.statuses: readif the read fails without it), with no write scope, and a comment says why.Check each skipped lane against scopestep still fails when legs skip because select-tests failed on a hold; a test or workflow-lint check pins this.Dependencies
unblockStopsin merge-holds.mjs yet, and ci-status loads merge-holds.mjs from the base commit, so item 1 cannot land until then. Item 2 can reuse that rule only after it too.Related work
Sources read
Fail a head a pr-unblock lane stoppedstep still uses its own jq and awk rule over commit statuses.holds_jshelper exists, but a grep of .base finds nounblockStopsanywhere.contents: readandpull-requests: readonly, so a commit-status read likely needsstatuses: readadded.statuses: write, so a read-only grant fits that rule.Check each skipped lane against scopestep is where a skip must not become a pass.Automated refinement by the lanes App. Intake triages the issue again with it.
fix(ci): read the queue-hold rules without an unfed continue-on-error…
fix(ci): keep only the pull, labels and events in ci-status's read cache
kyle-sexton commentedon Oct 29, 2026
Done on main (verified 2cc3903). (1) ci-status's 'Fail a head a pr-unblock lane stopped' step imports the base commit's merge-holds.mjs unblockStops (pr-require-checks.yml ~:5357), so the rule is stated once. (2) select-tests runs a merge_group-only step that reads the base commit's queueHolds (labelHolds + unblockStops + switchHold) and fails a held group before the lane legs (pr-require-checks.yml:346-396; #10838, #10876). ci-status keeps its own hold steps, so every state that failed it still does.