054e85a2bf
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 was the extreme case: nothing ran against it at all, and its REUSE.md — 90 cited paths — was checked by no one. agent_gates.py exists at ONE gate on purpose, so the agent is not the one repo with nowhere to put a check and so the pre-push hook has the same entry point in all four repos. It grows when the agent grows a second gate. The shared reuse checker stays in felhom.eu/scripts/ and is invoked across the workspace — never copied here; an absent sibling clone FAILS the gate and prints the path tried, which test_agent_gates.py pins by running the entry point from a lone directory with no sibling. .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. Tooling only: no Go change, no build, no deploy, no version bump.
68 lines
2.8 KiB
Python
68 lines
2.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Seam test for scripts/agent_gates.py.
|
|
|
|
Run from the repo root: python3 scripts/test_agent_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 the 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.
|
|
|
|
The second test is the one that matters here: this repo's only gate lives in a SIBLING clone, so
|
|
"the sibling is missing" must be a FAILURE and not a quiet skip.
|
|
"""
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
|
|
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
ENTRY = os.path.join(ROOT, "scripts", "agent_gates.py")
|
|
|
|
|
|
class AgentGatesTest(unittest.TestCase):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
p = subprocess.run([sys.executable, ENTRY, "--fast"], cwd=ROOT,
|
|
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_member_gate_actually_ran(self):
|
|
self.assertIn("cited paths — exact", self.out,
|
|
"the reuse-refs gate is listed but its own output never appeared — an inert "
|
|
"runner prints the summary without calling anything:\n%s" % self.out)
|
|
|
|
def test_missing_shared_checker_is_a_failure_not_a_skip(self):
|
|
"""Fail-closed. Copy the entry point into a lone directory with no felhom.eu sibling and
|
|
confirm it CONVICTS rather than reporting green with nothing run."""
|
|
tmp = tempfile.mkdtemp(prefix="agent-gates-")
|
|
try:
|
|
lone = os.path.join(tmp, "felhom-agent", "scripts")
|
|
os.makedirs(lone)
|
|
shutil.copy(ENTRY, os.path.join(lone, "agent_gates.py"))
|
|
p = subprocess.run([sys.executable, os.path.join(lone, "agent_gates.py"), "--fast"],
|
|
cwd=os.path.dirname(lone),
|
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
out = p.stdout.decode("utf-8", "replace")
|
|
self.assertNotEqual(p.returncode, 0, out)
|
|
self.assertIn("is MISSING — tried", out)
|
|
finally:
|
|
shutil.rmtree(tmp, ignore_errors=True)
|
|
|
|
def test_unknown_argument_is_rejected(self):
|
|
p = subprocess.run([sys.executable, ENTRY, "--nope"], cwd=ROOT,
|
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
self.assertEqual(p.returncode, 2, p.stdout.decode("utf-8", "replace"))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main(verbosity=2)
|