Skip to content

fix: tag the version-bump commit so released tags carry their own version#97

Merged
breferrari merged 3 commits into
mainfrom
fix/release-tag-version-skew
Jun 2, 2026
Merged

fix: tag the version-bump commit so released tags carry their own version#97
breferrari merged 3 commits into
mainfrom
fix/release-tag-version-skew

Conversation

@breferrari

@breferrari breferrari commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes a release-pipeline bug where the git tag was cut before the version-bump commit, so every released tag's tree carried the previous version in its manifests. Surfaced by the shardmind 0.1.3 pre-release smoke test installing the obsidian-mind flagship. Also normalizes release tags to 3-component semver so the tag matches the manifest version ShardMind resolves.

Evidence

v6.2 tag -> commit 78484b1 -> .shardmind/shard.yaml + vault-manifest.json say 6.1.0
v6.1 tag -> commit 2a1936f -> say 6.0.0

The bump commit (release: update CHANGELOG and manifests for vX) lands on main after the tag, so it's never reachable from the tag.

Why it matters

ShardMind reads the manifest version: as the shard's identity, so shardmind install github:breferrari/obsidian-mind resolves the correct latest tag (the new hooks ran, requires.shardmind was satisfied) but reports the stale version. Worse, shardmind update keys off the manifest version — consecutive releases shipping the same stale version can make update detection misfire.

Root cause (correction to initial triage)

generate-changelog.ts already bumps both shard.yaml and vault-manifest.json to 3-component semver — main HEAD is correctly 6.2.0. The bug is purely tag ordering in release.yml, so this PR leaves generate-changelog.ts untouched.

Fix (.github/workflows/release.yml)

  1. Tag the bump commit. Drop the up-front tag creation; keep only a pre-flight "tag must not already exist" guard (manual trigger). After the version bump is committed to main, tag that commit and push it (-f/--force so the push:tags trigger's pre-bump tag moves forward).
  2. Verification step. Fails the release if the tagged tree's shard.yaml / vault-manifest.json version doesn't match the tag — the regression guard for this exact skew.
  3. 3-component tag normalization. Resolve-version normalizes vX/vX.YvX.Y.Z (so dispatch cuts v6.2.0, not v6.2). A 2-component push:tags trigger (v6.2) is recorded and the stale duplicate retired once v6.2.0 is created. Old 2-component tags (v6.0/v6.1/v6.2) are left as historical.

Backfill (already done, out-of-band)

main HEAD already had correct 6.2.0 manifests, so the live v6.2 tag was re-pointed to main HEAD (169df57). Verified: raw.githubusercontent.com/.../v6.2/.shardmind/shard.yaml now shows version: 6.2.0.

Test plan

  • Workflow YAML structure validated (no tabs; all steps at correct indent; tag/verify steps ordered after the bump commit, before zip/publish)
  • Normalization logic walked through: 6.2v6.2.0, v6.2.1 unchanged, push v6.2→creates v6.2.0 + retires v6.2
  • First release through the fixed workflow verified: curl -sL https://raw.githubusercontent.com/breferrari/obsidian-mind/<tag>/.shardmind/shard.yaml | grep '^version:' matches the 3-component tag, and a fresh shardmind install reports @<version>

🤖 Generated with Claude Code

…sion

The release workflow created the git tag at main HEAD *before*
generate-changelog.ts bumped shard.yaml / vault-manifest.json and committed
the result, so the tagged tree always lagged one version behind its tag:

  v6.2 tag -> tree says version 6.1.0
  v6.1 tag -> tree says version 6.0.0

ShardMind reads the manifest `version:` as the shard's identity (and
`shardmind update` keys off it), so `shardmind install github:...` resolved
the correct latest tag but reported the stale version, and consecutive
stale versions can make update detection misfire.

generate-changelog.ts already bumps both manifests correctly — the bug was
purely ordering. Fix:

- Don't create the tag up front. Keep only a pre-flight "tag must not exist"
  guard on the manual trigger.
- After committing the version bump to main, tag THAT commit and push it
  (-f/--force so the push:tags trigger's pre-bump tag moves forward).
- Add a verification step that fails the release if the tagged tree's
  shard.yaml / vault-manifest version doesn't match the tag (2-component
  tags like v6.2 are normalized to 6.2.0 for the check).

