ci(concurrency): stop cancelling the run a merge is read against, and give the release a bracket - #5
Merged
Conversation
… give the release a bracket
Two different defects in two files, both about the same thing: which run survives.
ci.yml cancelled unconditionally while also firing on a push to main and develop. That push run is the one a merge is read against, and an unconditional cancel throws it away when a second push lands behind it. What survives is a check that reported nothing, and a cancelled check reads as noise rather than as a failure -- so the merge ends up measured by an absence. The cancel now scopes to pull requests, where GitHub's per-job minute rounding actually bills for an answer about a tree that no longer exists. Outside a pull request the group only serialises, which costs nothing.
release.yml had no bracket at all. It gets one that serialises and never cancels: the run is started by a v*.*.* tag push or by hand, both deliberate acts somebody is waiting on, and a cancelled release run is the worst case of the paragraph above.
The fleet's usual form is `cancel-in-progress: ${{ github.event_name == 'pull_request' }}`, and it is deliberately NOT used in release.yml: that file has no pull-request trigger, so the expression would be false on every run it can have -- a line that reads as a live decision and is a constant. It is written as the constant instead, with the restoration named in the comment.
Found by tools/workflow-concurrency-sweep.sh in claude-baseline.
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.
Two files, two different defects, both about which run survives.
ci.yml— cancels the run a merge is read againstIt fires on a push to
mainanddevelopand cancelled unconditionally. A second push on the same ref throws that run away, and what survives is a check that reported nothing — a cancelled check reads as noise rather than as a failure, so the merge is measured by an absence.Outside a pull request the group then only serialises: two runs stay off one ref, for free. The cancel stays where it pays — a pull request whose later push overtook the run in flight, which is where GitHub's per-job minute rounding actually bills for an answer about a tree that no longer exists.
release.yml— no bracket at all, and it must never cancelIt had none. It gets one that serialises and never cancels:
The run is started by a
v*.*.*tag push or by hand. Both are deliberate acts somebody is waiting on the result of, and a cancelled release run is the worst case of the paragraph above.cancel-in-progress: ${{ github.event_name == 'pull_request' }}is right wherever a pull request can start the workflow — it cannot here, sinceon:carries a tag push andworkflow_dispatchonly. The expression would evaluate tofalseon every run this file can have: a line that reads as a live decision and is a constant.This fleet has paid for that shape before — a sibling repository carried the same expression over a
workflow_dispatch-only trigger, and the note there records it as "a condition that could not come true". So it lands as the constant, and the comment names the restoration: bring the expression back in the same change that adds apull_requesttrigger.The group still earns its place either way — two releases must not run against one ref at once.
Found by
tools/workflow-concurrency-sweep.shinclaude-baseline.