fix(semrel): a release dropped to the behind-remote race must not exit green #45
No reviewers
Labels
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
webgrip/workflows!45
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "ryangr0/semrel-behind-remote-retry"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The plain composite ended on a bare
"$sr" "${args[@]}". When a push landsmid-run the checkout is behind origin, semantic-release logs "The local branch
is behind the remote one, therefore a new version won't be published" and
EXITS 0. The job goes green having released nothing, and nothing recovers it:
the commit that overtook it is a
[skip ci]release commit, so no later runis triggered either.
ploeg lost a release to this on 2026-08-09. Run 159 aligned to the tip, a push
landed 19 seconds later, and semantic-release checked 29 seconds after that.
Green job, no rc.
align-to-remote-tipcloses the wide window — queued, thenovertaken — but it cannot close the seconds between itself and the run step,
and a narrow window is still a window.
The monorepo composite has carried the fix since run 141 dropped two releases
the same way; it just never made it over here, because there the racers are
sibling package jobs and the race looks like a monorepo problem. It isn't. An
ordinary second push races just as well — rarer, and every bit as silent.
So: same guard, three attempts, reset onto the moved tip between them, and
rc=0on a final behind-remote is converted to a failure, because a droppedrelease is not a success. Two adaptations for this composite:
origin/$GITHUB_REF_NAME is not a branch, and such a run cannot hit the
race anyway since nothing pushes to that ref.
dropped release, and the skip-refs validation gate should stay green.
Verified by extracting the loop and driving it against a scripted
semantic-release: clean success runs once and passes; behind-once and
behind-twice recover and pass; behind three times fails; a non-fast-forward
recovers; a real plugin error fails on the first attempt without retrying; a
behind-remote on a tag ref fails without attempting a reset; and a dry run
stays green.
Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com
The plain composite ended on a bare `"$sr" "${args[@]}"`. When a push lands mid-run the checkout is behind origin, semantic-release logs "The local branch is behind the remote one, therefore a new version won't be published" and EXITS 0. The job goes green having released nothing, and nothing recovers it: the commit that overtook it is a `[skip ci]` release commit, so no later run is triggered either. ploeg lost a release to this on 2026-08-09. Run 159 aligned to the tip, a push landed 19 seconds later, and semantic-release checked 29 seconds after that. Green job, no rc. `align-to-remote-tip` closes the wide window — queued, then overtaken — but it cannot close the seconds between itself and the run step, and a narrow window is still a window. The monorepo composite has carried the fix since run 141 dropped two releases the same way; it just never made it over here, because there the racers are sibling package jobs and the race looks like a monorepo problem. It isn't. An ordinary second push races just as well — rarer, and every bit as silent. So: same guard, three attempts, reset onto the moved tip between them, and `rc=0` on a final behind-remote is converted to a failure, because a dropped release is not a success. Two adaptations for this composite: - Only reset when GITHUB_REF is a branch. On a tag or PR ref origin/$GITHUB_REF_NAME is not a branch, and such a run cannot hit the race anyway since nothing pushes to that ref. - Never fail a dry run. It publishes nothing, so a dropped release is not a dropped release, and the skip-refs validation gate should stay green. Verified by extracting the loop and driving it against a scripted semantic-release: clean success runs once and passes; behind-once and behind-twice recover and pass; behind three times fails; a non-fast-forward recovers; a real plugin error fails on the first attempt without retrying; a behind-remote on a tag ref fails without attempting a reset; and a dry run stays green. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>