Repository navigation
ci: cancel-in-progress voids the base-branch suite — no post-merge verification on Dev_new_gui #13432
Description
The base branch is essentially never verified
ci.yml uses:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: trueFor a pull request that is correct — a new push should cancel the superseded run. For a push to Dev_new_gui it means each merge cancels the previous merge's verification. Because merges arrive faster than the suite finishes, most merges are never verified at all.
Measured
- 23 of the last 38 completed
ci.ymlruns onDev_new_guiwerecancelled(61%). The other 15 werefailure. Not one wassuccess. - 17 merges to
Dev_new_guiin three hours — one every ~10.6 minutes. - The sharded suite takes ~9 minutes.
A ~10.6-minute merge interval against a ~9-minute run means cancellation is the normal outcome, not the exception. At one point eight consecutive runs were cancelled.
Why this blocks #13162
#13162 asks for python-suite to become a required status check. That cannot safely happen while this holds: a required check that the next merge cancels would leave PRs permanently un-mergeable, blocking the repo rather than protecting it.
Sharding (#10691) fixed the duration problem #13162 opened with — the suite went from ~51 minutes to ~9. It did not touch the cancellation problem, and cancellation is now the binding constraint. This should land before the required-check change, not after.
It also has a quieter cost today: nobody can tell whether Dev_new_gui is green, because the measurement is destroyed before it completes. Re-measuring the #13162 backlog has repeatedly required hunting for a run that happened to survive.
Proposed fix
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}PR runs keep cancelling on supersede; base-branch runs are allowed to finish.
The trade-off, stated honestly
This is not free, which is why it is filed rather than just applied:
- Base runs would queue instead of cancel. At ~17 merges per 3 hours that is ~17 additional runs to completion in that window.
- The
python-suiteshards run onubuntu-latest, so they cost the self-hosted pool nothing. Butci.ymlalso has jobs on the[self-hosted, Linux, X64]singleton, and those would accumulate. The runner was offline earlier today and a ~60-run backlog built up, so headroom there is not generous.
Options if the straight fix is too costly:
- Separate concurrency group for the base branch — let base runs serialize among themselves without cancelling, while PR runs keep the current behaviour.
- Restrict the change to the
python-shardjob only (job-levelconcurrency), so the expensive self-hosted jobs keep cancelling and only the ubuntu-latest suite is preserved. This is the narrowest change that makes the suite measurable.
Option 2 is probably the best value: it makes python-suite trustworthy as a gate without adding any load to the singleton pool.
Acceptance criteria
- A merge to
Dev_new_guino longer cancels the previous merge'spython-suiterun - PR runs still cancel on supersede
- Self-hosted queue depth does not materially worsen (measure before/after)
- A comment in
ci.ymlrecords why base and PR differ, socancel-in-progress: trueis not restored wholesale later
Provenance
Found while measuring the remaining #13162 backlog: eight consecutive base runs were cancelled, making the measurement impossible without hunting for a surviving run. Related: #13162, #10691.
Activity
mrveiss commentedon Aug 4, 2026
Correction: this does not block the #13162 required-check change
I claimed in the description that making
python-suiterequired is unsafe while this holds. That was wrong, and the reasoning was wrong in a specific way worth recording.Required status checks are evaluated on the pull request head, not on the base branch. The concurrency group is
${{ github.workflow }}-${{ github.ref }}, and a PR's ref is its own — so another session merging toDev_new_guidoes not touch a PR's run. Checked against the last 12pull_requestruns: they completesuccess/failure. The only cancellations are repeated pushes to the same PR (issue-13398shows three, all supersedes), which is exactly whatcancel-in-progressis for.So
python-suitecould become a required check today without this being fixed. The remaining blocker for #13162 is simply that the suite is not yet green.What this issue actually costs — still worth fixing
The problem is real, just narrower than I described:
Dev_new_guiis green. 23 of the last 38 completed base runs were cancelled and none succeeded.That is a monitoring and post-merge-verification gap, not a merge-gating one.
A correction to the proposed fix, too
I suggested job-level
concurrencyonpython-shardas the narrowest option. That does not work. Workflow-levelcancel-in-progresscancels the entire run including its jobs; a job-level concurrency group cannot override that. The options are actually:cancel-in-progress: ${{ github.event_name == 'pull_request' }}— base runs stop cancelling, but with a shared group they queue behind each other.ci.yml, which would accumulate.python-shardinto its own workflow file with its own concurrency policy — the only option that isolates the ubuntu-latest suite from the self-hosted jobs entirely.Option 3 is the one that actually achieves "the base suite always produces a verdict" without adding self-hosted load. It is a larger change than a one-line edit.
Separate throughput note for #13162
Branch protection has
strict: true. Ifpython-suitebecomes required, every merge toDev_new_guiforces every open PR to update and re-run the full suite. At ~17 merges per three hours that is substantial additional CI. Worth sizing before flipping the switch — it is a separate concern from this issue, but it lands at the same moment.[-]ci: cancel-in-progress voids the base-branch suite — 23 of the last 38 runs cancelled, blocking the #13162 required-check change[/-][+]ci: cancel-in-progress voids the base-branch suite — no post-merge verification on Dev_new_gui[/+]ci: let a push to the base branch finish instead of cancelling it (#1…
github-actions commentedon Aug 4, 2026
PR #13541 (merged to
Dev_new_gui) references this issue with a close keyword.If this issue is fully resolved, close it manually. If work remains, no action is needed.
mrveiss commentedon Aug 4, 2026
cancelledbase runs still appear after this landed — that is expected, and not a regressionWorth recording, because the obvious reading is that the fix did not work.
After #13541, base
ci.ymlruns still show up ascancelledwhen several PRs merge in quick succession. Three merges landed within 8 seconds and produced:Both
cancelledruns have zero jobs:They never started a job. GitHub keeps at most one pending run per concurrency group: when a third arrives while one is running and one is pending, the pending one is cancelled and replaced. That is supersede behaviour, independent of
cancel-in-progress.So the distinction that matters:
Dropping a pending run is harmless here. The suite measures the base branch, and the newest run measures the newest base — a per-commit measurement is not something anything depends on. The first uncancelled base run after this landed produced the measurement #13162 had been unable to take at all.
How to tell the two apart when diagnosing: check the job count. A cancelled run with zero jobs was superseded while pending. A cancelled run with jobs in
completed/in_progresswas killed mid-flight, which is the failure this issue was about.mrveiss commentedon Aug 4, 2026
Delivered and verified in the merged tree — closing.
Closes #13432did not fire because the PR merged toDev_new_gui, which is not the repository default branch.Evidence —
.github/workflows/ci.yml:39-52now scopes cancellation to pull requests:The measurement that motivated it is recorded inline: of the last 39 completed base runs, 26 were cancelled and none succeeded — the base branch was effectively never verified.
Why
cancelledbase runs still appear, and why that is not a regression: runs started before this landed keep their original semantics, and a newly queued run still cancels a pending predecessor (GitHub keeps at most one in-progress plus one pending per group). Base runs now serialise and each in-progress run completes. Droppingcancel-in-progress: trueis the whole fix; it does not queue unboundedly.This restores the post-merge signal that #13162 needs in order to be measurable at all.
fix(ci): cancel superseded pull-request runs in 12 workflows (#14434) (…