CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / canary (push) Failing after 37s
CI Pipeline / lint (push) Successful in 45s
Auto-version and Release / release (push) Successful in 55s
CI Pipeline / type-check (push) Successful in 32s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / unit-tests (push) Failing after 59s
deploy / deploy (push) Failing after 15m24s
CI Pipeline / required-checks (push) Successful in 1s
Handoff 2026-09-11 Part A-C:
A. tui_startup_canary two modes: candidate (--stage, sys.path SCRUBBED of
/mnt/workdrive/rune-code/current + imported-rune purge + contamination
check that rune resolves from the stage) and current (consuming path).
Scrub proven: candidate mode on the 76f71fc stage reports 76f71fc/0.66.2
while current is bb536c9/0.66.3. FIXED a live exit-code bug: main()
returned 1 but was called without sys.exit — a failed canary exited 0
(the deploy gate's own returncode check in deploy_stage.py was correct,
so promotion was never actually bypassed; the standalone script was).
B. Negative deployment canary (tests/test_deployment_canary.py): broken
staged candidate → canary exit 1 naming the failure → current identity
byte-identical before/after. Plus current-mode identity regression.
C. Release recursion: is_release_commit() extracted into
version_convergence.py (ONE source of truth); workflow guard uses
--is-release-subject CLI (no inline python in YAML); regression tests
cover recognition, never-bump-from-release-commits (incl. the 5x loop
case), substantive commits still bumping, and the CLI exit contract.
1241 tests green; ratchet 353/80; henxels clean.
88 lines
3.2 KiB
Python
88 lines
3.2 KiB
Python
"""Release recursion regression (handoff 2026-09-11 Part C).
|
|
|
|
The rule: a release bump commit MUST NOT trigger another version bump.
|
|
The decision lives in version_convergence (ONE source of truth) — the
|
|
workflow guard calls --is-release-subject; these tests exercise the same
|
|
function the workflow uses, plus the CLI exit-code contract itself.
|
|
"""
|
|
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
REPO = Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(REPO / "scripts"))
|
|
|
|
from version_convergence import is_release_commit # noqa: E402
|
|
|
|
|
|
class ReleaseRecursionRule(unittest.TestCase):
|
|
def test_release_commit_is_recognized(self):
|
|
# The EXACT subject shape the auto-version workflow generates.
|
|
self.assertTrue(
|
|
is_release_commit(
|
|
"chore(release): auto-bump version to 0.66.2 — earned by # "
|
|
"(patch: converged release (push-to-master bump))"
|
|
)
|
|
)
|
|
self.assertTrue(is_release_commit("chore(release): auto-bump version to 0.61.0"))
|
|
self.assertTrue(is_release_commit("chore: release v0.60.0"))
|
|
|
|
def test_release_commit_never_warrants_a_bump(self):
|
|
# The deeper invariant: classify_subject('other') does not feed
|
|
# highest_warranted_bump, so a release commit alone cannot bump.
|
|
from version_convergence import classify_subject, highest_warranted_bump
|
|
|
|
subject = (
|
|
"chore(release): auto-bump version to 0.66.2 — earned by # (patch: converged release (push-to-master bump))"
|
|
)
|
|
self.assertEqual(classify_subject(subject), "other")
|
|
self.assertIsNone(highest_warranted_bump([subject]))
|
|
self.assertIsNone(highest_warranted_bump([subject] * 5)) # the loop case
|
|
|
|
def test_substantive_commits_still_bump(self):
|
|
from version_convergence import classify_subject, highest_warranted_bump
|
|
|
|
self.assertEqual(classify_subject("feat(ADAPT-LIVE): route discriminator"), "feat")
|
|
self.assertEqual(classify_subject("fix(deploy): prefix-match"), "fix")
|
|
self.assertEqual(
|
|
highest_warranted_bump(["feat(x): a", "fix(y): b"]),
|
|
"minor",
|
|
)
|
|
|
|
def test_cli_exit_contract(self):
|
|
# The workflow consumes the CLI, not the Python API — prove the
|
|
# exit-code contract the guard depends on.
|
|
r = subprocess.run(
|
|
[
|
|
sys.executable,
|
|
str(REPO / "scripts" / "version_convergence.py"),
|
|
"--is-release-subject",
|
|
"chore(release): auto-bump version to 0.66.2",
|
|
],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=60,
|
|
cwd=str(REPO),
|
|
)
|
|
self.assertEqual(r.returncode, 0, "release subject → guard exits 0 (skip)")
|
|
r2 = subprocess.run(
|
|
[
|
|
sys.executable,
|
|
str(REPO / "scripts" / "version_convergence.py"),
|
|
"--is-release-subject",
|
|
"feat(x): real feature",
|
|
],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=60,
|
|
cwd=str(REPO),
|
|
)
|
|
self.assertEqual(r2.returncode, 1, "feat subject → guard exits 1 (bump)")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|