fix(release): key the candidate by version — the tag never points at the push #127

Merged
ryangr0 merged 1 commit from fix/candidate-keyed-by-version into main 2026-08-11 05:00:53 +00:00
Owner

Caught by checking a real tag before cutting the first post-ADR-0009 release: node-ci-runner-v1.0.2 targets the [skip ci] bump commit @semantic-release/git creates after verify — the parent of the push the candidate was sha-named for. Promotion would silently never fire; every release would take the fallback, indistinguishable from ADR-0009 not existing.

Fix: the composite exports the candidate ref as a prefix (:cand), the gate appends -<version> (pairs with semantic-release-config #8), and the promote step looks up cand-<version> directly — dropping the tag→commit API resolution entirely. A release now promotes its own candidate: one release proves seed + promote end-to-end.

Mismatched halves fall back safely in both directions. Merge together with config #8.

Generated with Claude Code

Caught by checking a real tag before cutting the first post-ADR-0009 release: `node-ci-runner-v1.0.2` targets the `[skip ci]` bump commit @semantic-release/git creates **after** verify — the parent of the push the candidate was sha-named for. Promotion would silently never fire; every release would take the fallback, indistinguishable from ADR-0009 not existing. **Fix**: the composite exports the candidate ref as a prefix (`:cand`), the gate appends `-<version>` (pairs with semantic-release-config #8), and the promote step looks up `cand-<version>` directly — dropping the tag→commit API resolution entirely. A release now promotes its **own** candidate: one release proves seed + promote end-to-end. Mismatched halves fall back safely in both directions. Merge together with config #8. Generated with [Claude Code](https://claude.com/claude-code)
Caught before the first promotion attempt, by checking a real tag:
node-ci-runner-v1.0.2 targets the chore(release) [skip ci] bump commit that
@semantic-release/git creates AFTER the verify build — the parent of the
push whose sha the candidate was named for. A sha-keyed candidate can
therefore never be found from the tag: promotion would silently never fire
and every release would take the fallback build, indistinguishable from
ADR-0009 not existing.

The version is the one name both sides derive independently: the gate knows
it via ${nextRelease.version} templating, the release pipeline parses it
from the tag. The composite now exports the candidate ref as a PREFIX
(:cand) and the gate appends -<version>; the promote step looks up
cand-<version> directly, dropping the tag->commit API resolution entirely.

A pleasant consequence: a release now promotes its OWN candidate (the
verify that cut version X pushed cand-X), so a single release exercises
seed + promote end-to-end instead of needing two.

Mismatched halves stay safe in both directions: old config + new promote
misses and falls back; new config + old composite pushes an oddly-named tag
that nothing reads, and falls back.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
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/infrastructure!127
No description provided.