clay-borg/tools/edition-check.py
tegwick da58e78e4a
Some checks failed
ci / check (push) Failing after 4s
CB-REV-0002: round 2, and the corrections were not approvable either
Three FATAL, five SERIOUS. The substance of round 1's corrections held —
Reactive is genuinely one arm different, the five replacement controls are
non-inert, the inert metric is right, the numbers reproduce. What failed
were the CLAIMS about them, and two defects the corrections introduced.

FATAL 1: the fix for round 1's #11 did not fix it. The assertion was
`games + setup_fails == 200`, and a refused setup increments setup_fails
while skipping games — so the sum is invariant under exactly the failure
it claimed to catch. Injecting setup failures gave exit 0 over 196-game
columns. Now asserts games == GAMES, verified to exit 101.

FATAL 2: the correction to the selective-column FATAL was itself
selective. "81-1000 per cell, baseline AND H1" and "31-1000" twelve lines
apart, both taken from the baseline row; under H1 rank-75 arms are
59/0/0/0. Every cell is now printed rather than summarised, and the
corrected verdict is the opposite of the one it replaced: under rank-75,
H1 REDUCES DARVO arms to zero at 3p and above.

FATAL 3: "DARVO arms 2 per seat per game" is 1 per seat per game, exactly,
at every band.

SERIOUS: the tiebreak oracle asserted only that the winner set CHANGED, so
reversing the tiebreak left it green; the #13 defect's impact was claimed
and never measured (72,000 games: zero divergences — real in principle,
witnessed only by a constructed board); a 29-of-363 citation pointed at a
file that did not contain it (round 1's reviewer did report it, and it was
never transcribed — the record was wrong, not the number); the harnesses
were run by NO GATE, so every published figure came from a manual run of
an ungated binary, including the assertion added for #1; and edition-check's
sibling handling — added by the last correction — was self-certifying,
crashed instead of failing, and counted Markdown lines as coverage. Now
discovered on disk, and it found a real gap on its first run: Rules_Text.csv
vendored with no digest.

Also: "peak Stress held" was dead code kept quiet by `let _ = held;` — the
numbers were right by coincidence.

make panels is now a registered gate. Round 3 is owed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 09:44:00 +02:00

205 lines
8.2 KiB
Python
Executable file

