ADR-0011 decided it: vendor the CSV with a checked digest, read it with a ~50-line reader, and let the hashes move. The declaration's constraint was measured against the WRONG BUDGET. It said a CSV crate costs 21,613 against AM-4a's 3,798 of headroom, '5.7x over, settled by measurement'. But setup and problem_priorities are cfg(scenarios) and are not in the shipped runtime at all, so AM-4a never sees them. Against AM-4b, csv costs 17,651 against 19,742 -- it FITS, with 2,091 to spare. It is refused anyway, on proportion: 89% of the budget's remaining capacity to read 20 rows. The revisit condition is stated (nested quoting, embedded newlines, multiple dialects). GR-S01 now deals Surface + hidden 1..=k as ruled, with edition values and suits. Measured: 6/9/12 available against thresholds 5/7/9 -- the game is winnable at every seat count, which is what the maintainer could not do. gd0001 is INVERTED, not deleted, and now also asserts the 6/9/12 so a deal that is reachable for the wrong reason still fails. Blast radius was scenario expectations, exactly as the ADR predicted: no scenario pinned a hash and no bundle is committed. Six scenarios and two unit tests updated, each with a note. gr-e01-threshold-unreachable-2p is RENAMED to -reachable- and rewritten as the non-provisional import check ground-game asked for by name. gr-e03's setup was restructured, not just renumbered: with values 2,2,2 its personal-edge test would have tied three ways and asserted nothing. BLOCKING: AM-7 fails at median 0.845 against its 0.9 floor. Isolated across three runs -- 3 problems + stand-in 0.97, 3 problems + edition 0.909, 4 problems + edition 0.845. State is BOUNDED (proven: identical after 5k and 100k events), so this is not the unbounded-growth defect AM-7 exists to catch; it is a bigger working set streaming a long log. Whether AM-7's floor is still right for a larger aggregate is a spec question and lowering it requires an ADR, so it is not being tuned here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
93 lines
3.3 KiB
Python
Executable file
93 lines
3.3 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
|
|
|
|
VENDORED = "editions/ground-darvo-r0/Problems.csv"
|
|
PROVENANCE = "editions/ground-darvo-r0/PROVENANCE.md"
|
|
UPSTREAM = os.path.join(os.path.dirname(ROOT), "ground-game", VENDORED)
|
|
|
|
|
|
def digest(path):
|
|
return hashlib.sha256(open(path, "rb").read()).hexdigest()
|
|
|
|
|
|
def recorded():
|
|
text = open(os.path.join(ROOT, PROVENANCE)).read()
|
|
m = re.search(r"sha256\s+([0-9a-f]{64})", text)
|
|
if not m:
|
|
raise ValueError(f"{PROVENANCE} records no sha256 digest")
|
|
return m.group(1)
|
|
|
|
|
|
def check():
|
|
have = digest(os.path.join(ROOT, VENDORED))
|
|
want = recorded()
|
|
print("edition-check — vendored data against its provenance")
|
|
if have != want:
|
|
print(f" [FAIL] {VENDORED} does not match its recorded digest")
|
|
print(f" recorded {want}\n actual {have}")
|
|
return 1
|
|
print(f" [ok ] vendored copy matches its recorded digest")
|
|
|
|
if not os.path.exists(UPSTREAM):
|
|
# NOT a pass and NOT a failure: the question could not be asked.
|
|
print(" [----] upstream not checked out — freshness UNVERIFIED")
|
|
print(f" expected {UPSTREAM}")
|
|
return 0
|
|
up = digest(UPSTREAM)
|
|
if up != have:
|
|
print(" [FAIL] upstream has changed since this copy was vendored")
|
|
print(f" upstream {up}\n vendored {have}")
|
|
print(" ground-game froze point_value and required_solution")
|
|
print(" within r0 — a change here is a new revision, or a")
|
|
print(" contract violation worth raising.")
|
|
return 1
|
|
print(" [ok ] vendored copy is current with ../ground-game")
|
|
return 0
|
|
|
|
|
|
def self_test():
|
|
"""A checker that cannot detect a mismatch is decoration."""
|
|
results = []
|
|
|
|
def chk(name, ok, detail=""):
|
|
results.append((name, ok, detail))
|
|
|
|
chk("the vendored file exists", os.path.exists(os.path.join(ROOT, VENDORED)))
|
|
chk("provenance records a digest", len(recorded()) == 64)
|
|
chk("digest of the real file matches provenance",
|
|
digest(os.path.join(ROOT, VENDORED)) == recorded())
|
|
# The control that matters: a changed byte must be detected.
|
|
import tempfile
|
|
with tempfile.NamedTemporaryFile("wb", delete=False) as fh:
|
|
fh.write(open(os.path.join(ROOT, VENDORED), "rb").read() + b"\n#tamper\n")
|
|
tampered = fh.name
|
|
chk("a tampered copy has a different digest",
|
|
digest(tampered) != recorded(), "otherwise the check is decoration")
|
|
os.unlink(tampered)
|
|
|
|
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())
|