Skip to content

fix(release): make the tag step idempotent for job re-runs - #37

Merged
serialexperimentslainnnn merged 1 commit into
developfrom
bugfix/release-tag-idempotent
Aug 6, 2026
Merged

serialexperimentslainnnn merged 1 commit into
developfrom
bugfix/release-tag-idempotent

Conversation

@serialexperimentslainnnn

Copy link
Copy Markdown
Owner

Summary

Last fix before cutting 5.0.0, and it protects the operation we are about to perform for the first
time. Two problems in release.yml, both flagged during the review of the commit that introduced
them (#36) and deliberately left for a follow-up.

1. The documented recovery path did not work. If the publish fails after the tag is cut, the
workflow says to re-run the job. But fetch-depth: 0 fetches tags, so a bare git tag -s exits
non-zero on the second pass — the job dies there and never reaches gh release upload --clobber.
The release would be stuck needing a human to delete a tag this repository treats as immutable,
which is the exact situation immutability exists to prevent.

Re-running the whole workflow is not a substitute: guard would see the tag on the remote and
correctly report the version as already released, skipping verify and publish entirely. The job
re-run is the only path, so it has to survive an existing tag. It now detects the ref, verifies the
signature already on it, and skips re-cutting.

2. A justification that was false. The header claimed the tag is checked out because main is a
moving ref a later merge could slip into the release. actions/checkout defaults to github.sha,
so every job was already pinned to the triggering commit. Building from the tag is a provenance
statement, not a race fix — corrected rather than left as a plausible-sounding reason someone would
later rely on.

Type of change

  • Bug fix
  • Docs / build / CI

Risk and rollback

Risk: touches only the release path, and only the branch that runs when a tag already exists —
which is unreachable on a first, successful release. If it is wrong, it is wrong in the direction of
not re-cutting a tag that should have been cut, and that fails loudly at git verify-tag.

Rollback: revert. Nothing here reaches a user.

How was this tested?

  • release.yml parses (yaml.safe_load) — and that check earned its keep: it caught a stray
    character on line 1 that would have broken the entire workflow file. It was local-only and
    never committed, but the file was one git add away from a release workflow that cannot parse.
  • The idempotency branch exercised in a throwaway repository: first pass creates the tag, second
    pass reports it exists and does not re-cut.
  • End to end. It cannot be: this branch only runs after a failed publish, and the first real
    execution of release.yml is 5.0.0 itself.

Notes for reviewers

This is the last thing between us and the release. apply-rulesets.sh still has to run after
#36 is merged (it is) and before #35 goes in — the No bot PRs pending on develop check has to
exist as a job before it can be required, or #35 blocks on a check nothing will ever report.

Not fixed here and left for 5.0.1: the CHANGELOG entry for 5.0.0 predates tonight's CI work (image
segmentation, release ordering, the bot gate, CodeQL required on develop), so the record of the
release is incomplete on that point.

The recovery path the workflow documents did not work. If the publish failed after the tag was cut,
the intended fix was to re-run the job — but `fetch-depth: 0` fetches tags, so a bare `git tag -s`
exited non-zero on the second pass, the job died before reaching `gh release upload --clobber`, and
the release was stuck needing a human to delete a tag this repository treats as immutable. Which is
the exact situation immutability exists to prevent.

Re-running the whole WORKFLOW cannot substitute: `guard` would see the tag on the remote and
correctly report the version as already released, skipping verify and publish entirely. So the job
re-run is the only path, and it has to survive an existing tag. It now detects the ref, verifies the
signature that is already on it, and skips re-cutting.

Also corrects a justification that was simply false. The header claimed the tag is checked out
because `main` is a moving ref that a later merge could slip into the release. `actions/checkout`
defaults to `github.sha`, so every job was already pinned to the triggering commit — building from
the tag is a provenance statement, not a race fix. Both claims were flagged in the review of the
commit that introduced them; this is that follow-up.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@serialexperimentslainnnn
serialexperimentslainnnn merged commit 8a4d9fd into develop Aug 6, 2026
10 checks passed
@serialexperimentslainnnn
serialexperimentslainnnn deleted the bugfix/release-tag-idempotent branch August 10, 2026 19:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant