fix(semrel): a release dropped to the behind-remote race must not exit green #45

Merged
ryangr0 merged 1 commit from ryangr0/semrel-behind-remote-retry into main 2026-08-09 07:59:48 +00:00 AGit
Owner

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

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>
fix(semrel): a release dropped to the behind-remote race must not exit green
Some checks failed
docker-build-and-push-harbor-fast.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
docker-build-and-push-harbor.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
docker-build-and-push-registry-fast.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
docker-build-and-push-registry.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
docker-build-and-push.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
forgejo-distribute.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
github-issue-create-by-prompt.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
github-issues-create-by-prompt.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
helm-chart-deploy.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
helm-chart-push.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
helm-charts-deploy.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
helm-charts-push.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
laravel-quality.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
php-application-static-analysis.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
rust-semantic-release.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
semantic-release-monorepo.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
sync-template-files.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
techdocs-deploy-codeberg.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
techdocs-deploy-gh-pages.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
tests.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
update_mkdocs.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
update_techdocs.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
wordpress-plugin-release-distribute.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
wordpress-plugin-release.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
semantic-release.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
setup-repository-bootstrap.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
setup-repository-copilot-files.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
setup-repository-create-from-template.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
spa-preview.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
static-analysis.yml / Merge pull request 'fix(semrel): a release dropped to the behind-remote race must not exit green' (#45) from ryangr0/semrel-behind-remote-retry into main (pull_request) Failing after 0s
5728850839
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>
webgrip-ci referenced this pull request from a commit 2026-08-09 08:01:09 +00:00
Sign in to join this conversation.
No reviewers
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
webgrip/workflows!45
No description provided.