`bash CHECK-quill-draft-compliance (the artifact gate).` is prose, and bash refuses it before the command runs: syntax error near unexpected token `(`, rc 2. tools/check_lint.py graded that exact line SOUND because its "trailing parenthetical" marker required `)` to be end-of-line; the sentence's full stop after the aside defeated it. The marker now allows `[.!?,;:]?` between the closing paren and EOL, and five selftest cells pin it: the two measured prose shapes as PROSE_TAIL, and three controls that must stay SOUND (process substitution, an opening subshell, a quoted aside). The pin moves 37 -> 42 in tools/selftest_baseline.tsv, in this diff. Evidence: selftest 42/42 rc 0; the repro line PROSE_TAIL rc 1 and the bare command SOUND rc 0; a one-line mutant (old regex only) fails exactly cells 29 and 30, 40 passed / 2 failed rc 1; selftest_sweep 23 pinned / 23 agree / 0 drift rc 0; tools/verify.py --fast 12 legs, 11 pass, 0 fault, 1 skipped, rc 0. Artifact and leg-graded CHECK: wizard-work/volt/q-checkparen/.
99 lines
4.0 KiB
Python
99 lines
4.0 KiB
Python
#!/usr/bin/env python3
|
|
"""CHECK for the q-checkparen artifact: check_lint catches a trailing prose aside.
|
|
|
|
Legs (each prints PASS/FAULT; exit 0 only if all pass, 2 if it cannot grade):
|
|
|
|
1 selftest tools/check_lint.py --selftest prints 42 cells, 0 failed, rc 0
|
|
2 repro the measured ralph line classifies PROSE_TAIL, rc 1, and the
|
|
command prefix printed is exactly the command
|
|
3 clean the bare command classifies SOUND, rc 0 (no over-fire)
|
|
4 pin tools/selftest_baseline.tsv pins check_lint.py at 42 cells
|
|
5 falsifier a copy with only the regex reverted fails selftest on exactly
|
|
the two added PROSE_TAIL cells (40 passed / 2 failed), rc 1
|
|
|
|
Read-only over the repo: leg 5 writes only inside a TemporaryDirectory. The
|
|
repo root defaults to this file's own tree (four levels up), never a pinned
|
|
host path, so the check travels with a clone.
|
|
"""
|
|
import argparse
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
DEFAULT_REPO = os.path.dirname(os.path.dirname(os.path.dirname(HERE)))
|
|
|
|
REPRO = "bash CHECK-quill-draft-compliance (the artifact gate)."
|
|
CLEAN = "bash CHECK-quill-draft-compliance"
|
|
OLD = r'(re.compile(r"\s\([^()]*\)[.!?,;:]?\s*$"), "trailing parenthetical"),'
|
|
NEW = r'(re.compile(r"\s\([^()]*\)\s*$"), "trailing parenthetical"),'
|
|
|
|
|
|
def run(args, cwd=None):
|
|
p = subprocess.run(args, capture_output=True, text=True, timeout=120, cwd=cwd)
|
|
return p.returncode, (p.stdout or "") + (p.stderr or "")
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--repo", default=DEFAULT_REPO)
|
|
a = ap.parse_args()
|
|
|
|
tool = os.path.join(a.repo, "tools", "check_lint.py")
|
|
pin = os.path.join(a.repo, "tools", "selftest_baseline.tsv")
|
|
for path in (tool, pin):
|
|
if not os.path.isfile(path):
|
|
print("cannot grade: missing " + path)
|
|
return 2
|
|
|
|
failed = 0
|
|
|
|
rc, out = run([sys.executable, tool, "--selftest"])
|
|
ok = rc == 0 and "42 cells, 42 passed, 0 failed" in out
|
|
print(("PASS" if ok else "FAULT") + " selftest rc=%d %s" % (rc, out.strip().splitlines()[-1]))
|
|
failed += 0 if ok else 1
|
|
|
|
rc, out = run([sys.executable, tool, "--check", REPRO, "--fail-on-fault"])
|
|
ok = rc == 1 and out.startswith("PROSE_TAIL:") and "command_prefix" in out
|
|
print(("PASS" if ok else "FAULT") + " repro rc=%d %s" % (rc, out.strip().splitlines()[0]))
|
|
failed += 0 if ok else 1
|
|
|
|
rc, out = run([sys.executable, tool, "--check", CLEAN, "--fail-on-fault"])
|
|
ok = rc == 0 and out.startswith("SOUND:")
|
|
print(("PASS" if ok else "FAULT") + " clean rc=%d %s" % (rc, out.strip().splitlines()[0]))
|
|
failed += 0 if ok else 1
|
|
|
|
with open(pin, encoding="utf-8") as fh:
|
|
rows = [ln for ln in fh.read().splitlines()
|
|
if ln and not ln.startswith("#") and ln.split("\t")[0] == "check_lint.py"]
|
|
ok = rows == ["check_lint.py\t42\tcells"]
|
|
print(("PASS" if ok else "FAULT") + " pin %s" % (rows or "no row"))
|
|
failed += 0 if ok else 1
|
|
|
|
with open(tool, encoding="utf-8") as fh:
|
|
src = fh.read()
|
|
if src.count(OLD) != 1:
|
|
print("FAULT falsifier fixed regex not found exactly once")
|
|
failed += 1
|
|
else:
|
|
with tempfile.TemporaryDirectory(prefix="checkparen.") as tmp:
|
|
mut = os.path.join(tmp, "mutant.py")
|
|
with open(mut, "w", encoding="utf-8") as fh:
|
|
fh.write(src.replace(OLD, NEW))
|
|
rc, out = run([sys.executable, mut, "--selftest"])
|
|
tail = out.strip().splitlines()[-1]
|
|
cells = re.findall(r"cell (\d+): want PROSE_TAIL got SOUND", out)
|
|
ok = (rc == 1 and "42 cells, 40 passed, 2 failed" in out
|
|
and cells == ["29", "30"])
|
|
print(("PASS" if ok else "FAULT") + " falsifier rc=%d %s" % (rc, tail))
|
|
failed += 0 if ok else 1
|
|
|
|
print("verify_fix: %d leg(s) faulted" % failed)
|
|
return 1 if failed else 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|