R-426: due-checks gate gets decoys; exemption removed

Four cases in test_gate_decoys.py, planted inside the real DUE-CHECKS block:
an orphaned check whose id survives only in prose, the due-TODAY boundary with
due-tomorrow as the genuine article (today pinned via FELHOM_GATE_TODAY to a
date before every real check), and the block's marker named in prose (exit 2).
Each convicting decoy was seen to PASS under a mutation of the gate (row match
loosened to the bare id; `<=` to `<`; duplicate-marker refusal removed). The
gate itself is unchanged — no hole found. EXEMPT drops `felhom.eu/due-checks`.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-06 01:08:23 +02:00
parent c6c6cb7676
commit dc9ecba9bf
2 changed files with 57 additions and 3 deletions
-3
View File
@@ -36,9 +36,6 @@ EXEMPT = {
("felhom.eu", "one-register"):
"R-424 — a real defect parked under state `idea` is invisible. Declared in the gate's own "
"docstring as residual hole 1; the decoy passes today.",
("felhom.eu", "due-checks"):
"R-426 — no legitimate decoy constructed; the attempt in the sweep was a no-op and its "
"verdict was withdrawn rather than reported.",
# felhom-controller
("felhom-controller", "docker-v"):
"COVERED IN THE SWEEP, not yet in a suite: an unallowlisted `-v` host path in a new Go file "
+57
View File
@@ -74,6 +74,8 @@ COVERS = {
"controller clone must be INCONCLUSIVE, never a pass"),
"hostinstall": ("R-426: R-185's regression with only its dry-run echo left, the age install commented "
"out, and a version const in a new hub sub-package; a comment naming the identifier passes"),
"due-checks": ("R-426: a dated check whose id survives only in prose (orphan), the due-TODAY boundary "
"(and due-tomorrow, which must pass), and the block's marker named in prose (exit 2)"),
"hub-copy": ("R-558: an English retrieval promise in the NEW bundle (the sentences moved "
"out of templates.go, so the surface list had to move with them), the same "
"in Hungarian, and an INNOCENT control using the identical verbs without the "
@@ -437,6 +439,61 @@ decoy("hostinstall/comment-names-identifier", "hostinstall_gates.py",
u'package zzr426decoy\n\n// hostInstallVersion was deleted on purpose (R-94).\n'),
expect="accept")
# ── due-checks (R-426, 2026-10-06) ──────────────────────────────────────────────────────────────
#
# The 2026-09-01 sweep's attempt was a no-op and was withdrawn. These are the shapes a session really
# produces in the DUE-CHECKS block of OPEN-ITEMS.md:
# * the label without the row: a dated check whose R-number appears in the register only in PROSE
# ("merged into …") — its row is gone, so the check is orphaned and must convict;
# * the boundary: a check due TODAY is due (the docstring's `<=` rule), and one due TOMORROW is not —
# both directions, with "today" pinned through the gate's own FELHOM_GATE_TODAY seam;
# * the block's marker named in prose elsewhere in the register: two markers are two sources of
# truth, and the gate must refuse to guess (exit 2) rather than read one of them.
# "Today" is pinned to 2026-01-01 — BEFORE every real dated check — so the real rows stay pending and only
# the planted row decides the verdict. The id of an EXISTING row is read from the register at run time, so the boundary decoys cannot turn
# into orphan decoys when a row closes.
_DC_END = u"<!-- DUE-CHECKS-END -->"
def _dc_live_id():
for line in io.open(_OPEN_REG, encoding="utf-8"):
m = re.match(r"^\| \*\*(R-\d+[a-z]?)\*\* \|", line)
if m:
return m.group(1)
def _dc_plant(row, today=None, prose=u""):
inner = replace_in(_OPEN_REG, _DC_END, row + u"\n" + _DC_END)
def _plant():
undo = inner()
if prose:
io.open(_OPEN_REG, "a", encoding="utf-8").write(prose)
old = os.environ.get("FELHOM_GATE_TODAY")
if today:
os.environ["FELHOM_GATE_TODAY"] = today
def _clean():
undo()
if old is None:
os.environ.pop("FELHOM_GATE_TODAY", None)
else:
os.environ["FELHOM_GATE_TODAY"] = old
return _clean
return _plant
decoy("due-checks/orphan-named-in-prose", "due_checks_gate.py",
_dc_plant(u"| R-99426 | 2099-01-01 | a far-future check whose row was merged away |",
prose=u"\nNote: R-99426 was merged into another row on 2026-10-06.\n"))
decoy("due-checks/due-today", "due_checks_gate.py",
_dc_plant(u"| %s | 2026-01-01 | the boundary decoy |" % _dc_live_id(), today="2026-01-01"))
decoy("due-checks/due-tomorrow", "due_checks_gate.py",
_dc_plant(u"| %s | 2026-01-02 | the boundary genuine article |" % _dc_live_id(), today="2026-01-01"),
expect="accept")
decoy("due-checks/marker-named-in-prose", "due_checks_gate.py",
_dc_plant(u"", prose=u"\nThe dated checks sit between the DUE-CHECKS-BEGIN and DUE-CHECKS-END markers.\n"))
# ── script-tests (R-885) ─────────────────────────────────────────────────────────────────────────
#
# Its decoys are whole fake repos, so they live in their own file and are RUN from here (guide-quote's shape).