Scope: release pipeline only. No hook-lifecycle changes (PR #96).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 2, 2026 00:16

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a release workflow ordering bug so the git tag is applied to the version-bump commit, ensuring released tags contain manifests (.shardmind/shard.yaml, vault-manifest.json) with the matching version.

Changes:

  • Replaces early tag creation with a pre-flight “tag must not already exist” guard for manual releases.
  • Tags and force-pushes the tag after committing the changelog/manifests bump to main.
  • Adds a verification step to fail the release if the tagged tree’s manifest versions don’t match the tag (with 2-component tag normalization).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 62 to 66
if git ls-remote --tags origin "refs/tags/$VERSION" | grep -q .; then
echo "::error::Tag $VERSION already exists"
exit 1
fi
git tag "$VERSION"
git push origin "$VERSION"

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in ecba4a5. Restored the tag creation as a local, unpushed staged tag (manual-trigger step) before generate-changelog.ts runs, so getPreviousTag's second-newest assumption holds and prevTag is correct. The later 'Tag the release commit' step moves it onto the bump commit and force-pushes — keeping the no-skew fix.

Comment thread .github/workflows/release.yml Outdated
Comment on lines +134 to +140
shard=$(git show "$VERSION:.shardmind/shard.yaml" | sed -n 's/^version:[[:space:]]*//p' | head -1)
manifest=$(git show "$VERSION:vault-manifest.json" | sed -n 's/.*"version":[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
echo "tag=$VERSION expected=$want shard.yaml=$shard vault-manifest=$manifest"
if [ "$shard" != "$want" ] || [ "$manifest" != "$want" ]; then
echo "::error::Tagged tree version skew (shard.yaml=$shard manifest=$manifest, expected $want)"
exit 1
fi
Make the git tag match the 3-component manifest version ShardMind resolves
against. The Resolve-version step now normalizes vX / vX.Y to vX.Y.0 (vX.Y.Z
passes through), so workflow_dispatch cuts v6.2.0 rather than v6.2.

For the push:tags trigger, a human-pushed 2-component tag (v6.2) is recorded
as TRIGGER_TAG and retired after the canonical v6.2.0 tag is created at the
bump commit, so no stale duplicate lingers on the pre-bump commit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.

Comment thread .github/workflows/release.yml Outdated
Comment on lines +146 to +151
shard=$(git show "$VERSION:.shardmind/shard.yaml" | sed -n 's/^version:[[:space:]]*//p' | head -1)
manifest=$(git show "$VERSION:vault-manifest.json" | sed -n 's/.*"version":[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
echo "tag=$VERSION expected=$want shard.yaml=$shard vault-manifest=$manifest"
if [ "$shard" != "$want" ] || [ "$manifest" != "$want" ]; then
echo "::error::Tagged tree version skew (shard.yaml=$shard manifest=$manifest, expected $want)"
exit 1

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in ecba4a5. The verify step now always checks vault-manifest.json (present in every vault) and checks .shardmind/shard.yaml only when it exists in the tag (via git cat-file -e), matching the ENOENT-tolerance of the commit step and generate-changelog.ts. (Same concern as the earlier thread on the first review round.)

Comment on lines +53 to 55
if [[ ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::Invalid version format: $VERSION (expected vX.Y or vX.Y.Z)"
exit 1

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in ecba4a5. Error message now reads 'accepted inputs: vX, vX.Y, or vX.Y.Z, with or without the leading v'.

Three fixes from the PR #97 review:

- prevTag off-by-one: generate-changelog.ts derives the previous release as
  the second-newest tag, assuming the current release tag exists. Removing the
  early tag creation broke that on workflow_dispatch. Restore it as a LOCAL
  (unpushed) staged tag before the script runs; it's moved onto the bump commit
  and force-pushed later.
- verify step ENOENT-tolerance: always verify vault-manifest.json (present in
  every vault); verify .shardmind/shard.yaml only when it exists in the tag, so
  non-ShardMind forks stay releasable like the sibling steps already allow.
- error message: list the actual accepted inputs (vX, vX.Y, vX.Y.Z).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@breferrari breferrari merged commit daf9b1d into main Jun 2, 2026
1 check passed
@breferrari breferrari deleted the fix/release-tag-version-skew branch June 2, 2026 00:25
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.

2 participants