From 7ee00d59a86b964907bd1554e634e8639f6c8ef4 Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Mon, 5 Oct 2026 21:35:08 +0200 Subject: [PATCH] R-325 (felhom.eu half): hub_copy_gate accepts the controller gate importing the shared stem list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Once retrieval_promise_gate.py imports customer_copy_vocab and drops its STEMS literal, the drift check reads "ok — single source" instead of failing on the missing literal. An import only in a comment, or beside a stale literal, is still drift. Pinned by scripts/test_hub_copy_drift.py. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS --- scripts/hub_copy_gate.py | 19 ++++++++++++--- scripts/test_hub_copy_drift.py | 43 ++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 scripts/test_hub_copy_drift.py diff --git a/scripts/hub_copy_gate.py b/scripts/hub_copy_gate.py index 703f254b..79e4a69d 100644 --- a/scripts/hub_copy_gate.py +++ b/scripts/hub_copy_gate.py @@ -189,18 +189,31 @@ def scan_stems(): return convictions, seen -def check_drift(): +# R-325: the destination — the controller gate IMPORTS the shared list instead of carrying a literal. +# Matched at the start of a line, so an import written only in a `#` comment does not count. +_SHARED_IMPORT_RE = re.compile( + r"^(?:from\s+customer_copy_vocab\s+import\s+[^\n]*\bRETRIEVAL_STEMS\b|import\s+customer_copy_vocab\b)", re.M) + + +def check_drift(sibling=None): """The controller gate's STEMS must equal the shared list. Returns (status, message). status: "ok" | "drift" | "inconclusive" + + R-325: once the controller gate imports `customer_copy_vocab` and carries NO `STEMS` literal of its + own, the two cannot diverge and that is "ok". A literal, if present, is still compared — an import + beside a stale literal is drift. Pinned by scripts/test_hub_copy_drift.py. """ - sibling = os.path.join(os.path.dirname(_REPO), "felhom-controller", - "controller", "scripts", "retrieval_promise_gate.py") + if sibling is None: + sibling = os.path.join(os.path.dirname(_REPO), "felhom-controller", + "controller", "scripts", "retrieval_promise_gate.py") if not os.path.exists(sibling): return "inconclusive", ("the felhom-controller clone is absent, so the shared stem list " "could not be compared against the gate that also uses it (%s)" % sibling) text = open(sibling, encoding="utf-8").read() m = re.search(r"^STEMS\s*=\s*\[(.*?)\]", text, re.M | re.S) + if not m and _SHARED_IMPORT_RE.search(text): + return "ok", "controller gate imports the shared list (customer_copy_vocab.py) — single source" if not m: return "drift", "could not find a STEMS list in the controller gate — its shape changed" theirs = re.findall(r"[\"']([^\"']+)[\"']", m.group(1)) diff --git a/scripts/test_hub_copy_drift.py b/scripts/test_hub_copy_drift.py new file mode 100644 index 00000000..01f84a0b --- /dev/null +++ b/scripts/test_hub_copy_drift.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +"""R-325: hub_copy_gate.check_drift accepts the controller gate IMPORTING the shared stem list. + +Cases: a matching literal (ok), a diverged literal (drift), the import with no literal (ok — the +destination), an import that exists only in a comment (drift — the label without the fact), an import +beside a stale literal (drift), and an absent file (inconclusive, never a pass). +Run: python3 scripts/test_hub_copy_drift.py +""" +import os +import sys +import tempfile + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import hub_copy_gate as g # noqa: E402 +from customer_copy_vocab import RETRIEVAL_STEMS # noqa: E402 + +lit = "STEMS = [%s]\n" % ", ".join('"%s"' % x for x in RETRIEVAL_STEMS) +imp = "sys.path.insert(0, VOCAB_DIR)\nfrom customer_copy_vocab import RETRIEVAL_STEMS as STEMS # noqa\n" +CASES = [ + ("matching-literal", "import re\n" + lit, "ok"), + ("diverged-literal", "import re\nSTEMS = [\"visszaallithat\"]\n", "drift"), + ("imports-shared", "import re\n" + imp, "ok"), + ("import-in-comment-only", "import re\n# from customer_copy_vocab import RETRIEVAL_STEMS\n", "drift"), + ("import-beside-stale-literal", imp + "STEMS = [\"x\"]\n", "drift"), +] +fails = 0 +tmp = tempfile.mkdtemp(prefix="r325-") +for name, body, want in CASES: + p = os.path.join(tmp, name + ".py") + with open(p, "w", encoding="utf-8") as f: + f.write(body) + got, msg = g.check_drift(p) + ok = got == want + fails += not ok + print(" %s %-28s want %-12s got %s" % ("ok " if ok else "FAIL", name, want, got)) +got, _ = g.check_drift(os.path.join(tmp, "absent.py")) +if got != "inconclusive": + fails += 1 + print(" FAIL absent file -> %s, want inconclusive" % got) +else: + print(" ok absent file want inconclusive got inconclusive") +print("test_hub_copy_drift: %s" % ("FAILED" if fails else "OK")) +sys.exit(1 if fails else 0)