gates: the today-override announces itself; malformed no longer swallowed
gates / gates (push) Successful in 15s
gates / gates (push) Successful in 15s
Part 6 of the hub-blindness task, separable and done rather than dropped. Both due_checks_gate.py and instructions_gate.py read FELHOM_GATE_TODAY so their suites can control "today", and neither said so. A shell that still has it exported -- exactly what a session doing gate-test work leaves behind -- made both gates evaluate against a fabricated date and pass in SILENCE. That is this project's own named failure class: an instrument that can quietly return the wrong answer is not a measurement. The seam is legitimate and stays; the silence was the defect. Both now print a loud line naming the variable, its value, and that the real date is being ignored, before any verdict. And instructions_gate.py no longer swallows a MALFORMED override: it used to fall through to the real date without a word while due_checks_gate.py already exited 2 on the same input -- one variable, two gates, disagreeing about what a mistake means. Both exit 2 now. Tests extended in both suites (42 and 73 assertions, green). Red-proof: the announcement was deleted from due_checks_gate.py and its two assertions were seen failing, then reverted. Also adds REPORT-hub-blindness.md (topic-suffixed; the shared REPORT.md is left alone per the parallel-session rule).
This commit is contained in:
@@ -1,3 +1,21 @@
|
||||
## due_checks_gate.py v1.0.1 + instructions_gate.py — the today-override announces itself (2026-08-18)
|
||||
|
||||
**Both gates read `FELHOM_GATE_TODAY` so their suites can control "today"; neither said so.** A shell
|
||||
that still has it exported — exactly what a session doing gate-test work leaves behind — made both
|
||||
gates evaluate against a fabricated date and pass, **silently**. That is this project's own named
|
||||
failure class: an instrument that can quietly return the wrong answer is not a measurement. The seam
|
||||
is legitimate and stays; the silence was the defect.
|
||||
|
||||
- Both gates now print a loud line naming the variable, its value, and that the real date is being
|
||||
ignored, before any verdict.
|
||||
- **`instructions_gate.py` no longer swallows a MALFORMED override.** It used to fall through to the
|
||||
real date without a word, while `due_checks_gate.py` already exited 2 on the same input — two gates
|
||||
reading one variable and disagreeing about what a mistake means. Both now exit 2.
|
||||
|
||||
Tests extended in both suites (valid → announced; malformed → exit 2). One red-proof: the
|
||||
announcement was deleted from `due_checks_gate.py` and its two assertions were seen failing, then
|
||||
reverted.
|
||||
|
||||
## due_checks_gate.py v1.0.0 — a dated check becomes a thing that bites (2026-08-18, R-341)
|
||||
|
||||
**New gate, registered as #10 in `repo_gates.py` (`--fast`).** R-341 booked two dated measurements —
|
||||
|
||||
@@ -87,10 +87,17 @@ def today_utc():
|
||||
override = os.environ.get("FELHOM_GATE_TODAY")
|
||||
if override:
|
||||
try:
|
||||
return datetime.strptime(override.strip(), "%Y-%m-%d").date()
|
||||
d = datetime.strptime(override.strip(), "%Y-%m-%d").date()
|
||||
except ValueError:
|
||||
print("DUE-CHECKS GATE INCONCLUSIVE: FELHOM_GATE_TODAY=%r is not YYYY-MM-DD" % override)
|
||||
sys.exit(2)
|
||||
# THE OVERRIDE ANNOUNCES ITSELF. A shell that still has this exported — exactly what a session
|
||||
# doing gate-test work leaves behind — would otherwise make this gate evaluate a fabricated
|
||||
# "today" and pass in silence. An instrument that can quietly return the wrong answer is not a
|
||||
# measurement, so the seam stays and is made loud.
|
||||
print("!! FELHOM_GATE_TODAY=%s IS SET — this gate is evaluating against that date, NOT "
|
||||
"today's real UTC date. Unset it for a real run." % override.strip())
|
||||
return d
|
||||
return datetime.now(timezone.utc).date()
|
||||
|
||||
|
||||
|
||||
@@ -121,12 +121,29 @@ def effective(text):
|
||||
|
||||
|
||||
def today_tuple():
|
||||
"""Local date as (y, m, d). Injectable via FELHOM_GATE_TODAY for the test suite."""
|
||||
"""Local date as (y, m, d). Injectable via FELHOM_GATE_TODAY for the test suite.
|
||||
|
||||
THE OVERRIDE ANNOUNCES ITSELF (R-339 session, 2026-08-18). It is a legitimate test seam and the
|
||||
suite depends on it — but a shell that still has it exported, which is exactly what a session
|
||||
doing gate-test work leaves behind, silently made every date comparison here evaluate against a
|
||||
fabricated day and pass. That is this project's own named failure class: an instrument that can
|
||||
quietly return the wrong answer is not a measurement. So the override is kept and made LOUD.
|
||||
|
||||
A MALFORMED override is now exit 2, not a silent fall-through to the real date. Quietly ignoring
|
||||
it means the run the operator thought they were doing is not the run that happened — and it also
|
||||
made this gate disagree with due_checks_gate.py, which already exited 2. Same seam, same rule.
|
||||
"""
|
||||
override = os.environ.get("FELHOM_GATE_TODAY")
|
||||
if override:
|
||||
m = ISO_DATE_RE.match(override.strip())
|
||||
if m:
|
||||
print("!! FELHOM_GATE_TODAY=%s IS SET — this gate is evaluating against that date, NOT "
|
||||
"today's real date. Unset it for a real run." % override.strip())
|
||||
return tuple(int(g) for g in m.groups())
|
||||
print("FAIL: FELHOM_GATE_TODAY=%r is set but is not YYYY-MM-DD." % override)
|
||||
print(" Refusing to fall back to the real date: the run you think you are doing would")
|
||||
print(" not be the run that happens. Fix or unset the variable.")
|
||||
sys.exit(2)
|
||||
import datetime
|
||||
|
||||
d = datetime.date.today()
|
||||
|
||||
@@ -211,6 +211,27 @@ def test_g_gate_is_registered_in_the_runner():
|
||||
"due_checks_gate.py" in out)
|
||||
|
||||
|
||||
|
||||
# ── Part 6 — the today-override must ANNOUNCE itself ─────────────────────────────────────────
|
||||
def test_override_announces_itself():
|
||||
"""A shell that still has FELHOM_GATE_TODAY exported must not be able to fake a run in silence."""
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
reg = make_register(tmp, HEADER + "| R-341 | 2099-01-01 | far future |\n")
|
||||
rc, out = run_gate(reg, today="2026-08-20")
|
||||
check("P6: valid override is announced", "FELHOM_GATE_TODAY=2026-08-20" in out and "IS SET" in out)
|
||||
check("P6: the announcement says the real date is being ignored",
|
||||
"NOT" in out and "real UTC date" in out)
|
||||
check("P6: announcing does not change the verdict", rc == 0, "rc=%d" % rc)
|
||||
|
||||
|
||||
def test_malformed_override_is_inconclusive_not_a_silent_fallback():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
reg = make_register(tmp, HEADER + "| R-341 | 2099-01-01 | far future |\n")
|
||||
rc, out = run_gate(reg, today="not-a-date")
|
||||
check("P6: malformed override exits 2", rc == 2, "rc=%d" % rc)
|
||||
check("P6: names the variable and the bad value", "FELHOM_GATE_TODAY" in out and "not-a-date" in out)
|
||||
|
||||
|
||||
def main():
|
||||
print("test_due_checks_gate")
|
||||
for fn in sorted((v for k, v in globals().items() if k.startswith("test_")),
|
||||
|
||||
@@ -516,6 +516,27 @@ def test_two_file_shape_still_checked_byte_identical():
|
||||
check("tally names the two-file shape", "two-file shape" in out)
|
||||
|
||||
|
||||
|
||||
# ── Part 6 — the today-override must ANNOUNCE itself, and a malformed one must not be ignored ──
|
||||
def test_override_announces_itself():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = make_repo(tmp, "# Repo\n")
|
||||
rc, out = run_gate(root, today="2026-08-06")
|
||||
check("P6: valid override is announced", "FELHOM_GATE_TODAY=2026-08-06" in out and "IS SET" in out)
|
||||
check("P6: announcing does not change the verdict", rc == 0, "rc=%d" % rc)
|
||||
|
||||
|
||||
def test_malformed_override_exits_2_instead_of_silently_using_the_real_date():
|
||||
"""It used to fall through to today's real date without a word — and disagreed with
|
||||
due_checks_gate.py, which already exited 2 on the same input. Same seam, same rule."""
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = make_repo(tmp, "# Repo\n")
|
||||
rc, out = run_gate(root, today="not-a-date")
|
||||
check("P6: malformed override exits 2", rc == 2, "rc=%d" % rc)
|
||||
check("P6: names the variable and the bad value", "FELHOM_GATE_TODAY" in out and "not-a-date" in out)
|
||||
check("P6: says it refuses to fall back", "Refusing to fall back" in out)
|
||||
|
||||
|
||||
def main():
|
||||
print("test_instructions_gate")
|
||||
for fn in sorted(
|
||||
|
||||
Reference in New Issue
Block a user