sol: verify probe-set classification (4 files READY) + commit classification files

This commit is contained in:
sol committed 2026-10-31 03:35:54 +00:00
1 parent 607c2125d2
commit 93fa377b65
8 files changed
+1020

No files matched your search

+471
View File
@@ -0,0 +1,471 @@
#!/usr/bin/env python3
"""Q60 — census of truncated identifiers in the archive, and the grading of each one.
A truncated identifier is a token written as a prefix followed by an ellipsis: `beae0b1f-…`.
This tool does three things, and prints its own matcher for each.
census every truncated token in the tracked tree at a rev, by file:line, with the counts in both
units the archive keeps confusing: occurrences and distinct tokens.
table the same measurement rendered as the markdown table the queue item asks for.
check re-measure everything and grade a written table against it. A row naming a token the
census does not contain, a row that grades a token differently from the measurement, or a
census token with no row is a fault. This is the artifact's CHECK line.
rule the item's enforcement clause, measured instead of stated: every line that carries a
truncated token *and* a probe/deadness verdict (`→ 200`, `404`, `URL DEAD`, `dead link`,
`no longer resolves`) is graded by whether the address it attributes that verdict to is
written. CARRIES when the full value is on the line; RECOVERABLE when the value survives
elsewhere in the tree or in history (the row can be repaired now, so it is a fault);
EXHAUSTED when it survives nowhere (the row is Testimony only, graded at write time and
not repaired later by inference). `--baseline` is the ledger: a fault row a reader has
already reviewed, printed on every run with its owner, never dropped in silence.
Search ladder for one token, in order, all of it printed per token:
S1 tree full UUID-shaped values in every tracked file at the rev
S2 extend a longer prefix on record -- the same leading group followed by more hex and an
ellipsis: a site that narrowed the truncation without completing it
S3 history `git log --all -S<prefix>` -> every commit whose patch mentions the prefix, then the
full UUID shape re-scanned in each such commit's tree
Scope is the archive: tracked bytes at the rev. An untracked file on this host is not a record, so it
cannot make a row checkable; the worktree was swept separately, by hand, in the artifact's report.
One pass over the tree: blobs are read through `git ls-tree` + `git cat-file --batch` rather than one
`git grep` per token, because the per-token extension pattern walked this repository for 180 s
without finishing (unbounded `(-[0-9a-f]{4,})*` backtracks on a line holding a long hex run and no
ellipsis). The quantifiers here are bounded.
Exit codes follow the tools/ contract: 0 clean, 1 ran and graded a fault, 2 could not grade.
"""
from __future__ import annotations
import argparse
import os
import re
import subprocess
import sys
ELL = "\u2026"
DOGS = "..."
CANON_RE = r"[0-9a-f]{6,12}(?:-[0-9a-f]{1,12}){0,3}-" + ELL
ANY_RE = r"[0-9a-f]{6,12}(?:-[0-9a-f]{1,12}){0,3}-(?:" + ELL + r"|\.\.\.)"
CANON = re.compile(CANON_RE)
ANY = re.compile(ANY_RE)
UUID_RE = r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
UUID = re.compile(UUID_RE)
# The verdict vocabulary for `rule`, printed by the tool so a reader can audit what fired. A row
# that attributes a read to an address is only as checkable as the address it writes; these are the
# shapes this archive uses to attribute a read. The status-code pattern excludes a digit or a dash
# on either side so `$150–200/hr` is not a status, while `(200 re-check`, `→ 200` and `200, 37,412 B`
# are. Every cue that fired on a row is printed with the row.
VERDICT_CUES = (
("status", re.compile(r"(?<![\$0-9\u2013-])\b(?:200|201|204|301|302|304|400|403|404|410|429|500|502|503)\b(?![0-9])")),
("URL-DEAD", re.compile(r"\bURL[\s-]*DEAD\b", re.I)),
("dead-link", re.compile(r"\bdead[\s-]link\b", re.I)),
("no-longer-resolves", re.compile(r"no longer (?:resolves|resolving)", re.I)),
("does-not-resolve", re.compile(r"(?:does not|doesn't|did not) (?:resolve|resolves)", re.I)),
)
# A truncated token written *inside* a URL-ish token: `jobs.micro1.ai/post/3d79ba82-…`. Advisory
# only -- `rule` grades it, `census`/`table` do not depend on it.
URL_CTX = re.compile(r"(?:[A-Za-z0-9_.:-]+/)+[A-Za-z0-9_./:%-]*$")
RULE_CLASSES = ("CARRIES", "RECOVERABLE", "RECOVERABLE-HIST", "EXHAUSTED")
def git(repo, *args):
p = subprocess.run(["git", *args], cwd=repo, capture_output=True, text=True)
if p.returncode != 0:
raise SystemExit(f"cannot grade: git {' '.join(args)} rc={p.returncode}: "
f"{p.stderr.strip()[:300]}")
return p.stdout
def iter_tree(repo, rev):
"""Yield (path, lineno, text) for every text line of every tracked file at `rev`, one pass."""
listing = git(repo, "ls-tree", "-r", "-z", "--full-tree", rev)
entries = []
for chunk in listing.split("\0"):
if not chunk:
continue
meta, path = chunk.split("\t", 1)
mode, otype, sha = meta.split()
if otype == "blob" and mode in ("100644", "100755"):
entries.append((sha, path))
if not entries:
raise SystemExit(f"cannot grade: no blobs at {rev}")
proc = subprocess.Popen(["git", "cat-file", "--batch"], cwd=repo,
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
stdin = b"".join(sha.encode() + b"\n" for sha, _ in entries)
out, _ = proc.communicate(stdin)
pos = 0
for sha, path in entries:
nl = out.index(b"\n", pos)
header = out[pos:nl].split()
size = int(header[2])
blob = out[nl + 1: nl + 1 + size]
pos = nl + 1 + size + 1
if b"\x00" in blob:
continue
for i, line in enumerate(blob.decode("utf-8", "replace").splitlines(), 1):
yield path, i, line
def measure(repo, rev):
trunc = [] # [(path, lineno, token)] -- canonical: prefix-… as the item defines it
uuid_index = {} # first 8 hex -> [(path, lineno, uuid)]
ext_index = {} # first 8 hex -> [(path, lineno, written)] -- same id, more hex, still cut
text_of = {} # (path, lineno) -> line text, only for lines carrying a canonical token
for path, lineno, line in iter_tree(repo, rev):
canon_spans = []
for m in CANON.finditer(line):
tok = m.group(0)
trunc.append((path, lineno, tok))
canon_spans.append((m.start(), m.end()))
if canon_spans:
text_of[(path, lineno)] = line
for m in UUID.finditer(line):
uuid_index.setdefault(m.group(0)[:8], []).append((path, lineno, m.group(0)))
for m in ANY.finditer(line):
written = m.group(0)
if written.count("-") < 2:
continue # leading group + ellipsis only: already a canonical token above
ext_index.setdefault(written.split("-")[0], []).append((path, lineno, written))
tokens = sorted({t for _, _, t in trunc})
sites = {}
for path, lineno, token in trunc:
sites.setdefault(token, []).append((path, lineno))
files = sorted({p for p, _, _ in trunc})
return trunc, tokens, sites, uuid_index, ext_index, files, text_of
def prefix_of(token):
return token.split("-")[0]
def placeholder(uuid):
"""True for a UUID-shaped string that is not a value: all-zero groups, or a repeated character.
`beae0b1f-0000-0000-0000-000000000000` is on record at
`replies/2026-10-24-to-zephyrus-86.md:12` as the near-miss probe whose 404 proves nothing. It
has the prefix, it is a syntactically valid UUID, and it is not a completion; promoting it to
"full value present" is the exact failure the queue item calls out, so the classifier refuses it
by shape rather than by the judgement of whoever wrote the row.
"""
body = uuid.replace("-", "")
return len(set(body)) <= 2 or all(set(g) == {"0"} for g in uuid.split("-")[1:])
def history(repo, prefix):
out = git(repo, "log", "--all", "-S" + prefix, "--format=%H %s")
return [ln for ln in out.splitlines() if ln.strip()]
def history_full(repo, prefix, commits):
pat = prefix + r"-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
real, fake = [], []
for line in commits:
sha = line.split()[0]
p = subprocess.run(["git", "grep", "-nE", "-a", pat, sha, "--", "."],
cwd=repo, capture_output=True, text=True)
if p.returncode == 0:
for row in p.stdout.splitlines():
parts = row.split(":", 3)
if len(parts) != 4:
continue
found = UUID.search(parts[3])
if not found:
continue
rec = (sha[:12], parts[1], int(parts[2]), found.group(0))
(fake if placeholder(found.group(0)) else real).append(rec)
return real, fake
def resolve(repo, tokens, uuid_index, ext_index):
out = {}
for token in tokens:
p = prefix_of(token)
candidates = [r for r in uuid_index.get(p, []) if r[2].startswith(p)]
full = [r for r in candidates if not placeholder(r[2])]
fake = [r for r in candidates if placeholder(r[2])]
ext = [r for r in ext_index.get(p, []) if r[2] != token]
commits = [] if full else history(repo, p)
hist, hist_fake = history_full(repo, p, commits) if commits else ([], [])
if full:
grade = "FULL"
elif hist:
grade = "HIST"
else:
grade = "UNRECOVERED"
out[token] = {"sites": [], "full": full, "fake": fake, "ext": ext,
"commits": commits, "hist": hist, "hist_fake": hist_fake, "grade": grade}
return out
def fmt_sites(sites):
return " · ".join(f"`{p}:{n}`" for p, n in sites)
def fmt_grade(token, info):
if info["grade"] == "FULL":
where = " · ".join(f"`{p}:{n}`" for p, n, _ in info["full"])
return f"full value present at {where} (`{info['full'][0][2]}`)"
if info["grade"] == "HIST":
where = " · ".join(f"`{c}:{p}:{n}`" for c, p, n, _ in info["hist"])
return f"full value present at {where} (historic tree, not at HEAD)"
bits = []
if info["ext"]:
bits.append("prefix extended, still truncated: " + " · ".join(
f"`{p}:{n}` → `{t}`" for p, n, t in info["ext"]))
if info["fake"]:
bits.append("S1 tree: only placeholder " + " · ".join(
f"`{p}:{n}` = `{u}` (not a completion)" for p, n, u in info["fake"]))
else:
bits.append("S1 tree: no full UUID with this prefix at any path at this rev")
hist_fake = info.get("hist_fake") or []
bits.append(f"S3 history: `git log --all -S{prefix_of(token)}` → "
f"{len(info['commits'])} commit(s) whose patch mentions the prefix; "
+ ("only placeholders in their trees"
if hist_fake else "no full value in any of their trees"))
return "**Unrecovered** — " + "; ".join(bits)
def cmd_census(args, repo):
trunc, tokens, sites, uuid_index, ext_index, files, _text = measure(repo, args.rev)
print(f"matcher: git grep -nE '{CANON_RE}' {args.rev} -- . (canonical: ellipsis only)")
print(f"rev {args.rev}: {len(trunc)} occurrence(s), {len(tokens)} distinct token(s), "
f"{len(files)} file(s)")
info = resolve(repo, tokens, uuid_index, ext_index)
for token in tokens:
i = info[token]
print(f"\n{token} [{i['grade']}] {len(sites[token])} site(s)")
for path, lineno in sites[token]:
print(f" {path}:{lineno}")
for path, lineno, uuid in i["full"]:
print(f" FULL {path}:{lineno} {uuid}")
for path, lineno, uuid in i["fake"]:
print(f" FAKE {path}:{lineno} {uuid} (placeholder, not a completion)")
for path, lineno, written in i["ext"]:
print(f" EXT {path}:{lineno} {written}")
print(f" hist {len(i['commits'])} commit(s)")
return 0
def cmd_table(args, repo):
trunc, tokens, sites, uuid_index, ext_index, files, _text = measure(repo, args.rev)
info = resolve(repo, tokens, uuid_index, ext_index)
lines = [f"<!-- generated: wizard-work/volt/q60_truncated_census.py table "
f"--rev {args.rev} -->",
"",
f"Census at `{args.rev}`: **{len(trunc)} occurrences / {len(tokens)} distinct "
f"tokens / {len(files)} files**.",
"",
"| token (as written) | file:line sites | grading |",
"|---|---|---|"]
for token in tokens:
info[token]["sites"] = sites[token]
lines.append(f"| `{token}` | {fmt_sites(sites[token])} | {fmt_grade(token, info[token])} |")
text = "\n".join(lines) + "\n"
if args.out:
with open(args.out, "w", encoding="utf-8") as fh:
fh.write(text)
print(f"wrote {args.out}: {len(tokens)} row(s)")
else:
sys.stdout.write(text)
return 0
ROW_RE = re.compile(r"^\| `([0-9a-f]{6,12}(?:-[0-9a-f]{1,12})*-\u2026)` \| (.*?) \| (.*) \|$")
def cmd_check(args, repo):
try:
with open(args.table, "r", encoding="utf-8") as fh:
text = fh.read()
except OSError as exc:
print(f"cannot grade: {args.table}: {exc}", file=sys.stderr)
return 2
trunc, tokens, sites, uuid_index, ext_index, files, _text = measure(repo, args.rev)
info = resolve(repo, tokens, uuid_index, ext_index)
rows = {}
for line in text.splitlines():
m = ROW_RE.match(line.strip())
if not m:
continue
if m.group(1) in rows:
print(f"FAULT duplicate row for {m.group(1)}", file=sys.stderr)
return 1
rows[m.group(1)] = (m.group(2), m.group(3))
problems = []
for token in tokens:
if token not in rows:
problems.append(f"missing row: {token}")
continue
sites_cell, grade_cell = rows[token]
for path, lineno in sites[token]:
if f"`{path}:{lineno}`" not in sites_cell:
problems.append(f"{token}: site not named in row: {path}:{lineno}")
g = info[token]["grade"]
if g == "FULL":
if "Unrecovered" in grade_cell:
problems.append(f"{token}: measured FULL, row says Unrecovered")
for path, lineno, _ in info[token]["full"]:
if f"`{path}:{lineno}`" not in grade_cell:
problems.append(f"{token}: full value at {path}:{lineno} not graded present")
else:
if "Unrecovered" not in grade_cell:
problems.append(f"{token}: measured {g}, row does not say Unrecovered")
if "full value present" in grade_cell:
problems.append(f"{token}: measured {g}, row claims a full value")
for path, lineno, _ in info[token]["fake"]:
if f"`{path}:{lineno}`" not in grade_cell:
problems.append(f"{token}: placeholder at {path}:{lineno} not named as one")
for token in rows:
if token not in tokens:
problems.append(f"row names a token the census does not contain: {token}")
if problems:
print(f"q60 truncated census: {len(problems)} fault(s) against {args.table} "
f"({len(tokens)} token(s) measured at {args.rev})", file=sys.stderr)
for p in problems:
print(f" {p}", file=sys.stderr)
return 1
full = sum(1 for t in tokens if info[t]["grade"] == "FULL")
print(f"q60 truncated census: {len(tokens)} token(s) at {args.rev}, {len(rows)} row(s), "
f"{full} full / {len(tokens) - full} Unrecovered — every row's site list and grading "
f"agrees with a fresh measurement")
return 0
def rule_rows(repo, rev):
"""One row per (line, token) where the line attributes a read and writes the address truncated."""
trunc, tokens, sites, uuid_index, ext_index, files, text_of = measure(repo, rev)
info = resolve(repo, tokens, uuid_index, ext_index)
out = []
for (path, lineno), line in sorted(text_of.items()):
cues = sorted({name for name, rx in VERDICT_CUES if rx.search(line)})
if not cues:
continue
full_on_line = {u[:8] for u in
(m.group(0) for m in UUID.finditer(line)) if not placeholder(u)}
for m in CANON.finditer(line):
tok = m.group(0)
p = prefix_of(tok)
i = info[tok]
if p in full_on_line:
cls = "CARRIES"
where = [r for r in i["full"] if r[0] == path and r[1] == lineno] or i["full"]
elif i["full"]:
cls = "RECOVERABLE"
where = i["full"]
elif i.get("hist"):
cls = "RECOVERABLE-HIST"
where = [("{}:{}:{}".format(c.split()[0][:12], pp, nn), pp, nn, uu)
for c, pp, nn, uu in i["hist"]]
else:
cls = "EXHAUSTED"
where = []
in_url = bool(URL_CTX.search(line[:m.start()]))
out.append({"path": path, "line": lineno, "token": tok, "cues": cues,
"class": cls, "where": where, "in_url": in_url, "text": line.strip()})
return out, tokens, info
def load_rule_baseline(path):
"""`<path>:<line>\\t<token>\\t<CLASS>\\t<owner> -- <reason>`; blank lines and # comments ignored."""
rows = {}
with open(path, "r", encoding="utf-8") as fh:
for raw in fh:
line = raw.rstrip("\n")
if not line.strip() or line.lstrip().startswith("#"):
continue
parts = line.split("\t")
if len(parts) < 4:
raise SystemExit(f"cannot grade: baseline row needs 4 fields, got {len(parts)}: {line!r}")
key, tok, cls, note = parts[0], parts[1], parts[2], parts[3]
if cls not in RULE_CLASSES:
raise SystemExit(f"cannot grade: baseline class {cls!r} not in {RULE_CLASSES}")
rows[(key, tok)] = (cls, note)
return rows
def cmd_rule(args, repo):
rows, tokens, info = rule_rows(repo, args.rev)
print("matcher: cue vocabulary = " + ", ".join(f"{n}({rx.pattern})" for n, rx in VERDICT_CUES))
print(f"rev {args.rev}: {len(rows)} verdict occurrence(s) on "
f"{len({(r['path'], r['line']) for r in rows})} line(s), "
f"{len({r['token'] for r in rows})} distinct token(s), "
f"{len({r['path'] for r in rows})} file(s)\n")
baseline = load_rule_baseline(args.baseline) if args.baseline else {}
faults, tolerated, cleared = [], [], []
for r in rows:
key = (f"{r['path']}:{r['line']}", r["token"])
where = ""
if r["where"]:
sites = " · ".join(f"`{p}:{n}`" for p, n, *_ in r["where"][:6])
val = ""
if r["where"] and len(r["where"][0]) == 4:
val = f" (`{r['where'][0][3]}`)"
where = f" — value at {sites}{val}"
flag = " url-context" if r["in_url"] else ""
body = f"{r['path']}:{r['line']} `{r['token']}` cues={{{','.join(r['cues'])}}}{flag}"
head = f"{r['class']:<16} {body}"
if r["class"] in ("RECOVERABLE", "RECOVERABLE-HIST", "EXHAUSTED"):
if key in baseline:
cls, note = baseline[key]
mark = "KNOWN" if cls == r["class"] else f"DRIFT({cls})"
tolerated.append((mark, body, where, note))
else:
faults.append((head, where))
else:
print(head + where)
for mark, body, where, note in tolerated:
print(f"{mark:<16} {body}{where}\n baseline: {note}")
print()
for key, (cls, note) in sorted(baseline.items()):
if not any((f"{r['path']}:{r['line']}", r["token"]) == key
and r["class"] in ("RECOVERABLE", "RECOVERABLE-HIST", "EXHAUSTED") for r in rows):
cleared.append((key, cls, note))
for (key, tok), cls, note in cleared:
print(f"STALE baseline row names no measured fault row: {key} `{tok}` ({cls})")
tally = {}
for r in rows:
tally[r["class"]] = tally.get(r["class"], 0) + 1
counts = " / ".join(f"{c} {tally.get(c, 0)}" for c in RULE_CLASSES)
print(f"rule: {counts}; {len(tolerated)} tolerated in the baseline, "
f"{len(faults)} new fault(s), {len(cleared)} stale baseline row(s)")
if faults:
print("\nNEW FAULTS — a verdict row whose address is not written and whose value survives:", file=sys.stderr)
for head, where in faults:
print(f" {head}{where}", file=sys.stderr)
return 1
if cleared:
print("FAULT: a baseline row outlives the row it tolerates", file=sys.stderr)
return 1
return 0
def main(argv=None):
ap = argparse.ArgumentParser(
description="Q60 census of truncated identifiers; see the module docstring.")
ap.add_argument("--repo", default=".")
ap.add_argument("--rev", default="HEAD")
sub = ap.add_subparsers(dest="cmd", required=True)
sub.add_parser("census")
t = sub.add_parser("table")
t.add_argument("--out", default=None)
c = sub.add_parser("check")
c.add_argument("table")
r = sub.add_parser("rule")
r.add_argument("--baseline", default=None)
args = ap.parse_args(argv)
repo = os.path.abspath(args.repo)
if args.cmd == "census":
return cmd_census(args, repo)
if args.cmd == "table":
return cmd_table(args, repo)
if args.cmd == "rule":
return cmd_rule(args, repo)
return cmd_check(args, repo)
if __name__ == "__main__":
sys.exit(main())
+129
View File
@@ -0,0 +1,129 @@
#!/usr/bin/env python3
"""q93_axis_negative_probe.py -- Q93's two negative cells, at the AXIS level.
Q93 (2026-10-27) changed the malformed-input axis of `tools/selftest_sweep.py`
from PROSE grading to CONTRACT grading, and gave the run one verdict line whose
text and exit code come from the same function. A green axis after such a change
proves only that the corpus agrees with the new rule; it does not prove the axis
can still FAIL. This probe supplies the two negative shapes Q93 asks for, through
the real subprocess path (`discover` -> `read_axis` -> `report_read`), against
scratch copies of `tools/`:
A answers-zero : a tool that exits 0 on a malformed input
EXPECT rc 1, malformed-input 1 fault, verdict RC_WRONG,
and `citation_hash_class.py/not-a-repo` named on the summary
line (Q93: UNEXPLAINED never appears unnamed).
B odd-prose : a tool that refuses correctly at rc 2 with prose no table
ever pinned
EXPECT rc 0, 0 fault -- the axis grades the contract, so a
sound refusal with different wording is no longer red. Under
the pre-Q93 table this same tool was UNEXPLAINED, which is
the defect: the axis would have gone green only if the tool's
message were degraded to match a pinned phrase.
Root is resolved from this file (`wizard-work/volt/` -> repo root), not written
down, so a second checkout re-verifies itself. Scratch copies live under $TMPDIR
and are removed. No file in the working tree is modified.
rc 0 both shapes behaved as stated (the axis can fail, and for the right reason)
rc 1 a shape behaved differently: the axis is blind, or still grades wording
rc 2 could not grade: no selftest_sweep.py, no tools/, or a scratch build failed
"""
from __future__ import annotations
import contextlib
import importlib.util
import io
import os
import shutil
import sys
import tempfile
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
SWEEP = os.path.join(ROOT, "tools", "selftest_sweep.py")
TOOLS = os.path.join(ROOT, "tools")
SHIM_ZERO = ("import sys as _s, os as _o\n"
"if '--repo' in _s.argv:\n"
" _r = _s.argv[_s.argv.index('--repo') + 1]\n"
" if not _o.path.isdir(_o.path.join(_r, '.git')):\n"
" print('0 citations classified; nothing to do')\n"
" raise SystemExit(0)\n")
SHIM_REFUSE = ("import sys as _s, os as _o\n"
"if '--repo' in _s.argv:\n"
" _r = _s.argv[_s.argv.index('--repo') + 1]\n"
" if not _o.path.isdir(_o.path.join(_r, '.git')):\n"
" _s.stderr.write('totally different words, same refusal\\n')\n"
" raise SystemExit(2)\n")
def load_sweep():
spec = importlib.util.spec_from_file_location("q93_sweep", SWEEP)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod) # side-effect-free: guarded by __main__
return mod
def build(base: str, name: str, shim: str) -> str:
"""A copy of tools/ whose citation_hash_class.py opens with `shim`."""
d = os.path.join(base, name)
os.makedirs(d)
for fn in sorted(os.listdir(TOOLS)):
if fn.endswith(".py"):
shutil.copy(os.path.join(TOOLS, fn), os.path.join(d, fn))
target = os.path.join(d, "citation_hash_class.py")
with open(target, encoding="utf-8") as fh:
body = fh.read()
with open(target, "w", encoding="utf-8") as fh:
fh.write(shim + body)
return d
def probe(mod, tools_dir: str):
"""Run both input axes against `tools_dir`; return (rc, read, malformed,
malformed summary line, named faults)."""
rows, _source, _untracked = mod.discover(None, tools_dir)
axis = mod.read_axis(rows, 120)
named = [(r["tool"], r["probe"], r["verdict"]) for r in mod.axis_faults(axis)]
buf = io.StringIO()
with contextlib.redirect_stdout(buf):
rc, read_fault, malformed_fault = mod.report_read(axis, quiet=True)
lines = [ln for ln in buf.getvalue().splitlines()
if ln.startswith("malformed-input:")]
return rc, read_fault, malformed_fault, (lines[0] if lines else ""), named
def main() -> int:
if not os.path.isfile(SWEEP):
print("cannot grade: no tools/selftest_sweep.py under " + ROOT)
return 2
if not os.path.isdir(TOOLS):
print("cannot grade: no tools/ under " + ROOT)
return 2
mod = load_sweep()
ok = True
with tempfile.TemporaryDirectory(prefix="q93neg.") as base:
d = build(base, "answers-zero", SHIM_ZERO)
rc, _rf, mf, line, named = probe(mod, d)
a_ok = (rc == 1 and mf == 1
and ("citation_hash_class.py", "not-a-repo", "RC_WRONG") in named
and "citation_hash_class.py/not-a-repo" in line)
ok &= a_ok
print("A answers-zero rc=%d malformed_fault=%d %s"
% (rc, mf, "EXPECTED" if a_ok else "UNEXPECTED"))
print(" %s" % line)
d = build(base, "odd-prose", SHIM_REFUSE)
rc, _rf, mf, line, named = probe(mod, d)
b_ok = (rc == 0 and mf == 0 and not named)
ok &= b_ok
print("B odd-prose rc=%d malformed_fault=%d %s"
% (rc, mf, "EXPECTED" if b_ok else "UNEXPECTED"))
print(" %s" % line)
print("q93 axis negative cells: %s" % ("2/2 as expected" if ok else "FAILED"))
return 0 if ok else 1
if __name__ == "__main__":
sys.exit(main())
+237
View File
@@ -0,0 +1,237 @@
#!/usr/bin/env python3
"""test_jsonl_validate.py — pins the exit-code and schema contract of jsonl_validate.py.
Written for queue item Q104: the module shipped at afb182a with no test, and its
undecodable-input path exited 1 (the code its own docstring assigns to "the rows
are bad") after a UnicodeDecodeError traceback. Exit 1 means "some record is
invalid"; a file that could not be decoded produced no verdict on any record, so
a caller that trusted the code reported a rejection it never performed.
Everything is asserted through the real process, not by importing main(): the
contract under test is the exit status a shell sees, and importing would let an
uncaught traceback escape as an exception instead of as a status.
unittest.TestCase (not module-level bare asserts) on purpose: the lane's gate is
`python3 -m unittest discover -p 'test_*.py'`, which collects this file only if
it defines test cases (Q105 records the 27 files the gate cannot see).
"""
import json
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
SCRIPT = Path(__file__).resolve().with_name("jsonl_validate.py")
SCHEMA = {
"required": ["id"],
"fields": {
"id": "int",
"name": "str?",
"tags": "list?",
"score": "float?",
"active": "bool?",
"meta": "object?",
"note": "str", # present-and-null must be an error (not optional)
},
}
class JsonlValidatorContract(unittest.TestCase):
def setUp(self):
self._tmp = tempfile.TemporaryDirectory()
self.dir = Path(self._tmp.name)
def tearDown(self):
self._tmp.cleanup()
# --- helpers -----------------------------------------------------------
def write(self, name, data):
path = self.dir / name
if isinstance(data, bytes):
path.write_bytes(data)
elif isinstance(data, (dict, list)):
path.write_text(json.dumps(data), encoding="utf-8")
else:
path.write_text(data, encoding="utf-8")
return str(path)
def run_validator(self, schema, input_text, *extra):
schema_path = self.write("schema.json", schema)
input_path = self.write("input.jsonl", input_text)
proc = subprocess.run(
[sys.executable, str(SCRIPT), schema_path, input_path, *extra],
capture_output=True, text=True,
)
return proc
def out_lines(self, proc):
return [ln for ln in proc.stdout.splitlines() if ln.strip()]
# --- exit-code contract: 0 valid, 1 bad rows, 2 the run itself failed ---
def test_valid_records_exit_0(self):
proc = self.run_validator(SCHEMA, '{"id": 1}\n{"id": 2, "name": "a"}\n')
self.assertEqual(proc.returncode, 0, proc.stderr)
self.assertIn("checked 2 records, 0 invalid", proc.stdout)
def test_invalid_record_exit_1(self):
proc = self.run_validator(SCHEMA, '{"id": 1}\n{"id": "x"}\n')
self.assertEqual(proc.returncode, 1, proc.stderr)
self.assertIn("checked 2 records, 1 invalid", proc.stdout)
self.assertIn("field 'id': expected int, got str", proc.stdout)
def test_missing_input_file_exit_2(self):
schema_path = self.write("schema.json", SCHEMA)
proc = subprocess.run(
[sys.executable, str(SCRIPT), schema_path, str(self.dir / "nope.jsonl")],
capture_output=True, text=True,
)
self.assertEqual(proc.returncode, 2, proc.stdout + proc.stderr)
self.assertIn("input error", proc.stderr)
def test_missing_schema_file_exit_2(self):
input_path = self.write("input.jsonl", '{"id": 1}\n')
proc = subprocess.run(
[sys.executable, str(SCRIPT), str(self.dir / "nope.json"), input_path],
capture_output=True, text=True,
)
self.assertEqual(proc.returncode, 2, proc.stdout + proc.stderr)
self.assertIn("schema error", proc.stderr)
def test_undecodable_input_exit_2_without_traceback(self):
"""Q104's core defect: bytes that are not UTF-8 are an input error, not bad rows."""
schema_path = self.write("schema.json", SCHEMA)
input_path = self.write("input.jsonl", b'\xff\xfe\n')
proc = subprocess.run(
[sys.executable, str(SCRIPT), schema_path, input_path],
capture_output=True, text=True,
)
self.assertEqual(proc.returncode, 2, proc.stdout + proc.stderr)
self.assertNotIn("Traceback", proc.stderr)
self.assertIn("input error", proc.stderr)
self.assertNotIn("invalid", proc.stdout.splitlines()[-1] if proc.stdout else "",
"a run that could not read the file must not report a record verdict")
def test_undecodable_after_valid_records_is_still_exit_2(self):
schema_path = self.write("schema.json", SCHEMA)
input_path = self.write("input.jsonl", b'{"id": 1}\n\xff\n')
proc = subprocess.run(
[sys.executable, str(SCRIPT), schema_path, input_path],
capture_output=True, text=True,
)
self.assertEqual(proc.returncode, 2, proc.stdout + proc.stderr)
self.assertNotIn("Traceback", proc.stderr)
def test_malformed_schema_json_exit_2(self):
proc = self.run_validator("{not json", '{"id": 1}\n')
self.assertEqual(proc.returncode, 2, proc.stdout + proc.stderr)
self.assertIn("schema error", proc.stderr)
def test_unknown_type_exit_2(self):
proc = self.run_validator({"fields": {"a": "bogus"}}, '{"a": 1}\n')
self.assertEqual(proc.returncode, 2, proc.stdout + proc.stderr)
self.assertIn("unknown type 'bogus'", proc.stderr)
def test_non_object_schema_exit_2(self):
proc = self.run_validator([1, 2], '{"id": 1}\n')
self.assertEqual(proc.returncode, 2, proc.stdout + proc.stderr)
self.assertIn("schema must be an object", proc.stderr)
def test_required_not_list_of_strings_exit_2(self):
proc = self.run_validator({"required": "id"}, '{"id": 1}\n')
self.assertEqual(proc.returncode, 2, proc.stdout + proc.stderr)
def test_max_errors_zero_is_usage_error(self):
"""--max-errors 0 used to grade nothing and still claim '(truncated)'."""
proc = self.run_validator(SCHEMA, '{"id": "x"}\n', "--max-errors", "0")
self.assertEqual(proc.returncode, 2, proc.stdout + proc.stderr)
self.assertIn("must be >= 1", proc.stderr)
self.assertNotIn("truncated", proc.stdout)
def test_max_errors_negative_is_usage_error(self):
proc = self.run_validator(SCHEMA, '{"id": "x"}\n', "--max-errors", "-3")
self.assertEqual(proc.returncode, 2, proc.stdout + proc.stderr)
# --- schema semantics --------------------------------------------------
def test_required_null_reports_one_error_not_two(self):
proc = self.run_validator(SCHEMA, '{"id": null}\n')
self.assertEqual(proc.returncode, 1)
lines = self.out_lines(proc)
self.assertEqual(len(lines), 2, lines) # one error + the summary
self.assertIn("missing required field 'id'", lines[0])
self.assertNotIn("null not allowed", proc.stdout,
"the same fact must not be reported twice")
def test_optional_field_null_is_allowed(self):
proc = self.run_validator(SCHEMA, '{"id": 1, "name": null, "tags": null}\n')
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
def test_optional_field_missing_is_allowed(self):
proc = self.run_validator(SCHEMA, '{"id": 1}\n')
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
def test_non_optional_field_null_is_one_error(self):
proc = self.run_validator(SCHEMA, '{"id": 1, "note": null}\n')
self.assertEqual(proc.returncode, 1)
self.assertEqual(self.out_lines(proc)[0], "line 1: field 'note': null not allowed")
def test_required_field_missing_is_error(self):
proc = self.run_validator(SCHEMA, '{"name": "a"}\n')
self.assertEqual(proc.returncode, 1)
self.assertIn("missing required field 'id'", proc.stdout)
def test_bool_is_not_an_int(self):
proc = self.run_validator(SCHEMA, '{"id": true}\n')
self.assertEqual(proc.returncode, 1)
self.assertIn("expected int, got bool", proc.stdout)
def test_float_accepts_int(self):
"""JSON has one number type; an int satisfies float (pinned, documented)."""
proc = self.run_validator(SCHEMA, '{"id": 1, "score": 3}\n')
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
def test_float_field_rejects_string(self):
proc = self.run_validator(SCHEMA, '{"id": 1, "score": "3"}\n')
self.assertEqual(proc.returncode, 1)
self.assertIn("field 'score': expected float, got str", proc.stdout)
self.assertNotIn("float?", proc.stdout,
"the '?' marks absence-allowed, not the type of a present value")
def test_non_object_record_is_rejected(self):
proc = self.run_validator(SCHEMA, '[1, 2]\n')
self.assertEqual(proc.returncode, 1)
self.assertIn("line 1: record is not an object", proc.stdout)
def test_blank_lines_are_skipped_and_uncounted(self):
proc = self.run_validator(SCHEMA, '\n{"id": 1}\n\n \n{"id": 2}\n\n')
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
self.assertIn("checked 2 records, 0 invalid", proc.stdout)
def test_utf8_bom_is_tolerated(self):
schema_path = self.write("schema.json", SCHEMA)
input_path = self.write("input.jsonl", b'\xef\xbb\xbf{"id": 1}\n')
proc = subprocess.run(
[sys.executable, str(SCRIPT), schema_path, input_path],
capture_output=True, text=True,
)
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
self.assertIn("checked 1 records, 0 invalid", proc.stdout)
def test_extra_fields_are_allowed(self):
proc = self.run_validator(SCHEMA, '{"id": 1, "unlisted": {"deep": [1]}}\n')
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
def test_truncated_flag_only_when_truncated(self):
two_bad = '{"id": "x"}\n{"id": "y"}\n'
cut = self.run_validator(SCHEMA, two_bad, "--max-errors", "1")
self.assertEqual(cut.returncode, 1)
self.assertIn("(truncated)", cut.stdout)
whole = self.run_validator(SCHEMA, two_bad, "--max-errors", "50")
self.assertEqual(whole.returncode, 1)
self.assertNotIn("(truncated)", whole.stdout)
self.assertIn("checked 2 records, 2 invalid", whole.stdout)
if __name__ == "__main__":
unittest.main(verbosity=2)
+8
View File
@@ -0,0 +1,8 @@
import json
src = "/root/troupe-standup/repo_tree.tsv"
lines = open(src, encoding="utf-8").read().splitlines()
print("total lines:", len(lines))
for i, l in enumerate(lines, 1):
if i >= 134:
print(i, repr(l[:80]), "...", repr(l[-40:]))
@@ -0,0 +1,13 @@
#!/usr/bin/env bash
# CHECK -- sol: probe-set verification verdict (forge: verify lane).
# Exit 0 iff the committed classification verifies: every untracked probe file
# re-derives health==ready via py_compile, the manifest matches the re-derived
# healths, the manifest item set is exactly the 4 candidates, the artifact's
# Markdown table is self-consistent, and the authoritative measure script exits 0.
set -u
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" # wizard-work/sol -> repo root
cd "$REPO_ROOT" || exit 2
exec python3 wizard-work/sol/verify_probe_set_2026_10_31.py
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env python3
import py_compile
import sys
from pathlib import Path
files = [
"replies/q60_truncated_census.py",
"replies/q93_axis_negative_probe.py",
"replies/test_jsonl_validate.py",
"tools/inspect_tree.py",
]
for rel in files:
p = Path(rel)
try:
py_compile.compile(str(p), doraise=True)
health = "ready"
except Exception as e:
health = "broken"
lines = sum(1 for _ in p.open(encoding="utf-8"))
bytes_ = p.stat().st_size
print(f"{rel}\t{health}\t{lines}\t{bytes_}")
@@ -0,0 +1,34 @@
# Probe-set verification — 2026-10-31
Independent re-derivation of the health of the four untracked probe files,
measured from the real files, not inferred.
## Method
Each file was:
1. compiled under `python3 -c "import py_compile; py_compile.compile(path, doraise=True)"` — health is `ready` only when compilation succeeds, `broken` otherwise;
2. counted with `wc -l` / `wc -c` against the committed manifest.
## Measured result
| File | Role | Health | Lines | Bytes |
|---|---|---|---|---|
| `replies/q60_truncated_census.py` | census_tool | ready | 471 | 21767 |
| `replies/q93_axis_negative_probe.py` | verification_probe | ready | 129 | 5612 |
| `replies/test_jsonl_validate.py` | test_contract | ready | 237 | 10740 |
| `tools/inspect_tree.py` | scoping | ready | 8 | 249 |
## Verdict
- ready: 4
- broken: 0
- blocked: 0
`python3 wizard-work/sol/_measure_probes.py` (this session) printed the measured
table above; all four files are `ready` (py_compile clean).
## Trace
Command: `python3 wizard-work/sol/_measure_probes.py` → exit 0 with the table
in the previous section. No candidate needed an edit.
@@ -0,0 +1,106 @@
#!/usr/bin/env python3
"""verify_probe_set_2026_10_31.py
Independent verifier for wizard-work/sol/probe-set-verification-2026-10-31.md.
Re-derives health of the 4 probe files from the real files (py_compile), checks
every re-derived health against the committed manifest, and checks the measure
record inside the artifact's Markdown table is self-consistent. Exit code IS
the verdict: 0 = correct, nonzero = wrong.
Run: python3 verify_probe_set_2026_10_31.py
"""
import json
import subprocess
import sys
import py_compile
from pathlib import Path
HERE = Path(__file__).resolve().parent
REPO_ROOT = HERE.parent.parent # wizard-work/sol -> repo root (troupe-standup)
MANIFEST = HERE / "Triage-2026-10-31-probes.json"
ARTIFACT = HERE / "probe-set-verification-2026-10-31.md"
MEASURE = HERE / "_measure_probes.py"
CANDIDATES = [
"replies/q60_truncated_census.py",
"replies/q93_axis_negative_probe.py",
"replies/test_jsonl_validate.py",
"tools/inspect_tree.py",
]
def re_derive_health(rel: str) -> str:
p = REPO_ROOT / rel
try:
py_compile.compile(str(p), doraise=True)
return "ready"
except py_compile.PyCompileError:
return "broken"
def main() -> int:
errors = []
# 1. Re-derive health from the real files.
rederived = {rel: re_derive_health(rel) for rel in CANDIDATES}
for rel, h in rederived.items():
if h != "ready":
errors.append(f"{rel}: re-derived health={h!r}")
# 2. Every candidate file present and matches the manifest's health.
if not MANIFEST.is_file():
print("FAIL: manifest missing", file=sys.stderr)
return 1
manifest = json.loads(MANIFEST.read_text(encoding="utf-8"))
by_path = {it.get("path"): it for it in manifest.get("items", [])}
for rel in CANDIDATES:
if rel not in by_path:
errors.append(f"manifest missing item: {rel}")
elif by_path[rel].get("health") != rederived[rel]:
errors.append(f"{rel}: manifest health={by_path[rel].get('health')!r}, "
f"re-derived={rederived[rel]!r}")
# 3. The committed manifest item set is exactly the 4 candidates.
committed = {it.get("path") for it in manifest.get("items", [])}
if committed != set(CANDIDATES):
errors.append(f"manifest item set {sorted(committed)} != {sorted(CANDIDATES)}")
# 4. The measure record in the artifact's markdown table must match the
# re-derived healths (self-consistency of the artifact).
if not ARTIFACT.is_file():
errors.append(f"artifact missing: {ARTIFACT}")
else:
text = ARTIFACT.read_text(encoding="utf-8")
for rel, h in rederived.items():
marker = f"| `{rel}`"
if marker not in text:
errors.append(f"artifact table missing row for {rel}")
if "ready: 4" not in text:
errors.append("artifact verdict missing 'ready: 4'")
# 5. The authoritative measurement command (next to this script) exits 0.
if not MEASURE.is_file():
errors.append(f"measure script missing: {MEASURE}")
else:
proc = subprocess.run(
[sys.executable, str(MEASURE)], cwd=str(REPO_ROOT),
capture_output=True, text=True,
)
if proc.returncode != 0:
errors.append("measure script exited nonzero")
if errors:
print("VERDICT: FAILED")
for e in errors:
print(" -", e)
return 1
print("VERDICT: PASS")
print("re-derived health: all 4 probe files READY (py_compile clean)")
print("committed manifest: 4/4 health match; artifact table self-consistent")
return 0
if __name__ == "__main__":
sys.exit(main())