gates: one entry point (controller/scripts/controller_gates.py) + pre-push hook
A census of all thirteen gate scripts across the four felhom repos on 2026-08-02 found that every check a CLAUDE.md names was passing and two of the four nobody is told to run were failing. This repo had seven gates and CLAUDE.md named two; four more were reachable only via a line in REUSE.md, and docker_run_volume_path_gate.py — RED at census time — through one line in REUSE.md and nothing else. controller_gates.py runs all seven plus reuse_refs_check on the repo root, streams each gate's own output, and exits worst-wins non-zero. The shared reuse checker stays in felhom.eu/scripts/ and is invoked across the workspace — never copied here, which would recreate the drift it detects; an absent sibling clone FAILS the gate and prints the path tried. .githooks/pre-push runs it with --fast and refuses the push. Per-clone and --no-verify-able, both stated in the hook itself; a manual run WARNS when the clone is unarmed. test_controller_gates.py is a SEAM test — it asserts each member gate's own distinctive stdout, not the runner's summary line. Red-proofed: an inert run_gate still prints 'all controller gates OK' and exits 0, and turns the seam test red. Tooling only: no Go change, no image build, no deploy, no version bump.
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Seam test for scripts/controller_gates.py.
|
||||
|
||||
Run from controller/: python3 scripts/test_controller_gates.py
|
||||
|
||||
WHY THIS EXISTS. An entry point is a seam by definition: a runner that LISTS a gate but never
|
||||
executes it is inert and fully green, and this project has shipped an inert seam four times. So
|
||||
the assertion is on each member gate's OWN distinctive stdout — never on the runner's summary
|
||||
line, which the runner can print without ever calling anything — plus the exit code, which is a
|
||||
runner's actual effect.
|
||||
|
||||
Red-proofed 2026-08-02: replacing run_gate's body with `return 0` (the inert runner) turns
|
||||
test_every_member_gate_actually_ran red while the summary still prints "all controller gates OK".
|
||||
"""
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
SCRIPTS = os.path.dirname(os.path.abspath(__file__))
|
||||
CTRL = os.path.dirname(SCRIPTS)
|
||||
ENTRY = os.path.join(SCRIPTS, "controller_gates.py")
|
||||
|
||||
# (label, a substring only THAT gate can print)
|
||||
FINGERPRINTS = [
|
||||
("template-id", "integrity gate OK — every JS element-ID reference"),
|
||||
("emoji", "emoji gate OK"),
|
||||
("native-confirm", "native-confirm gate OK"),
|
||||
("offbox-rename", "offbox rename gate OK"),
|
||||
("app-row-dedup", "app_row_dedup_gate: OK"),
|
||||
("mojibake", "mojibake_gate: OK"),
|
||||
("docker-v", "docker -v gate OK"),
|
||||
("reuse-refs", "cited paths — exact"),
|
||||
]
|
||||
|
||||
|
||||
class ControllerGatesTest(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
p = subprocess.run([sys.executable, ENTRY, "--fast"], cwd=CTRL,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
cls.rc = p.returncode
|
||||
cls.out = p.stdout.decode("utf-8", "replace")
|
||||
|
||||
def test_exit_code_is_zero(self):
|
||||
self.assertEqual(self.rc, 0, self.out)
|
||||
|
||||
def test_every_member_gate_actually_ran(self):
|
||||
for label, fingerprint in FINGERPRINTS:
|
||||
self.assertIn(fingerprint, self.out,
|
||||
"gate %r is listed but its own output never appeared — an inert runner "
|
||||
"prints the summary without calling anything:\n%s" % (label, self.out))
|
||||
|
||||
def test_shared_reuse_checker_is_not_copied_into_this_repo(self):
|
||||
"""It lives in felhom.eu/scripts/ and is invoked across the workspace. A copy here would
|
||||
recreate exactly the drift it exists to detect."""
|
||||
self.assertFalse(os.path.exists(os.path.join(SCRIPTS, "reuse_refs_check.py")),
|
||||
"reuse_refs_check.py must NOT be copied into this repo")
|
||||
|
||||
def test_unknown_argument_is_rejected(self):
|
||||
p = subprocess.run([sys.executable, ENTRY, "--nope"], cwd=CTRL,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
self.assertEqual(p.returncode, 2, p.stdout.decode("utf-8", "replace"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
Reference in New Issue
Block a user