#!/usr/bin/env python3
"""Is the vendored edition still what ground-game published? (ADR-0011 D2)
`editions/ground-darvo-r0/` is a copy of content owned by another repo.
A stale copy is worse than no copy, so the digest is committed and this
compares it.
**An absent upstream is reported absent, never as a pass.** That is the
shape ADR-0009 used for `node`: a check that cannot run says so, because
a silent skip is the class this project has found seven times.
"""
import hashlib
import os
import re
import sys
from repo import ROOT, enter_root
EDITION = "editions/ground-darvo-r0"
PROVENANCE = f"{EDITION}/PROVENANCE.md"
UPSTREAM_DIR = os.path.join(os.path.dirname(ROOT), "ground-game", EDITION)
def digest(path):
return hashlib.sha256(open(path, "rb").read()).hexdigest()
def recorded():
"""Every recorded digest, by filename.
The first version matched ONE `sha256 <hex>` and assumed it described
`Problems.csv`. ADR-0015 vendored three more files, and the check
reported the first digest against the wrong file -- a gate written for
a single-file world silently comparing across files.
"""
text = open(os.path.join(ROOT, PROVENANCE)).read()
found = dict(
(name, d)
for d, name in re.findall(r"sha256\s+([0-9a-f]{64})\s+(\S+)", text)
)
if not found:
raise ValueError(f"{PROVENANCE} records no `sha256 <hex> <file>` digests")
return found
def vendored_files():
"""Every `.csv` actually present, so a file added without a digest is
caught rather than skipped."""
d = os.path.join(ROOT, EDITION)
return sorted(f for f in os.listdir(d) if f.endswith(".csv"))
# CB-WP-0038 vendored two things that are NOT inside the edition
# directory: `editions/catalog.yaml`, which selects between packages and
# so belongs above them, and the `h1-problem-stress` experiment package.
#
# Their digests were CLAIMED by that pass and never recorded. The
# adversarial review (CB-REV-0001) could not find them and reported the
# control unverified — correctly. Recorded relative to `editions/`.
SIBLINGS = "../"
# Discovered ON DISK, not read out of PROVENANCE (CB-REV-0002 #8). The
# first version listed siblings by reading the digest block, which made
# three controls vacuous at once: a recorded-but-absent file could never
# be reported missing (it was in `present` by construction), an absent one
# raised FileNotFoundError from `digest` instead of failing with the
# designed message, and "the sibling packages are covered" counted lines
# in a Markdown file -- it passed with all three files deleted.
SIBLING_GLOBS = ("catalog.yaml", "experiments/*/rules_delta.yaml", "experiments/*/*.csv")
def sibling_files():
"""Sibling packages that are on disk, as `../`-relative paths."""
import glob as _glob
root = os.path.join(ROOT, EDITION, SIBLINGS)
out = []
for pattern in SIBLING_GLOBS:
for hit in _glob.glob(os.path.join(root, pattern)):
rel = os.path.relpath(hit, os.path.join(ROOT, EDITION))
out.append(rel.replace(os.sep, "/"))
return sorted(out)
def check():
want = recorded()
print("edition-check — vendored data against its provenance")
rc = 0
siblings = sibling_files()
present = vendored_files() + siblings
undocumented = [f for f in vendored_files() + siblings if f not in want]
if undocumented:
print(f" [FAIL] vendored with no recorded digest: {', '.join(undocumented)}")
rc = 1
missing = [f for f in want if f not in present]
if missing:
print(f" [FAIL] a digest is recorded for a file that is not here: {', '.join(missing)}")
rc = 1
for name in [f for f in present if f.endswith(".csv")]:
if name not in want:
continue
path = os.path.join(ROOT, EDITION, name)
if not os.path.exists(path):
print(f" [FAIL] {name} is recorded but not on disk")
rc = 1
continue
have = digest(path)
# `../x` resolves out of the edition dir, which is the point.
if have != want[name]:
print(f" [FAIL] {name} does not match its recorded digest")
print(f" recorded {want[name]}\n actual {have}")
rc = 1
else:
print(f" [ok ] {name} matches its recorded digest")
# ADR-0015 D3's falsifier, checked rather than asserted: the hand
# reader handles commas inside quotes and NOTHING ELSE. A doubled
# quote or an embedded newline means `csv` is the answer after all.
for name in [f for f in present if f.endswith(".csv")]:
raw = open(os.path.join(ROOT, EDITION, name), encoding="utf-8-sig").read()
if '""' in raw:
print(f" [FAIL] {name} contains a doubled quote — ADR-0011's revisit")
print(" condition has fired; the hand reader cannot parse it")
rc = 1
# An embedded newline shows up as an odd quote count on a line.
for i, line in enumerate(raw.splitlines(), 1):
if line.count('"') % 2:
print(f" [FAIL] {name}:{i} has an unbalanced quote — embedded newline?")
rc = 1
break
if rc == 0:
print(" [ok ] no doubled quotes or embedded newlines (ADR-0015 D3)")
if not os.path.isdir(UPSTREAM_DIR):
# NOT a pass and NOT a failure: the question could not be asked.
print(" [----] upstream not checked out — freshness UNVERIFIED")
print(f" expected {UPSTREAM_DIR}")
return rc
for name in [f for f in present if f.endswith(".csv")]:
up = os.path.join(UPSTREAM_DIR, name)
if not os.path.exists(up):
print(f" [FAIL] {name} is not in upstream — where did it come from?")
rc = 1
elif digest(up) != digest(os.path.join(ROOT, EDITION, name)):
print(f" [FAIL] upstream {name} has changed since it was vendored")
rc = 1
if rc == 0:
print(" [ok ] every vendored copy is current with ../ground-game")
return rc
def self_test():
"""A checker that cannot detect a mismatch is decoration."""
results = []
def chk(name, ok, detail=""):
results.append((name, ok, detail))
present = vendored_files()
want = recorded()
chk("vendored files exist", len(present) >= 4, ", ".join(present))
chk("every vendored file has a recorded digest",
all(f in want for f in present),
"a file added without a digest must fail, not be skipped")
# `present` is the edition's own CSVs plus the sibling paths recorded
# for the catalog and the experiment package (CB-WP-0038).
everything = present + sibling_files()
chk("every digest names a file that is here",
all(f in everything for f in want),
"a stale digest is a lie with a filename")
chk("digests match the real files",
all(digest(os.path.join(ROOT, EDITION, f)) == want[f] for f in everything))
chk("the sibling packages are covered",
all(f in want for f in sibling_files()) and len(sibling_files()) >= 3,
"catalog.yaml and rules_delta.yaml decide WHAT WE MEASURED; the first "
"version counted lines in PROVENANCE and passed with the files deleted")
# The control that matters: a changed byte must be detected.
import tempfile
one = present[0]
with tempfile.NamedTemporaryFile("wb", delete=False) as fh:
fh.write(open(os.path.join(ROOT, EDITION, one), "rb").read() + b"\n#tamper\n")
tampered = fh.name
chk("a tampered copy has a different digest",
digest(tampered) != want[one], "otherwise the check is decoration")
os.unlink(tampered)
# ADR-0015 D3's condition must be DETECTABLE, or asserting its absence
# in `check()` proves nothing.
chk("a doubled quote would be detected", '""' in 'a,""b""', "the pattern check itself")
chk("an unbalanced quote would be detected", 'a,"b'.count('"') % 2 == 1)
print("edition-check self-test (positive control)")
ok = True
for name, passed, det in results:
print(f" [{'ok ' if passed else 'FAIL'}] {name}" + (f"{det}" if det else ""))
ok &= passed
return 0 if ok else 1
if __name__ == "__main__":
enter_root()
raise SystemExit(self_test() if "--self-test" in sys.argv else check())