All checks were successful
PR Checks / rust-gates (pull_request) Successful in 2m15s
An existing tag was treated as "nothing to release", unconditionally. That is wrong in the one case it matters: a tag with no release behind it means an earlier run tagged and then died before publishing -- which is exactly what happened on servuo-plugins' first release, where absent REGISTRY_* secrets took the release API call to 401 after the tag had been pushed. Standing down on the tag alone makes that permanent. Every later run sees the tag, sets RELEASE=false, and the release never appears; the version is unpublishable forever. The tag now decides nothing on its own. The API does: 200 -> a release exists, stand down 404 -> tag without release, reuse the tag and publish what is missing else -> refuse and exit 1 The last arm matters as much as the others. A 000 from a network failure or a 401 from a bad token is not evidence of absence, and guessing "no release" would republish over a good one. Note the 404 arm deliberately overrides the RELEASE=false decided just above it: with the tag in place there are no releasable commits after it, so the normal path always stands down -- which is why this could never self-heal on its own. Two consequences handled with it. The changelog range is now previous-tag..this-tag on a recovery run, since a run finishing an earlier one has nothing after the tag and would otherwise publish an empty change list. And the tagging step tolerates the tag already existing, because `git tag` on an existing name fails under `set -e` while pushing an identical tag is a harmless no-op -- a push that does fail there means the remote tag points somewhere else, which should stop the run. This is the same handling installer/release.yml already carries; link was the copy that still had the trap. Verified by extracting this step and driving it through four scenarios against a real clone with the live tags, with curl stubbed to return each status: a normal patch bump (v1.1.1, release=true), a tag with no release (recovers, release=true), a tag with a release (stands down), and an unreachable API (exit 1, publishes nothing). Co-Authored-By: Claude <noreply@anthropic.com>