Skip to content

Auto-tag rolling-next on post-merge (forge-only) + align guard tag-resolution #21

@misnaej

Description

@misnaej

Priority: low (tier-4). Filed from an investigation; no code yet.

Problem

The rolling-next git tag can silently desync from plugin.json. A branch bumps plugin.json (e.g. to 1.16.2), merges to dev, but the matching v1.16.2 tag is only created if someone manually runs /forge:next (forge-next-prep --tag). If nobody runs it, dev sits at plugin.json=1.16.2 with the latest tag still v1.16.1 — and the pre-commit guard keeps passing (1.16.2 > v1.16.1), so later PRs are never forced to bump. This actually happened: v1.16.2 was missing and had to be tagged by hand.

The tagging logic already exists

next_prep.py::_maybe_tag_release already does the right thing — tags v<plugin.json.version> at HEAD and pushes when plugin.json is strictly newer than the latest tag, idempotent otherwise. It resolves the latest tag via _latest_v_tag = git tag --list v* --sort=-v:refname (global semver-max, branch-independent — correct). It's just wired only to the manual /next path.

Proposal

Call the existing _maybe_tag_release automatically from forge-post-merge (already interactive-only / CI-safe per FOUNDATION §15; already fires on every git pull). No new tag logic — reuse.

Forge-only gating (must not fire in consumer repos): add an explicit opt-in [tool.forge] auto_tag_on_merge = true (FOUNDATION §16 Pattern C — only forge sets it), AND guard on current branch == dev_branch. _maybe_tag_release already no-ops without .claude-plugin/plugin.json.

Open decision — auto-push risk: _maybe_tag_release pushes the tag (irreversible release) as a side effect of git pull. Two postures:

  • Advisory: post-merge only warns ("plugin.json X > latest tag Y — run forge-next-prep --tag"), mirroring the staleness-check pattern. Human pulls the trigger.
  • Full-auto: tag + push behind the opt-in flag (the bump was already PR-reviewed).

Also: fix a guard inconsistency (tech-debt)

verify_plugin_version.py resolves "latest tag" with git describe --tags --abbrev=0 (ancestry-scoped — misses tags not in HEAD's history, e.g. a release tagged on main after a dev/main split). next_prep._latest_v_tag uses global semver-max. They disagree in the dual-track case. Switch the guard to the same global-max resolution so the guard and the auto-tagger never contradict.

Decisions to make when picked up

  • advisory vs full-auto on post-merge
  • opt-in flag name (auto_tag_on_merge?)
  • fold the verify_plugin_version tag-resolution fix into the same PR

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureNew capabilitytech-debtCleanup / consolidationtier-4-lowNice-to-have / research

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions