Q60 enforcement check v1 (Zeph lane): population recount with head+exclusions, per-token recovery, complete-but-wrong leg, 5-cell selftest
This commit is contained in:
1 parent
3712524b90
commit
36c6bbab57
1 file changed
+238
@@ -0,0 +1,238 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Q60 enforcement check (Zeph lane, 2026-10-26).
|
||||
|
||||
Implements the narrowed Q60 residue from reply 100 section 6 and the
|
||||
WORK-QUEUE.md Q60 addendum: the census half is landed; this is the check half.
|
||||
|
||||
What it does, on a checkout at a NAMED head:
|
||||
1. Population: count truncated-identifier occurrences / distinct tokens /
|
||||
files under the pinned pattern ``[0-9a-f]{8,}(-[0-9a-f]{4})*-…``.
|
||||
The head and the exclusion list are printed beside every number, because
|
||||
a recount at the head that carries the report re-counts the report itself
|
||||
(reply 100 section 2: 77/19 at 0d294b8 collapses to 49/17 once the census
|
||||
file and the check-in that quotes it are excluded). Occurrence and
|
||||
distinct counts are printed side by side, because the 31 -> 35 -> 16
|
||||
drift was an occurrence/distinct confusion and the distinct count was
|
||||
constant at 16 (reply 100 section 3).
|
||||
2. Recovery: for each distinct truncated stem, look for a longer string in
|
||||
the tree (same exclusions) beginning with that stem. Stems with no
|
||||
in-tree longer string fall back to the KNOWN tables below, which are
|
||||
census rows (in-tree recoveries) and reply-100 section 4 (external
|
||||
recoveries). A stem in neither place FAILS the gate: it is a new
|
||||
unrecovered identifier-subject token.
|
||||
3. Complete-but-wrong: any full UUID-shaped value in the tree whose first
|
||||
8 hex chars match a KNOWN full value's prefix but whose value differs
|
||||
FAILS the gate. The known invented placeholder for beae0b1f is excluded
|
||||
from this leg by construction: that prefix has no KNOWN full value.
|
||||
|
||||
Exit status: 0 when no FAIL line is printed, 1 otherwise.
|
||||
``--selftest`` builds fixture trees and asserts the negative cells: an
|
||||
unknown truncated token fails, a complete-but-wrong value fails, and a
|
||||
self-quoting report file excluded from the population collapses the count.
|
||||
|
||||
Usage:
|
||||
python3 q60_enforce.py --tree <checkout-path> [--exclude <relpath> ...]
|
||||
python3 q60_enforce.py --selftest
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
TRUNC_RE = re.compile("([0-9a-f]{8,}(?:-[0-9a-f]{4})*)-\u2026")
|
||||
FULL_RE = re.compile(
|
||||
r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
|
||||
)
|
||||
# Longer-string search: a UUID-shaped continuation of the stem (one or more
|
||||
# hyphen groups of 4-12 hex, so the 8-4-4-4-12 shape matches in full).
|
||||
# The truncated form itself (stem + hyphen, before the ellipsis) must NOT
|
||||
# count: a bare "stem-" is not a longer string.
|
||||
LONG_RE_TEMPLATE = r"{stem}(-[0-9a-f]{{4,12}})+"
|
||||
|
||||
# Census in-tree recoveries (recoveries/truncated-identifier-census.md rows
|
||||
# 2, 3, 4, 6, 7, 8, 10, 13, 14, 15), keyed by first 8 hex chars.
|
||||
KNOWN_IN_TREE = {
|
||||
"3d79ba82": "3d79ba82-926b-48c0-9d15-8791a364ea81",
|
||||
"34413f8d": "34413f8d-26bf-4bbc-8ade-eb309a0e2245",
|
||||
"a92b55d0": "a92b55d0-1d36-4884-8e65-f456450b3a74",
|
||||
"3c67f712": "3c67f712-697d-48d8-b05c-01be896e61da",
|
||||
"29ba0d51": "29ba0d51-2d9f-412e-ad19-5f28a76ca96e",
|
||||
"e33f87f8": "e33f87f8-88ec-4e1a-9a13-df9bbb1d8120",
|
||||
"6ec57334": "6ec57334-604d-42b5-a2e7-54662739c504",
|
||||
"51a65c2c": "51a65c2c-07dd-4307-aba6-f7c4af17311c",
|
||||
"20c08939": "20c08939-56c2-4351-a47a-efcdf022eca5",
|
||||
"18a809aa": "18a809aa-0b7f-4523-ac0e-508c9f0f6f66",
|
||||
}
|
||||
|
||||
# External recoveries (reply 100 section 4, Timmy's fetches, 2026-10-25).
|
||||
KNOWN_EXTERNAL = {
|
||||
"6b5089a8": "6b5089a8-2daf-4b4e-a739-bcf762cfe29a",
|
||||
"10dfc8bc": "10dfc8bc-99ad-4ca2-ab76-853cb90a92c2",
|
||||
"a90cdb7c": "a90cdb7c-1c33-4fca-9a96-26c236006f14",
|
||||
"6c573a9c": "6c573a9c-1d6f-4ae6-a93e-ff79868456f4",
|
||||
"67cbefc2": "67cbefc2-d94f-4f31-9e6e-b6210a60ad5e",
|
||||
}
|
||||
|
||||
KNOWN_FULL = dict(KNOWN_IN_TREE)
|
||||
KNOWN_FULL.update(KNOWN_EXTERNAL)
|
||||
|
||||
# Terminal justified-unrecovered state (reply 100 section 4): exhausted by
|
||||
# full-history pickaxe, and the only longer string anywhere is Timmy's
|
||||
# invented placeholder, which is not a recovery and must not count as one.
|
||||
KNOWN_UNRECOVERED = {"beae0b1f"}
|
||||
PLACEHOLDER = "beae0b1f-0000-0000-0000-000000000000"
|
||||
|
||||
|
||||
def list_files(tree):
|
||||
"""Tracked files if tree is a git checkout, else every file under it."""
|
||||
git_dir = os.path.join(tree, ".git")
|
||||
if os.path.isdir(git_dir) or os.path.isfile(git_dir):
|
||||
out = subprocess.run(
|
||||
["git", "-C", tree, "ls-files"],
|
||||
capture_output=True, text=True, check=True,
|
||||
)
|
||||
return [p for p in out.stdout.splitlines() if p]
|
||||
found = []
|
||||
for root, _dirs, names in os.walk(tree):
|
||||
for name in names:
|
||||
found.append(os.path.relpath(os.path.join(root, name), tree))
|
||||
return sorted(found)
|
||||
|
||||
|
||||
def read_text(path):
|
||||
with open(path, "r", encoding="utf-8", errors="replace") as fh:
|
||||
return fh.read()
|
||||
|
||||
|
||||
def head_of(tree):
|
||||
try:
|
||||
out = subprocess.run(
|
||||
["git", "-C", tree, "rev-parse", "HEAD"],
|
||||
capture_output=True, text=True, check=True,
|
||||
)
|
||||
return out.stdout.strip()
|
||||
except Exception:
|
||||
return "(not a git checkout)"
|
||||
|
||||
|
||||
def run_check(tree, excludes):
|
||||
"""Return (report_lines, failed_bool). Pure function over the tree."""
|
||||
lines = []
|
||||
failed = False
|
||||
head = head_of(tree)
|
||||
lines.append("HEAD=%s" % head)
|
||||
lines.append("EXCLUDE=%s" % ",".join(excludes) if excludes else "EXCLUDE=(none)")
|
||||
files = [f for f in list_files(tree) if f not in set(excludes)]
|
||||
contents = {}
|
||||
for rel in files:
|
||||
try:
|
||||
contents[rel] = read_text(os.path.join(tree, rel))
|
||||
except OSError:
|
||||
continue
|
||||
occ = 0
|
||||
per_token = {}
|
||||
files_with = set()
|
||||
for rel, text in contents.items():
|
||||
for m in TRUNC_RE.finditer(text):
|
||||
occ += 1
|
||||
per_token.setdefault(m.group(1), []).append(rel)
|
||||
files_with.add(rel)
|
||||
lines.append("OCC=%d DISTINCT=%d FILES=%d" % (occ, len(per_token), len(files_with)))
|
||||
# Recovery + complete-but-wrong, per distinct stem.
|
||||
for stem in sorted(per_token):
|
||||
stem8 = stem[:8]
|
||||
longer = None
|
||||
if stem8 not in KNOWN_UNRECOVERED:
|
||||
pat = re.compile(LONG_RE_TEMPLATE.format(stem=re.escape(stem)))
|
||||
for rel, text in contents.items():
|
||||
for m in pat.finditer(text):
|
||||
cand = m.group(0)
|
||||
if cand != PLACEHOLDER:
|
||||
longer = (cand, rel)
|
||||
break
|
||||
if longer:
|
||||
break
|
||||
if longer:
|
||||
lines.append("TOKEN %s: RECOVERED-IN-TREE %s at %s" % (stem, longer[0], longer[1]))
|
||||
elif stem8 in KNOWN_EXTERNAL:
|
||||
lines.append("TOKEN %s: RECOVERED-EXTERNAL %s (reply 100 s4)" % (stem, KNOWN_EXTERNAL[stem8]))
|
||||
elif stem8 in KNOWN_IN_TREE:
|
||||
lines.append("TOKEN %s: RECOVERED-IN-TREE-KNOWN %s" % (stem, KNOWN_IN_TREE[stem8]))
|
||||
elif stem8 in KNOWN_UNRECOVERED:
|
||||
lines.append("TOKEN %s: UNRECOVERED-JUSTIFIED (exhausted; placeholder is not a recovery)" % stem)
|
||||
else:
|
||||
lines.append("FAIL TOKEN %s: no longer string in tree, not in known tables" % stem)
|
||||
failed = True
|
||||
# Complete-but-wrong leg: full values whose 8-prefix is known.
|
||||
for rel, text in contents.items():
|
||||
for val in set(FULL_RE.findall(text)):
|
||||
prefix = val[:8]
|
||||
if prefix in KNOWN_FULL and val != KNOWN_FULL[prefix]:
|
||||
lines.append("FAIL COMPLETE-BUT-WRONG %s at %s (known %s)" % (val, rel, KNOWN_FULL[prefix]))
|
||||
failed = True
|
||||
lines.append("VERDICT=%s" % ("FAIL" if failed else "PASS"))
|
||||
return lines, failed
|
||||
|
||||
|
||||
def selftest():
|
||||
"""Fixture trees; each cell asserts a behaviour, not a tautology."""
|
||||
passed = []
|
||||
|
||||
def check(tree, excludes, want_fail, label):
|
||||
_lines, failed = run_check(tree, excludes)
|
||||
assert failed == want_fail, "%s: want fail=%s" % (label, want_fail)
|
||||
passed.append(label)
|
||||
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
# Cell 1: clean tree passes (one harmless abbreviation + its full value).
|
||||
with open(os.path.join(d, "a.md"), "w") as fh:
|
||||
fh.write("see 3d79ba82-\u2026 and full 3d79ba82-926b-48c0-9d15-8791a364ea81\n")
|
||||
check(d, [], False, "clean-tree-passes")
|
||||
# Cell 2: a self-quoting report excluded collapses the count.
|
||||
with open(os.path.join(d, "report.md"), "w") as fh:
|
||||
fh.write("3d79ba82-\u2026 3d79ba82-\u2026 3d79ba82-\u2026\n")
|
||||
lines, _ = run_check(d, [])
|
||||
assert any(l.startswith("OCC=4 ") for l in lines), "self-quote counted without exclusion"
|
||||
lines, _ = run_check(d, ["report.md"])
|
||||
assert any(l.startswith("OCC=1 ") for l in lines), "exclusion did not collapse count"
|
||||
passed.append("self-quotation-excluded")
|
||||
# Cell 3: unknown truncated token fails.
|
||||
with open(os.path.join(d, "b.md"), "w") as fh:
|
||||
fh.write("dead link deadbeef-\u2026 with no longer string\n")
|
||||
check(d, ["report.md"], True, "unknown-token-fails")
|
||||
os.remove(os.path.join(d, "b.md"))
|
||||
# Cell 4: complete-but-wrong fails (same prefix, different suffix).
|
||||
with open(os.path.join(d, "c.md"), "w") as fh:
|
||||
fh.write("3d79ba82-1111-2222-3333-444444444444\n")
|
||||
check(d, ["report.md"], True, "complete-but-wrong-fails")
|
||||
os.remove(os.path.join(d, "c.md"))
|
||||
# Cell 5: justified-unrecovered placeholder does not count as recovery
|
||||
# and does not fail.
|
||||
with open(os.path.join(d, "e.md"), "w") as fh:
|
||||
fh.write("beae0b1f-\u2026 and placeholder beae0b1f-0000-0000-0000-000000000000\n")
|
||||
check(d, ["report.md"], False, "placeholder-not-a-recovery")
|
||||
for label in passed:
|
||||
print("SELFTEST PASS %s" % label)
|
||||
print("SELFTEST: %d cells passed, 0 failed" % len(passed))
|
||||
return 0
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--tree", default=".")
|
||||
ap.add_argument("--exclude", action="append", default=[])
|
||||
ap.add_argument("--selftest", action="store_true")
|
||||
args = ap.parse_args(argv)
|
||||
if args.selftest:
|
||||
return selftest()
|
||||
lines, failed = run_check(args.tree, args.exclude)
|
||||
for line in lines:
|
||||
print(line)
|
||||
return 1 if failed else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in new issue
Block a user