diff --git a/controller/scripts/retrieval_promise_gate.py b/controller/scripts/retrieval_promise_gate.py index 5ecf937..6d3705e 100644 --- a/controller/scripts/retrieval_promise_gate.py +++ b/controller/scripts/retrieval_promise_gate.py @@ -51,7 +51,24 @@ GO_SOURCES = [ # R-311 adds `visszanyit`: the honest new message says a customer needs support's help „a régebbi # előzményed visszanyitásához". That is the SAME claim in a fourth verb, and the docstring above # records what happens when the guard chases words instead of claims — it misses the next one. -STEMS = ["visszaállíthat", "visszaszerezhet", "visszahozhat", "visszanyit"] +# +# R-325: the list is NOT kept here. It lives ONCE in felhom.eu/scripts/customer_copy_vocab.py, which +# the hub's copy gate imports too — two copies of a word list is the R-299 defect exactly. The +# sibling clone is read the way controller_gates.py reads reuse_refs_check.py: CI clones felhom.eu +# beside this repo, and an ABSENT clone is INCONCLUSIVE (exit 2) — never a pass on an empty list. +# FELHOM_SHARED_SCRIPTS overrides the directory (the decoy suite uses it; nothing else should). +_SHARED_SCRIPTS = os.environ.get("FELHOM_SHARED_SCRIPTS") or os.path.normpath( + os.path.join(_HERE, "..", "..", "..", "felhom.eu", "scripts")) +if not os.path.isfile(os.path.join(_SHARED_SCRIPTS, "customer_copy_vocab.py")): + print("retrieval-promise gate INCONCLUSIVE: the shared vocabulary is missing (%s) — the felhom.eu " + "clone must sit beside this repo; without the stems nothing can be judged" % + os.path.join(_SHARED_SCRIPTS, "customer_copy_vocab.py")) + sys.exit(2) +sys.path.insert(0, _SHARED_SCRIPTS) +from customer_copy_vocab import RETRIEVAL_STEMS as STEMS # noqa: E402 +if not STEMS: + print("retrieval-promise gate INCONCLUSIVE: customer_copy_vocab.RETRIEVAL_STEMS is empty") + sys.exit(2) # R-564 — THE SPLIT VERB. Hungarian moves the particle after the verb when something is stressed: # „csak akkor ÁLLÍTHATÓK VISSZA", „csak a hiányzó fájlokat HOZOD VISSZA". The joined stems above never diff --git a/controller/scripts/test_gate_decoys.py b/controller/scripts/test_gate_decoys.py index e3e3dfc..76bb82c 100644 --- a/controller/scripts/test_gate_decoys.py +++ b/controller/scripts/test_gate_decoys.py @@ -39,7 +39,8 @@ COVERS = { "app-row-dedup": "hand-rolled row markup in partials/, AND a commented-out partial call", "template-id": "a JS reference to a missing id, in partials/", "secret-markup": "a secret templated into markup, in partials/", - "retrieval-promise": "an unregistered retrieval promise, in partials/", + "retrieval-promise": "an unregistered retrieval promise, in partials/; R-325: the shared vocabulary " + "absent (INCONCLUSIVE) and an invented stem in it convicting", "mojibake": "CONTROL: already walked; proves the planted file is really reachable", "debug-routes": "a live dispatcher case commented out - the button survives, the handler dies", "golden-notice": "R-410 in the other direction: an empty dir must not count as a bake", @@ -276,6 +277,53 @@ swapped("go-parity/nested-arg-ok", "i18n_go_parity.py", UPDATE_GO, _one(_R576, 'util.MsgError("update.refusal.already", fmt.Sprintf("%s,%s", f(a, b), c)), "lost the race'), expect="accept") +# --- retrieval-promise, R-325: the stems are IMPORTED from felhom.eu/scripts/customer_copy_vocab.py. --- +# Two shapes. (1) The vocabulary absent must be INCONCLUSIVE, never a pass on an empty list. +# (2) declaration-for-reachability: a gate that still carried a private literal would ignore the +# shared file. A doctored vocabulary with one invented stem, and a template using only that stem, +# must convict — proof the shared list is the one in force. +import shutil # noqa: E402 +import tempfile # noqa: E402 + + +def _retrieval_with_vocab(vocab_src): + d = tempfile.mkdtemp(prefix="r325-") + try: + if vocab_src is not None: + io.open(os.path.join(d, "customer_copy_vocab.py"), "w", encoding="utf-8").write(vocab_src) + env = dict(os.environ, FELHOM_SHARED_SCRIPTS=d) + p = subprocess.run([sys.executable, os.path.join("scripts", "retrieval_promise_gate.py")], + cwd=CTRL, env=env, capture_output=True, text=True) + return p.returncode, p.stdout + p.stderr + finally: + shutil.rmtree(d, ignore_errors=True) + + +ran += 1 +_rc, _out = _retrieval_with_vocab(None) +if _rc != 2 or "INCONCLUSIVE" not in _out: + fails.append("retrieval-promise/vocab-absent: want rc=2 INCONCLUSIVE, got rc=%d\n%s" % (_rc, _out[-300:])) +else: + print(" ok %-20s %s" % ("retrieval-promise/vocab-absent", "stays undetermined")) + +ran += 1 +_made = not os.path.isdir(SUB) +if _made: + os.makedirs(SUB) +_planted = os.path.join(SUB, "decoy-r325.html") +io.open(_planted, "w", encoding="utf-8").write(u"
Minden adatod felhomdecoyszohato marad.
\n") +try: + _rc, _out = _retrieval_with_vocab(u'RETRIEVAL_STEMS = ["visszaállíthat", "felhomdecoyszo"]\n') +finally: + os.remove(_planted) + if _made and os.path.isdir(SUB) and not os.listdir(SUB): + os.rmdir(SUB) +if _rc != 1 or "felhomdecoyszo" not in _out: + fails.append("retrieval-promise/vocab-is-live: an invented stem in the SHARED list did not convict — the " + "gate is not reading customer_copy_vocab.py (rc=%d)\n%s" % (_rc, _out[-300:])) +else: + print(" ok %-20s %s" % ("retrieval-promise/vocab-is-live", "decoy rejected")) + # --- golden-notice: R-410's decoy, in the other direction. It is ADVISORY, so rc is never the --- # --- question — what it COUNTED is. --- ran += 1