fix(release): wire release boundary into convergence (duplicate-bump root cause)

release_convergence() never assigned  from
last_release_boundary() — the production path classified ALL commits
(959+) as unreleased, so the warranted bump (minor, from an ancient
feat) never converged and every queued push wrote its own bump commit
(5x 0.66.9 observed 2026-09-11 20:21). Now the boundary is the one
source of truth: last chore(release) commit, falling back to the
latest tag. Post-boundary subjects only.

Also: local path was NOT reached when _boundary_subject was injected;
test_cli_prints_plan_json expectation updated to boundary semantics
(feat below the tag no longer warrants minor).
This commit is contained in:
Nick committed 2026-09-11 20:34:30 +01:00
1 parent 95bac995a3
commit d01df797c1
2 files changed
+29 -9

No files matched your search

+24 -8
View File
@@ -311,14 +311,30 @@ def release_convergence(
)
subjects = [s for s in result.stdout.splitlines() if s.strip()]
else:
# No release boundary: all commits are unreleased
result = subprocess.run(
["git", "log", "--format=%s"],
capture_output=True,
text=True,
cwd=str(repo) if repo else None,
check=True,
)
# Production path: converge over commits since the last release
# boundary. T15 Part F root cause: `boundary` was initialized to
# None and never assigned — every run classified ALL commits as
# unreleased (959+), so the warranted bump never converged and
# every queued push wrote its own bump commit (5× 0.66.9 observed
# 2026-09-11 20:21). Assign the boundary from the one source of
# truth and range the log over it.
boundary = last_release_boundary(repo)
if boundary:
result = subprocess.run(
["git", "log", "--format=%s", f"{boundary}..HEAD"],
capture_output=True,
text=True,
cwd=str(repo) if repo else None,
check=True,
)
else:
result = subprocess.run(
["git", "log", "--format=%s"],
capture_output=True,
text=True,
cwd=str(repo) if repo else None,
check=True,
)
subjects = [s for s in result.stdout.splitlines() if s.strip()]
# Exclude chore(release) commits from bump classification (they ARE releases)
+5 -1
View File
@@ -353,4 +353,8 @@ class TestRealGitRepo:
out = vc.main(["--repo", str(repo)])
printed = json.loads(capsys.readouterr().out)
assert printed == out
assert out["warranted_bump"] == "minor" # "feat: base" is in the subjects since tag
# Boundary semantics (T15 Part F fix): the release boundary falls
# back to the latest tag, so only post-tag commits count —
# "feat: base" sits below the boundary and must NOT warrant minor.
assert out["warranted_bump"] == "patch"
assert out["commits_since_boundary"] == 1