test(v1-gate): the attestation's date, form and writer, as red tests — a future date, a +14:00 offset and a duplicated key all read green

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-18 18:11:42 +02:00
commit cd6fb4302e
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q

View file

@ -18,6 +18,7 @@ import os
import shutil import shutil
import subprocess import subprocess
import sys import sys
from datetime import datetime, timezone
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any
@ -841,19 +842,223 @@ def test_m7_the_attestation_file_is_pinned() -> None:
def test_m7_the_gate_never_writes_an_attestation(tmp_path: Path) -> None: def test_m7_the_gate_never_writes_an_attestation(tmp_path: Path) -> None:
"""The file is the operator's word. A product that can produce one has produced a witness to """The file is the operator's word. A product that can produce one has produced a witness to
its own run, which is the whole thing rows 1-2 cannot do: so no source file in the package its own run, which is the whole thing rows 1-2 cannot do. Measured as BEHAVIOUR for the whole
writes ``ATTEST_FILE``, and scoring a tree leaves none behind.""" package (18.09, PM): every entry point runs against an unattested but otherwise consistent
root = _unattested(_green_rounds(tmp_path)) round directory, and none may leave an attestation behind. A grep for the file name reads a
gate.score_rounds(root, 3, _AI) name, and a writer called from ``render`` or the command line slipped past it."""
gate.score_changes(root, 3, _AI) root = _unattested(_green_rounds(tmp_path / "rounds"))
assert list(root.rglob(_ATTEST_FILE)) == [] config = json.loads(json.dumps(_CONFIG))
writes = [ config["maf_points"]["points"] = _one_point([6])["points"]
f"{path.name}:{i}" entries: dict[str, Any] = {
for path in sorted((_REPO / "src" / "portfolio_optimiser").rglob("*.py")) "score_rounds": lambda: gate.score_rounds(root, 3, _AI),
for i, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1) "score_changes": lambda: gate.score_changes(root, 3, _AI),
if _ATTEST_FILE in line and "write_text" in line "score_kept": lambda: gate.score_kept(root, 0.8, _AI),
] "read_attestation": lambda: [gate.read_attestation(root / str(n)) for n in range(4)],
assert writes == [] "evaluate+render": lambda: gate.render(
gate.evaluate(
rounds_dir=root,
config=config,
repo_root=_REPO,
src=_synthetic_src(tmp_path / "src"),
probe_runner=_all_pass,
stress_measure=_CLEAN,
)
),
}
for name, entry in entries.items():
entry()
assert list(root.rglob(_ATTEST_FILE)) == [], name
for flags in ((), ("--json",)):
proc = _cli("--rounds-dir", str(root), *flags)
assert proc.returncode == 1, proc.stderr
assert list(root.rglob(_ATTEST_FILE)) == [], ("cli", flags)
# ---------------------------------------------------------------------------------------------
# M-8 — what the attestation's DATE and FORM may say (PM checkpoint 18.09 of 1b48124)
# ---------------------------------------------------------------------------------------------
_NOW = datetime(2026, 5, 29, 12, 0, tzinfo=timezone.utc)
def _both_rows(root: Path, now: datetime | None = None) -> list[gate.Row]:
return [gate.score_rounds(root, 3, _AI, now=now), gate.score_changes(root, 3, _AI, now=now)]
def test_m8_the_baseline_stays_green_on_the_injected_clock(tmp_path: Path) -> None:
"""Positive control for everything below: the same tree, the clock on the fixture day."""
rows = _both_rows(_green_rounds(tmp_path), _NOW)
assert [(r.k, r.status) for r in rows] == [(3, gate.GREEN)] * 2, rows
@pytest.mark.parametrize(
"given",
["2026-05-30", "3000-01-01", "2026-05-29T23:00:00-05:00"],
)
def test_m8_an_attestation_dated_in_the_future_is_red(tmp_path: Path, given: str) -> None:
"""Finding 1: ``dato: 3000-01-01`` on every round read GREEN — the check only asked whether
the date was before the run. The last case is a future INSTANT written in a west-of-UTC
offset, so its wall-clock date is still today."""
root = _green_rounds(tmp_path)
_attest(root / "1", on=given)
for row in _both_rows(root, _NOW):
assert (row.k, row.status) == (2, gate.RED), (given, row.exceptions)
assert any("i framtiden" in x for x in row.exceptions), row.exceptions
def test_m8_the_clock_is_a_parameter_and_the_default_is_the_real_one(tmp_path: Path) -> None:
root = _green_rounds(tmp_path)
_attest(root / "1", on="3000-01-01")
assert gate.score_rounds(root, 3, _AI).status == gate.RED # the real clock, no injection
@pytest.mark.parametrize(
"given",
["2026-05-29T00:00:00+14:00", "2026-05-28T10:00:00+00:00", "2026-05-28T20:26:00+00:00"],
)
def test_m8_a_timezone_cannot_date_an_attestation_before_the_run(
tmp_path: Path, given: str
) -> None:
"""Finding 2: ``2026-05-29T00:00:00+14:00`` is 2026-05-28T10:00Z, ten hours BEFORE the run
(20:26Z), and read GREEN because only the wall-clock date was compared. A date that carries a
time is compared as the instant it is."""
root = _green_rounds(tmp_path)
_attest(root / "1", on=given)
for row in _both_rows(root, _NOW):
assert (row.k, row.status) == (2, gate.RED), (given, row.exceptions)
assert any("før kjøringen" in x for x in row.exceptions), row.exceptions
def test_m8_a_time_without_an_offset_is_ambiguous_and_red(tmp_path: Path) -> None:
root = _green_rounds(tmp_path)
_attest(root / "1", on="2026-05-29T10:00:00")
row = gate.score_rounds(root, 3, _AI, now=_NOW)
assert (row.k, row.status) == (2, gate.RED), row.exceptions
assert any("tidssone" in x for x in row.exceptions), row.exceptions
@pytest.mark.parametrize("given", ["2026-05-29T08:00:00+02:00", "2026-05-29T00:00:00+00:00"])
def test_m8_an_instant_after_the_run_and_before_now_is_green(tmp_path: Path, given: str) -> None:
root = _green_rounds(tmp_path)
_attest(root / "1", on=given)
for row in _both_rows(root, _NOW):
assert (row.k, row.status) == (3, gate.GREEN), (given, row.exceptions)
def test_m8_a_plain_date_keeps_the_same_day_rule(tmp_path: Path) -> None:
"""Same day as the run, and same day as ``now``, cannot be told apart from a date alone — so
it passes, and the contract text says so."""
root = _green_rounds(tmp_path)
_attest(root / "1", on="2026-05-28") # the run's own day
assert gate.score_rounds(root, 3, _AI, now=_NOW).status == gate.GREEN
_attest(root / "1", on="2026-05-29") # today
assert gate.score_rounds(root, 3, _AI, now=_NOW).status == gate.GREEN
assert "samme dag" in gate.ATTEST_RULE
_BODY = {"runde": "runde: 1", "kjøring": "kjøring: r1", "dato": "dato: 2026-05-29"}
@pytest.mark.parametrize("key", ["runde", "kjøring", "dato"])
@pytest.mark.parametrize("first_is_right", [True, False])
def test_m8_a_key_written_twice_is_red_in_either_order(
tmp_path: Path, key: str, first_is_right: bool
) -> None:
"""Finding 3: ``runde: 1`` then ``runde: 2`` was GREEN and the reverse RED — first-wins by
accident, and a last-wins mutant survived the whole suite. Two answers to one question are
not an answer, whichever comes first."""
root = _green_rounds(tmp_path)
wrong = {"runde": "runde: 2", "kjøring": "kjøring: r9", "dato": "dato: 2020-01-01"}[key]
pair = [_BODY[key], wrong] if first_is_right else [wrong, _BODY[key]]
lines = [x for k, x in _BODY.items() if k != key] + pair
_write(root / "1" / _ATTEST_FILE, "\n".join(lines) + "\n")
for row in _both_rows(root, _NOW):
assert (row.k, row.status) == (2, gate.RED), row.exceptions
assert any("to ganger" in x for x in row.exceptions), row.exceptions
def test_m8_even_the_same_value_twice_is_red(tmp_path: Path) -> None:
root = _green_rounds(tmp_path)
_write(root / "1" / _ATTEST_FILE, "\n".join([*_BODY.values(), _BODY["runde"]]) + "\n")
assert gate.score_rounds(root, 3, _AI, now=_NOW).status == gate.RED
def test_m8_a_byte_order_mark_is_tolerated(tmp_path: Path) -> None:
"""Finding 5a: a real file from an ordinary editor may start with a BOM, which made the first
key read as a different word and the round RED. The person is not wrong; the gate tolerates
it."""
root = _green_rounds(tmp_path)
text = "\n".join(_BODY.values()) + "\n"
(root / "1" / _ATTEST_FILE).write_bytes(b"\xef\xbb\xbf" + text.encode("utf-8"))
for row in _both_rows(root, _NOW):
assert (row.k, row.status) == (3, gate.GREEN), row.exceptions
def test_m8_an_attestation_that_is_a_directory_is_red_not_missing(tmp_path: Path) -> None:
"""Finding 5b: a directory named like the file is something PUT there — not the same as
nobody having confirmed yet."""
root = _green_rounds(tmp_path)
(root / "1" / _ATTEST_FILE).unlink()
(root / "1" / _ATTEST_FILE).mkdir()
for row in _both_rows(root, _NOW):
assert (row.k, row.status) == (2, gate.RED), row.exceptions
assert any("vanlig fil" in x for x in row.exceptions), row.exceptions
@pytest.mark.parametrize("target", ["valid", "dangling"])
def test_m8_an_attestation_that_is_a_symlink_is_red(tmp_path: Path, target: str) -> None:
"""Finding 5c: F4 refuses a linked outbox, and ``is_file()`` followed the same link here. What
a forger gains is nothing (the content binds), but the asymmetry was unmeasured."""
root = _green_rounds(tmp_path / "rounds")
elsewhere = tmp_path / "elsewhere.txt"
if target == "valid":
elsewhere.write_text("\n".join(_BODY.values()) + "\n", encoding="utf-8")
(root / "1" / _ATTEST_FILE).unlink()
(root / "1" / _ATTEST_FILE).symlink_to(elsewhere)
for row in _both_rows(root, _NOW):
assert (row.k, row.status) == (2, gate.RED), (target, row.exceptions)
assert any("lenke" in x for x in row.exceptions), row.exceptions
def test_m8_a_hard_link_is_a_declared_limit_not_a_rule(tmp_path: Path) -> None:
"""Chosen 18.09: a hard link is NOT refused, and the output says so. Nothing in the tree marks
where it points, ``cp -l`` and some backup tools make them innocently, and refusing would gain
nothing the attestation's content binds round, run and date either way."""
root = _green_rounds(tmp_path / "rounds")
outside = tmp_path / "outside.txt"
outside.write_text("\n".join(_BODY.values()) + "\n", encoding="utf-8")
(root / "1" / _ATTEST_FILE).unlink()
os.link(outside, root / "1" / _ATTEST_FILE)
assert gate.score_rounds(root, 3, _AI, now=_NOW).status == gate.GREEN
assert "hardlenke" in gate.ATTEST_RULE
def test_m8_an_attestation_that_is_not_utf8_is_red_because_it_is_unreadable(
tmp_path: Path,
) -> None:
"""Finding 6: the ``except`` arm on the read was uncovered — a whole-file garbage input goes
RED anyway through the missing keys, so a lenient decode (``errors="ignore"``) survived. Here
the three keyed lines are perfect and ONE stray byte follows: only strictness can refuse it."""
root = _green_rounds(tmp_path)
good = ("\n".join(_BODY.values()) + "\n").encode("utf-8")
(root / "1" / _ATTEST_FILE).write_bytes(good + b"merknad \xff\xfe\n")
for row in _both_rows(root, _NOW):
assert (row.k, row.status) == (2, gate.RED), row.exceptions
assert any("uleselig" in x for x in row.exceptions), row.exceptions
def test_m8_the_output_says_the_stress_row_needs_the_untracked_scratchpad() -> None:
"""Finding 7: row 7's 1 of 20 stands on ``scratchpad/`` being present. Without it the row is
NOT MEASURED, and that dependency is a fact about the checkout, not about the product."""
assert "scratchpad" in gate.STRESS_DEPENDENCY and "IKKE MÅLT" in gate.STRESS_DEPENDENCY
rows = gate.evaluate(
rounds_dir=Path("/nonexistent"),
config=_CONFIG,
repo_root=_REPO,
probe_runner=_all_pass,
stress_measure=_CLEAN,
)
assert gate.STRESS_DEPENDENCY in gate.render(rows)
def _outcome_obj(rows: list[dict[str, Any]], removed: dict[str, set[str]] | None = None) -> Any: def _outcome_obj(rows: list[dict[str, Any]], removed: dict[str, set[str]] | None = None) -> Any: