Files
admin f946b0d0ca
gates / gates (push) Successful in 12s
gates: the newest release header must state its MinAgent; backfill v0.233.0-v0.236.0 (R-470, R-472)
From hub v0.112.0 a floor above the golden is served only with a declared
MinAgent, read from this CHANGELOG's newest `## vX.Y.Z` header. New fast,
blocking gate minagent_header_gate.py: that block must contain a line
starting `**MinAgent: X.Y.Z**`; prose, a code span or a non-bold mention
does not count (decoy test; red-proof F: relaxing the match to a body
mention fails test_decoy_body_mention_is_not_the_line).

Backfill: v0.233.0, v0.234.0, v0.235.0 and v0.236.0 carried no MinAgent
line. Each now reads `**MinAgent: 0.129.0** (unchanged)`, the value of the
nearest earlier header (v0.232.0). Proof it did not move: zero commits
under controller/internal/agentapi since 2026-09-01 (last: bb50e12,
2026-08-14), and the highest featureMinAgent entry is 0.129.0.
2026-09-13 17:09:33 +02:00

58 lines
2.2 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Tests for minagent_header_gate.py (R-470/R-472) — each case writes a CHANGELOG and runs the REAL gate.
Run from controller/: python3 scripts/test_minagent_header_gate.py
"""
import os
import subprocess
import sys
import tempfile
import unittest
SCRIPTS = os.path.dirname(os.path.abspath(__file__))
GATE = os.path.join(SCRIPTS, "minagent_header_gate.py")
def run(body):
with tempfile.NamedTemporaryFile("w", suffix=".md", delete=False, encoding="utf-8") as f:
f.write(body)
path = f.name
try:
env = dict(os.environ, MINAGENT_GATE_CHANGELOG=path)
p = subprocess.run([sys.executable, GATE], capture_output=True, text=True, env=env)
return p.returncode, p.stdout + p.stderr
finally:
os.unlink(path)
class MinAgentHeaderGateTest(unittest.TestCase):
def test_header_line_passes(self):
rc, out = run("## v0.239.0 — x (2026-09-13)\n\n**MinAgent: 0.129.0** (unchanged)\n\nbody\n\n## v0.238.1 — y\n")
self.assertEqual(rc, 0, out)
self.assertIn("v0.239.0 declares MinAgent 0.129.0", out)
def test_missing_line_fails_naming_the_header(self):
rc, out = run("## v0.239.0 — x (2026-09-13)\n\nbody\n\n## v0.238.1 — y\n\n**MinAgent: 0.129.0** (unchanged)\n")
self.assertEqual(rc, 1, out)
self.assertIn("v0.239.0", out)
def test_decoy_body_mention_is_not_the_line(self):
"""R-421: the word in prose, a code span, or a non-bold form is the LABEL without the FACT.
COMPANION RED-PROOF F (REPORT.md): relax MINAGENT_LINE_RE to a plain search for 'MinAgent'.
This test then passes the decoy and fails."""
decoy = ("## v0.239.0 — x (2026-09-13)\n\n"
"MinAgent is unchanged from the previous release, see `**MinAgent: 0.129.0**` there.\n"
"The agent requirement (MinAgent: 0.129.0) did not move.\n\n## v0.238.1 — y\n")
rc, out = run(decoy)
self.assertEqual(rc, 1, out)
def test_no_header_is_inconclusive(self):
rc, out = run("# CHANGELOG\n\nnothing released\n")
self.assertEqual(rc, 2, out)
if __name__ == "__main__":
unittest.main()