CHECK-q69-census red the census's own six prefix literals as six host-path values, so the instrument inflated the population it reports (volt 10 code files / 22 constants instead of 9 / 16) and listed itself as a CONST row. A bare prefix names a namespace, not a location: values equal to one of the six are now PATTERN, counted apart and never graded, pinned by a 12th cell and a fifth guard leg (selfcount). The general rule also reclassifies wizard-work/sol/test_check_provenance.py:160, whose only host string is an assertion needle. Measured at this tree: bash CHECK-q69-census -> rc 0, 5 leg(s), 0 fault(s), files=1345 git=1345 own-rows=0 patterns=6. Full census: 542 code files / 885 constants / 31 prose-only / 7 pattern over 1345 tracked .py; text scan 586. The record in WORK-QUEUE.md carries the post-fix readings. CHECK: bash CHECK-q69-census
295 lines
11 KiB
Python
295 lines
11 KiB
Python
#!/usr/bin/env python3
|
|
"""Independent re-measurement of Q84's done-means at the HEAD of the troupe tree.
|
|
|
|
Run as: python3 q84_verify.py [--repo PATH]
|
|
|
|
The default repo is the checkout this file lives in -- `__file__` three
|
|
parents up -- not the author's `/root/troupe-standup`, so the reading is about
|
|
the commit that carries the verifier rather than about the tree that wrote it
|
|
(Q69). `--repo` names another checkout; nothing else in this file resolves an
|
|
absolute root.
|
|
|
|
It grades four things, none of them by importing the artifact's own CHECK:
|
|
|
|
oracle an integer-set-intersection oracle (NOT the module's brute_force_pairs)
|
|
over every ordered tuple of size 0..3 drawn from intervals with
|
|
endpoints in [-2, 3] -- 9,724 tuples -- against both public entry
|
|
points, plus a seeded random pass.
|
|
cells the 12 cells in test_interval_overlap.py are collected and pass.
|
|
mutants five mutants of interval_overlap.py, each in a fresh copy of the
|
|
lane, must each be killed by a NAMED cell; a sixth unmutated copy is
|
|
the positive control (rc 0, 12 tests).
|
|
bind the cell file binds no host directory (no absolute sys.path insert)
|
|
and the module docstring's complexity claims name both entry points.
|
|
|
|
Exit 0 only when every leg passes; 2 when the subject cannot be read.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import itertools
|
|
import json
|
|
import os
|
|
import random
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
|
|
MODULE = "interval_overlap.py"
|
|
CELLS = "test_interval_overlap.py"
|
|
|
|
|
|
def read(path):
|
|
with open(path, "r", encoding="utf-8") as fh:
|
|
return fh.read()
|
|
|
|
|
|
def load_module(path_text, name="interval_overlap_probe"):
|
|
"""Load the subject from its source text, so no host copy can shadow it."""
|
|
mod = type(sys)(name)
|
|
mod.__dict__["__file__"] = "<source>"
|
|
mod.__dict__["__name__"] = name
|
|
exec(compile(path_text, "<subject>", "exec"), mod.__dict__)
|
|
return mod
|
|
|
|
|
|
# --------------------------------------------------------------------- oracle
|
|
|
|
def domain(low=-2, high=3):
|
|
return [(s, e) for s in range(low, high + 1) for e in range(s, high + 1)]
|
|
|
|
|
|
def oracle_pairs(ivs):
|
|
"""Definition, not a sweep: non-empty integer sets, intersect iff non-empty."""
|
|
sets = [set(range(s, e)) for (s, e) in ivs]
|
|
out = []
|
|
for i in range(len(sets)):
|
|
for j in range(i + 1, len(sets)):
|
|
if sets[i] & sets[j]:
|
|
out.append((i, j))
|
|
return out
|
|
|
|
|
|
def leg_oracle(mod, seen):
|
|
iv = domain()
|
|
cases = 0
|
|
bad = []
|
|
for k in range(0, 4):
|
|
for combo in itertools.product(iv, repeat=k):
|
|
cases += 1
|
|
want = oracle_pairs(combo)
|
|
got = mod.find_overlapping_pairs(list(combo))
|
|
if got != want:
|
|
bad.append((combo, got, want))
|
|
if len(bad) > 3:
|
|
break
|
|
bent = bool(want)
|
|
gotb = mod.has_any_overlap(list(combo))
|
|
if gotb != bent:
|
|
bad.append((combo, "has_any_overlap", gotb, bent))
|
|
if len(bad) > 3:
|
|
break
|
|
if len(bad) > 3:
|
|
break
|
|
rng = random.Random(20261104)
|
|
rand_cases = 0
|
|
for _ in range(3000):
|
|
n = rng.randint(0, 12)
|
|
combo = []
|
|
for _ in range(n):
|
|
a = rng.randint(-5, 5)
|
|
combo.append((a, a + rng.randint(0, 6)))
|
|
rand_cases += 1
|
|
want = oracle_pairs(combo)
|
|
if mod.find_overlapping_pairs(list(combo)) != want or mod.has_any_overlap(list(combo)) != bool(want):
|
|
bad.append((combo, "random", mod.find_overlapping_pairs(list(combo)), want))
|
|
break
|
|
seen["cases"] = cases
|
|
seen["random_cases"] = rand_cases
|
|
if bad:
|
|
print(f" FAIL oracle: {len(bad)} mismatch(es), first {bad[0]}")
|
|
return 1
|
|
print(f" OK oracle: {cases} exhaustive tuple(s) + {rand_cases} seeded random, 0 mismatch")
|
|
return 0
|
|
|
|
|
|
# ---------------------------------------------------------------------- cells
|
|
|
|
def run_cells(lane, pattern="test_interval_overlap"):
|
|
proc = subprocess.run(
|
|
[sys.executable, "-m", "unittest", pattern],
|
|
cwd=lane, capture_output=True, text=True, timeout=900,
|
|
)
|
|
out = proc.stdout + proc.stderr
|
|
ran = re.search(r"^Ran (\d+) test", out, re.M)
|
|
failed = re.findall(r"^(FAIL|ERROR): (\S+)", out, re.M)
|
|
return proc.returncode, (int(ran.group(1)) if ran else 0), failed, out
|
|
|
|
|
|
def leg_cells(lane, seen):
|
|
rc, ran, failed, out = run_cells(lane)
|
|
seen["cells_ran"] = ran
|
|
if rc != 0 or ran != 12:
|
|
print(f" FAIL cells: rc={rc} ran={ran} failed={[f[1] for f in failed]}")
|
|
return 1
|
|
print(f" OK cells: Ran {ran} tests, rc 0, 0 failures")
|
|
return 0
|
|
|
|
|
|
# -------------------------------------------------------------------- mutants
|
|
|
|
MUTANTS = [
|
|
("M1-kind-order-flipped", [
|
|
("events.append((s, 1, idx))", "events.append((s, 0, idx))"),
|
|
("events.append((e, 0, idx))", "events.append((e, 1, idx))"),
|
|
], "test_half_open_adjacency_both_orders"),
|
|
("M2-zero-length-skip-removed", [
|
|
(" if s >= e: # zero-length interval: empty set, never overlaps\n continue\n",
|
|
" pass\n"),
|
|
], "test_zero_length_against_wide_interval"),
|
|
("M3-start-pair-loop-removed", [
|
|
(" for other in active:\n a, b = (idx, other) if idx < other else (other, idx)\n pairs.add((a, b))\n",
|
|
" pass\n"),
|
|
], "test_nested_and_disjoint_pairs"),
|
|
("M4-has-any-overlap-reverted", [
|
|
(" iv = list(intervals)\n for s, e in iv:\n if e < s:\n raise ValueError(f\"end < start: {(s, e)}\")\n # Sorted by start",
|
|
" return bool(find_overlapping_pairs(intervals))\n iv = list(intervals)\n for s, e in iv:\n if e < s:\n raise ValueError(f\"end < start: {(s, e)}\")\n # Sorted by start"),
|
|
], "test_has_any_overlap_does_not_build_pair_list"),
|
|
("M5-early-exit-boundary", [
|
|
("if max_end is not None and s < max_end:", "if max_end is not None and s <= max_end:"),
|
|
], "test_has_any_overlap_true_and_false"),
|
|
]
|
|
|
|
|
|
def _make_lane(dest, src_text, test_text):
|
|
"""A lane holding only the subject and its cells -- nothing else can answer."""
|
|
os.makedirs(dest, exist_ok=True)
|
|
with open(os.path.join(dest, MODULE), "w", encoding="utf-8") as fh:
|
|
fh.write(src_text)
|
|
with open(os.path.join(dest, CELLS), "w", encoding="utf-8") as fh:
|
|
fh.write(test_text)
|
|
|
|
|
|
def leg_mutants(src_text, test_text, seen):
|
|
faults = 0
|
|
rows = []
|
|
with tempfile.TemporaryDirectory(prefix="q84mut-") as tmp:
|
|
# positive control: an unmutated copy of the pair
|
|
ctl = os.path.join(tmp, "control")
|
|
_make_lane(ctl, src_text, test_text)
|
|
rc, ran, failed, _ = run_cells(ctl)
|
|
rows.append({"mutant": "control", "rc": rc, "ran": ran, "dead": []})
|
|
if rc != 0 or ran != 12:
|
|
print(f" FAIL mutants/control: rc={rc} ran={ran} -- the lane copy is not green")
|
|
faults += 1
|
|
else:
|
|
print(f" OK mutants/control: rc 0, Ran {ran}, 0 failures")
|
|
for name, edits, must_die in MUTANTS:
|
|
text = src_text
|
|
applied = 0
|
|
for old, new in edits:
|
|
if text.count(old) != 1:
|
|
break
|
|
text = text.replace(old, new)
|
|
applied += 1
|
|
tree = os.path.join(tmp, name)
|
|
_make_lane(tree, text, test_text)
|
|
rc, ran, failed, out = run_cells(tree)
|
|
dead = sorted({f[1] for f in failed})
|
|
killed = rc != 0 and must_die in dead
|
|
rows.append({"mutant": name, "edits_applied": applied, "rc": rc,
|
|
"ran": ran, "dead": dead, "must_die": must_die,
|
|
"killed_by_named_cell": killed})
|
|
if not killed:
|
|
faults += 1
|
|
print(f" {'OK ' if killed else 'FAIL'} {name}: rc={rc} named-cell-dead={must_die in dead} dead={len(dead)}")
|
|
seen["mutants"] = rows
|
|
return faults
|
|
|
|
|
|
# ----------------------------------------------------------------------- bind
|
|
|
|
def leg_bind(test_text, module_text, seen):
|
|
faults = 0
|
|
flat = " ".join(module_text.split())
|
|
quoted = re.findall(r'^sys\.path\.insert\(0,\s*[\'"]/', test_text, re.M)
|
|
seen["host_binds"] = len(quoted)
|
|
if quoted:
|
|
print(f" FAIL bind: {len(quoted)} absolute sys.path insert(s) in {CELLS}")
|
|
faults += 1
|
|
else:
|
|
print(" OK bind: no absolute sys.path insert in the cell file")
|
|
for needle in ("find_overlapping_pairs", "has_any_overlap"):
|
|
if needle not in flat:
|
|
print(f" FAIL bind: docstring does not name {needle}")
|
|
faults += 1
|
|
if "O(n log n + k)" not in flat or "in O(n log n) and stops at the first" not in flat:
|
|
print(" FAIL bind: complexity claims absent from the docstring")
|
|
faults += 1
|
|
else:
|
|
print(" OK bind: docstring names both entry points and both complexity bounds")
|
|
return faults
|
|
|
|
|
|
def default_repo():
|
|
"""The checkout this file lives in: wizard-work/volt/q84-closure/<here>."""
|
|
return os.path.dirname(os.path.dirname(os.path.dirname(
|
|
os.path.dirname(os.path.abspath(__file__)))))
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--repo", default=default_repo())
|
|
ap.add_argument("--json", default="")
|
|
ap.add_argument("--poison", default="",
|
|
help="write a copy of the pair into <dir>/wizard-work/beam with "
|
|
"has_any_overlap reverted to bool(find_overlapping_pairs(...)), "
|
|
"then exit; used by CHECK-q84's falsifiability leg")
|
|
args = ap.parse_args()
|
|
lane = os.path.join(args.repo, "wizard-work", "beam")
|
|
mod_path = os.path.join(lane, MODULE)
|
|
cells_path = os.path.join(lane, CELLS)
|
|
if not (os.path.isfile(mod_path) and os.path.isfile(cells_path)):
|
|
print(f"rc 2: subject unreadable at {lane}")
|
|
return 2
|
|
src_text = read(mod_path)
|
|
test_text = read(cells_path)
|
|
|
|
if args.poison:
|
|
old, new = MUTANTS[3][1][0]
|
|
if src_text.count(old) != 1:
|
|
print("rc 2: the poison edit does not apply to this source")
|
|
return 2
|
|
dest = os.path.join(args.poison, "wizard-work", "beam")
|
|
_make_lane(dest, src_text.replace(old, new), test_text)
|
|
print(f"poisoned lane written: {dest} ({MUTANTS[3][0]})")
|
|
return 0
|
|
|
|
print(f"q84 verify -- {args.repo}")
|
|
print(f" subject: {MODULE} {len(src_text)}B cells: {CELLS}")
|
|
|
|
seen = {}
|
|
faults = 0
|
|
faults += leg_bind(test_text, src_text, seen)
|
|
mod = load_module(src_text)
|
|
faults += leg_oracle(mod, seen)
|
|
faults += leg_cells(lane, seen)
|
|
faults += leg_mutants(src_text, test_text, seen)
|
|
|
|
verdict = "PASS" if faults == 0 else "FAIL"
|
|
print(f"q84 verify: {verdict} -- {faults} fault(s)")
|
|
if args.json:
|
|
killed = sum(1 for r in seen.get("mutants", [])
|
|
if r.get("killed_by_named_cell"))
|
|
with open(args.json, "w", encoding="utf-8") as fh:
|
|
json.dump({"verdict": verdict, "faults": faults,
|
|
"mutants_killed": killed, **seen}, fh, indent=2, default=str)
|
|
print(f"wrote {args.json}")
|
|
return 0 if faults == 0 else 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|