Release: do not let a pre-release tag move :latest (#4) #105

Merged
claude-bot merged 1 commit from fix/release-prerelease-tags into main 2026-09-01 16:04:25 +00:00
Contributor

Prerequisite for the #4 dry run. Found by reading release.yml before its first ever execution — the repo has zero tags, so nothing in this workflow has run.

Two defects, both only reachable via a pre-release tag

1. :latest was unconditional.

type=raw,value=latest        # fires for EVERY v* tag

docker/metadata-action already suppresses {{major}}.{{minor}} for pre-releases, which makes it easy to assume it handles latest too. It does not — a raw tag has no semver awareness. So v0.0.1-rc1 would have retagged :latest to a release-candidate build, and anything deploying :latest would silently pull it.

2. prerelease: false was hardcoded in the Forgejo release payload, so an -rc tag would be published as a finished release.

Both now key off a - in the tag name.

Why this had to land first

The plan for #4 is to prove the pipeline with a throwaway tag. Running that against the unfixed workflow would have demonstrated the bug by causing it — moving :latest to a disposable RC. Nothing consumes :latest today, so the blast radius would have been nil, but it would still have been a self-inflicted wound on the exact artifact #104 wants prod to avoid depending on.

What is still unverified

This PR doesn't prove the workflow works — it can't, because release.yml only triggers on v*. Specifically still untested:

  • registry auth on the release path (REGISTRY_TOKEN, changed during #64 and never exercised here)
  • the CHANGELOG note-extraction awk
  • the Forgejo release API call, which uses secrets.GITHUB_TOKEN rather than REGISTRY_TOKEN

That's what the dry-run tag is for, and it comes next.

🤖 Generated with Claude Code

Prerequisite for the #4 dry run. Found by **reading** `release.yml` before its first ever execution — the repo has zero tags, so nothing in this workflow has run. ## Two defects, both only reachable via a pre-release tag **1. `:latest` was unconditional.** ```yaml type=raw,value=latest # fires for EVERY v* tag ``` `docker/metadata-action` already suppresses `{{major}}.{{minor}}` for pre-releases, which makes it easy to assume it handles `latest` too. It does not — a raw tag has no semver awareness. So `v0.0.1-rc1` would have retagged `:latest` to a release-candidate build, and anything deploying `:latest` would silently pull it. **2. `prerelease: false` was hardcoded** in the Forgejo release payload, so an `-rc` tag would be published as a finished release. Both now key off a `-` in the tag name. ## Why this had to land first The plan for #4 is to prove the pipeline with a throwaway tag. Running that against the unfixed workflow would have *demonstrated the bug by causing it* — moving `:latest` to a disposable RC. Nothing consumes `:latest` today, so the blast radius would have been nil, but it would still have been a self-inflicted wound on the exact artifact #104 wants prod to avoid depending on. ## What is still unverified This PR doesn't prove the workflow works — it can't, because `release.yml` only triggers on `v*`. Specifically still untested: - registry auth on the release path (`REGISTRY_TOKEN`, changed during #64 and never exercised here) - the CHANGELOG note-extraction `awk` - the Forgejo release API call, which uses `secrets.GITHUB_TOKEN` rather than `REGISTRY_TOKEN` That's what the dry-run tag is for, and it comes next. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Release: do not let a pre-release tag move :latest (#4)
All checks were successful
CI / Alembic migration check (pull_request) Successful in 33s
CI / Python lint & type-check (pull_request) Successful in 57s
CI / Frontend lint, test & build (pull_request) Successful in 1m19s
CI / Python tests (pull_request) Successful in 2m7s
CI / Docker build, health smoke & E2E (pull_request) Successful in 2m20s
2da67f92eb
Found by reading release.yml before its first ever execution -- the repo
has zero tags, so nothing in this workflow has run.

Two defects, both of which only bite on a pre-release tag:

- `type=raw,value=latest` is unconditional, so `v0.0.1-rc1` would retag
  :latest to an RC build. docker/metadata-action already skips
  {{major}}.{{minor}} for pre-releases, but it does not skip a raw tag, so
  this needs an explicit guard. Anything deploying :latest would silently
  pull a release candidate.
- `prerelease: false` is hardcoded in the Forgejo release payload, so an
  -rc tag would be published as a finished release.

Both now key off a `-` in the tag name.

This matters more than it looks: the plan for #4 is to prove the pipeline
with a throwaway tag, and doing that against the unfixed workflow would have
demonstrated the bug by causing it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
claude-bot deleted branch fix/release-prerelease-tags 2026-09-01 16:04:25 +00:00
Sign in to join this conversation.
No description provided.