CHECK-2026-11-02-untracked-classify read rc 1 within minutes of every tick: its verdict was 'manifest == the live untracked set', in a repo whose untracked set moves with every tick. Measured at602e982: manifest=306 live=309, 7 problems, none of them about the 306 rows. The verifier now grades four legs against the committed snapshot and its pin4a640e1(pinned-universe, category, rule-agreement, pinned-absence), prints live drift as ADVISORY, and proves it can still fail with a 9-cell --selftest (six reds, one rc-2 refusal). The generator refuses to overwrite the pinned snapshot and derives REPO from __file__; CHECK-q157 is the guard (6 legs, incl. drift-tolerant vs tampered-manifest). Both touched entry points are signed into the sweep baseline. CHECK: cd /root/troupe-standup && bash CHECK-q157
798 lines
33 KiB
Python
798 lines
33 KiB
Python
#!/usr/bin/env python3
|
|
"""Q137 -- the work queue's declared open set, derived and then measured.
|
|
|
|
Two questions, kept apart on purpose:
|
|
|
|
DECLARED which ids does `WORK-QUEUE.md` itself leave open? That is a
|
|
textual fact: the last declaration for an id, and whether that
|
|
declaration's status word opens or closes it. `--check`
|
|
pins the answer so the set cannot drift unnoticed.
|
|
|
|
MEASURED for each declared-open id, is the defect its record describes
|
|
still present at HEAD? Each probe is a named function that
|
|
reads or runs the thing the record cites and returns a state
|
|
plus the evidence it read. `--closures` pins those states.
|
|
|
|
A repaired item with no closure record is the defect this file exists for:
|
|
the queue says "OPEN", a newcomer takes it, and the work is already done.
|
|
The probe table is the measurement; the pin is what makes the next run a
|
|
regression test rather than a fresh opinion.
|
|
|
|
States
|
|
REPAIRED the cited defect is gone at HEAD, measured by the probe
|
|
PARTIAL one part of the record is satisfied, another is not
|
|
STILL-OPEN the cited defect is still there at HEAD
|
|
UNMEASURED no probe here can settle it (network, archive, judgement)
|
|
|
|
Exit codes (tools/ contract)
|
|
0 graded clean / pin matches
|
|
1 a fault: drift from the pin, or a probe moved
|
|
2 could not grade (missing file, unreadable queue, probe crashed)
|
|
|
|
Stdlib only. Nothing here writes to the tree.
|
|
"""
|
|
import argparse
|
|
import ast
|
|
import importlib.util
|
|
import io
|
|
import json
|
|
import os
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
from contextlib import redirect_stdout
|
|
from pathlib import Path
|
|
|
|
QUEUE = "WORK-QUEUE.md"
|
|
|
|
# ---------------------------------------------------------------- declarations
|
|
|
|
EM = "\u2014"
|
|
SEP = re.compile(r"^[\u2014\u2013-]{1,2}\s*")
|
|
DASHES = (" " + EM + " ", " -- ", " - ")
|
|
OPEN_WORDS = {"OPEN", "OPENED", "REOPENED"}
|
|
CLOSED_WORDS = {"DONE", "CLOSED", "VERIFIED", "REPAIRED", "ACCEPTED",
|
|
"CORRECTION", "ERRATUM", "WITHDRAWN", "RETIRED",
|
|
"ANSWERED", "RESOLVED"}
|
|
CLOSED_IN_PLACE = re.compile(r"OPENED and REPAIRED|OPENED and CLOSED|"
|
|
r"opened and repaired in the same tick")
|
|
|
|
HEADING = re.compile(r"^(#{2,})\s*Q(\d+)\b([\s\u2014\u2013-].*)?$")
|
|
RECORD = re.compile(r"^\*\*Q(\d+)\b\s*[\u2014\u2013-]{1,2}\s*(.*)$")
|
|
|
|
|
|
def classify(tail):
|
|
"""State word from the text after the id, or 'OTHER' / 'SECTION'."""
|
|
t = tail.strip().lstrip("*").strip()
|
|
t = SEP.sub("", t).strip()
|
|
word = t.split()[0].strip(".,:;()") if t.split() else ""
|
|
word = word.strip("*").strip(".,:;()")
|
|
w = word.upper()
|
|
if w in OPEN_WORDS:
|
|
if CLOSED_IN_PLACE.search(t[:80]):
|
|
return "CLOSED"
|
|
return "OPEN"
|
|
if w in CLOSED_WORDS:
|
|
return "CLOSED"
|
|
return "OTHER"
|
|
|
|
|
|
def parse(text):
|
|
"""-> (decls, state): decls is a list of dicts in line order."""
|
|
decls = []
|
|
for n, line in enumerate(text.splitlines(), 1):
|
|
m = RECORD.match(line)
|
|
kind = "record"
|
|
if not m:
|
|
m = HEADING.match(line)
|
|
kind = "heading"
|
|
if not m:
|
|
continue
|
|
qid = int(m.group(2) if kind == "heading" else m.group(1))
|
|
tail = m.group(3) if kind == "heading" else m.group(2)
|
|
state = "SECTION" if kind == "heading" else classify(tail)
|
|
decls.append({
|
|
"qid": qid,
|
|
"line": n,
|
|
"kind": kind,
|
|
"state": state,
|
|
"word": (tail.lstrip("*").strip() or "")[:100],
|
|
})
|
|
state = {}
|
|
for d in decls:
|
|
if d["kind"] == "record":
|
|
state[d["qid"]] = d # last record wins, line order
|
|
elif d["qid"] not in state:
|
|
state[d["qid"]] = {"qid": d["qid"], "line": d["line"],
|
|
"kind": "heading", "state": "SECTION",
|
|
"word": d["word"]}
|
|
return decls, state
|
|
|
|
|
|
def open_ids(state):
|
|
return sorted(q for q, d in state.items() if d["state"] == "OPEN")
|
|
|
|
|
|
def opened_ids(decls):
|
|
"""Every id that carries at least one OPEN record, closed or not."""
|
|
return sorted({d["qid"] for d in decls
|
|
if d["kind"] == "record" and d["state"] == "OPEN"})
|
|
|
|
|
|
def counts(decls, state):
|
|
heads = [d for d in decls if d["kind"] == "heading"]
|
|
recs = [d for d in decls if d["kind"] == "record"]
|
|
return {
|
|
"headings": len(heads),
|
|
"heading_ids": len({d["qid"] for d in heads}),
|
|
"records": len(recs),
|
|
"record_ids": len({d["qid"] for d in recs}),
|
|
"ids": len(state),
|
|
"open": len(open_ids(state)),
|
|
"opened": len(opened_ids(decls)),
|
|
"record_only": len({d["qid"] for d in recs} - {d["qid"] for d in heads}),
|
|
}
|
|
|
|
|
|
# ---------------------------------------------------------------- the probes
|
|
#
|
|
# Each probe takes the repo root and returns (state, evidence). Evidence is
|
|
# the thing a reader can check: a file:line, an rc, a count, a sentence.
|
|
|
|
def read(repo, rel):
|
|
return (repo / rel).read_text(encoding="utf-8", errors="replace")
|
|
|
|
|
|
def run(argv, cwd, timeout=120):
|
|
try:
|
|
p = subprocess.run(argv, cwd=str(cwd), capture_output=True, text=True,
|
|
timeout=timeout)
|
|
return p.returncode, (p.stdout or "") + (p.stderr or "")
|
|
except (OSError, subprocess.TimeoutExpired) as exc:
|
|
return None, str(exc)
|
|
|
|
|
|
def _load(path, name):
|
|
spec = importlib.util.spec_from_file_location(name, str(path))
|
|
mod = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(mod)
|
|
return mod
|
|
|
|
|
|
def probe_q100(repo):
|
|
"""Q100: import_resolve_check's TEST_NAME must select `_test_x.py`."""
|
|
src = read(repo, "tools/import_resolve_check.py")
|
|
pat = None
|
|
for node in ast.walk(ast.parse(src)):
|
|
if isinstance(node, ast.Assign):
|
|
for t in node.targets:
|
|
if isinstance(t, ast.Name) and t.id == "TEST_NAME":
|
|
call = node.value
|
|
if isinstance(call, ast.Call) and call.args:
|
|
try:
|
|
pat = ast.literal_eval(call.args[0])
|
|
except ValueError:
|
|
pat = None
|
|
if pat is None:
|
|
return "STILL-OPEN", "TEST_NAME not found as a literal in import_resolve_check.py"
|
|
rx = re.compile(pat)
|
|
samples = ["wizard-work/forge/_test_roundtrip.py",
|
|
"wizard-work/forge/test_log.txt",
|
|
"wizard-work/forge/_test_roundtrip_refactored.py"]
|
|
hit = [s for s in samples[:1] + samples[2:] if rx.search(s)]
|
|
return ("REPAIRED" if len(hit) == 2 else "STILL-OPEN",
|
|
"TEST_NAME=%r selects %d/2 underscore test files" % (pat, len(hit)))
|
|
|
|
|
|
def probe_q101(repo):
|
|
"""Q101: ledger/census.py must at least parse."""
|
|
path = repo / "wizard-work/ledger/census.py"
|
|
try:
|
|
compile(path.read_text(encoding="utf-8"), str(path), "exec")
|
|
except (OSError, SyntaxError) as exc:
|
|
return "STILL-OPEN", "census.py will not compile: %s" % (exc,)
|
|
return "REPAIRED", "census.py compiles (compile() at %s)" % path.name
|
|
|
|
|
|
def probe_q102(repo):
|
|
"""Q102: three outcomes must be three channels."""
|
|
mod = _load(repo / "wizard-work/beam/majority_element.py", "q137_maj")
|
|
try:
|
|
got = mod.majority([None, None, 1])
|
|
none_majority = got is None
|
|
except Exception: # noqa: BLE001
|
|
none_majority = False
|
|
raised = False
|
|
try:
|
|
mod.majority([1, 2, 3])
|
|
except Exception as exc: # noqa: BLE001
|
|
raised = type(exc).__name__ == "NoMajority"
|
|
return ("REPAIRED" if none_majority and raised else "STILL-OPEN",
|
|
"majority([None,None,1])->None=%s; majority([1,2,3]) raises "
|
|
"NoMajority=%s" % (none_majority, raised))
|
|
|
|
|
|
def probe_q103(repo):
|
|
"""Q103: queue_index must see ids of any width."""
|
|
rc, out = run([sys.executable, "tools/queue_index.py",
|
|
"--check", "docs/queue-index.md"], repo)
|
|
ok = rc == 0
|
|
return ("REPAIRED" if ok else "STILL-OPEN",
|
|
"queue_index --check docs/queue-index.md rc=%s; %s"
|
|
% (rc, out.strip().splitlines()[-1][:120] if out.strip() else ""))
|
|
|
|
|
|
def probe_q104(repo):
|
|
"""Q104: undecodable JSONL must be a typed exit 2, no traceback."""
|
|
tmp = Path(tempfile.mkdtemp(prefix="q137-q104-"))
|
|
try:
|
|
bad = tmp / "bad.jsonl"
|
|
bad.write_bytes(b'{"a": 1}\n\xff\xfe not utf-8\n')
|
|
rc, out = run([sys.executable, "wizard-work/beam/jsonl_validate.py",
|
|
str(bad)], repo)
|
|
finally:
|
|
shutil.rmtree(tmp, ignore_errors=True)
|
|
typed = rc == 2 and "Traceback" not in out
|
|
return ("REPAIRED" if typed else "STILL-OPEN",
|
|
"undecodable input rc=%s traceback=%s"
|
|
% (rc, "Traceback" in out))
|
|
|
|
|
|
def probe_q105(repo):
|
|
"""Q105/Q128: the beam gate must collect both test styles."""
|
|
txt = read(repo, "wizard-work/beam/CHECK")
|
|
ok = "run_lane_tests.py" in txt
|
|
return ("REPAIRED" if ok else "STILL-OPEN",
|
|
"beam/CHECK runs run_lane_tests.py=%s (%d lines)"
|
|
% (ok, len(txt.splitlines())))
|
|
|
|
|
|
def probe_q106(repo):
|
|
"""Q106: the dated sol gate must not pin an absolute host root."""
|
|
txt = read(repo, "wizard-work/sol/CHECK-2026-09-28")
|
|
n = txt.count("/root")
|
|
return ("REPAIRED" if n == 0 else "STILL-OPEN",
|
|
"CHECK-2026-09-28 /root occurrences=%d" % n)
|
|
|
|
|
|
def probe_q107(repo):
|
|
"""Q107: --dir must not exit the number of invalid files."""
|
|
tmp = Path(tempfile.mkdtemp(prefix="q137-q107-"))
|
|
try:
|
|
(tmp / "ok.json").write_text('{"a": 1}', encoding="utf-8")
|
|
(tmp / "bad1.json").write_text("{nope", encoding="utf-8")
|
|
(tmp / "bad2.json").write_text("{nope", encoding="utf-8")
|
|
(tmp / "sub").mkdir()
|
|
(tmp / "sub" / "deep.json").write_text('{"b": 2}', encoding="utf-8")
|
|
rc, out = run([sys.executable, "wizard-work/spark/json-validator.py",
|
|
str(tmp)], repo)
|
|
finally:
|
|
shutil.rmtree(tmp, ignore_errors=True)
|
|
valid = sum(1 for ln in out.splitlines() if ln.startswith("VALID:"))
|
|
invalid = sum(1 for ln in out.splitlines() if ln.startswith("INVALID:"))
|
|
ok = rc == 1 and (valid, invalid) == (2, 2)
|
|
return ("REPAIRED" if ok else "STILL-OPEN",
|
|
"dir with 2 invalid + 2 valid (one nested): rc=%s valid=%d invalid=%d"
|
|
% (rc, valid, invalid))
|
|
|
|
|
|
def probe_q109(repo):
|
|
"""Q109: snippet.py's tool check must measure, not assume."""
|
|
txt = read(repo, "wizard-work/spark/snippet.py")
|
|
has_fn = "def check_tools" in txt
|
|
returns_measurement = "available, error = check_tools" in txt
|
|
graded = (repo / "wizard-work/spark/test_env_verifiers.py").is_file()
|
|
ok = has_fn and returns_measurement and graded
|
|
return ("REPAIRED" if ok else "STILL-OPEN",
|
|
"check_tools=%s, call site=%s, graded by test_env_verifiers=%s"
|
|
% (has_fn, returns_measurement, graded))
|
|
|
|
|
|
def probe_q110(repo):
|
|
"""Q110: the QUICKSTART's clone step must point at a live repository."""
|
|
txt = read(repo, "wizard-work/quill/QUICKSTART.md")
|
|
clones = re.findall(r"^git clone (\S+)", txt, re.M)
|
|
live = [u for u in clones if "forge.alexanderwhitestone.com" in u]
|
|
ok = len(clones) == 1 and len(live) == 1
|
|
return ("REPAIRED" if ok else "STILL-OPEN",
|
|
"%d git clone step(s): %s" % (len(clones), clones[:3]))
|
|
|
|
|
|
def probe_q111(repo):
|
|
"""Q111: zero-length intervals must not skew the optimum."""
|
|
mod = _load(repo / "wizard-work/beam/weighted_interval_scheduling.py",
|
|
"q137_wis")
|
|
fn = getattr(mod, "weighted_interval_scheduling")
|
|
|
|
def ok_pair(sel):
|
|
for i in range(len(sel)):
|
|
for j in range(i + 1, len(sel)):
|
|
a, b = sel[i], sel[j]
|
|
if min(a[1], b[1]) - max(a[0], b[0]) > 0:
|
|
return False
|
|
return True
|
|
|
|
bad = 0
|
|
trials = 0
|
|
import random
|
|
rng = random.Random(1371)
|
|
for _ in range(60):
|
|
n_try = rng.randint(1, 4)
|
|
iv = [[rng.randint(0, 3), rng.randint(0, 3), rng.randint(1, 4)]
|
|
for _ in range(n_try)]
|
|
iv = [[min(a, b), max(a, b), w] for a, b, w in iv]
|
|
got = fn(iv)
|
|
best = 0
|
|
m = len(iv)
|
|
for mask in range(1 << m):
|
|
sel = [iv[i] for i in range(m) if mask >> i & 1]
|
|
if ok_pair(sel) and sum(x[2] for x in sel) > best:
|
|
best = sum(x[2] for x in sel)
|
|
trials += 1
|
|
if got != best:
|
|
bad += 1
|
|
return ("REPAIRED" if bad == 0 and trials else "STILL-OPEN",
|
|
"zero-length included: %d mismatches in %d exhaustive trials"
|
|
% (bad, trials))
|
|
|
|
|
|
def probe_q112(repo):
|
|
"""Q112: the census must see every heading, and every record."""
|
|
rc, out = run([sys.executable,
|
|
"wizard-work/ledger/workqueue-census-v2/CHECK"], repo)
|
|
line = ""
|
|
for ln in out.splitlines():
|
|
if "distinct labels" in ln:
|
|
line = ln.strip()
|
|
if rc != 0 or not line:
|
|
return "STILL-OPEN", "census CHECK rc=%s, no summary line" % rc
|
|
m = re.search(r"\((\d+) rows, (\d+) distinct labels", line)
|
|
text = read(repo, QUEUE)
|
|
decls, state = parse(text)
|
|
c = counts(decls, state)
|
|
rows, labels = (int(m.group(1)), int(m.group(2))) if m else (0, 0)
|
|
covered = rows >= c["headings"] and labels >= c["heading_ids"]
|
|
return ("REPAIRED" if covered else "STILL-OPEN",
|
|
"census %d rows/%d labels vs %d headings/%d heading ids; "
|
|
"%d record-only ids are enumerated by the extractor, not as rows"
|
|
% (rows, labels, c["headings"], c["heading_ids"], c["record_only"]))
|
|
|
|
|
|
def probe_q113(repo):
|
|
"""Q113: the roster gate must fail on a seeded mutation."""
|
|
led = "wizard-work/ledger"
|
|
tmp = Path(tempfile.mkdtemp(prefix="q137-q113-"))
|
|
try:
|
|
dst = tmp / led
|
|
dst.mkdir(parents=True)
|
|
for name in ("wizards.csv", "wizards.manifest.json"):
|
|
shutil.copy2(repo / led / name, dst / name)
|
|
man = json.loads((dst / "wizards.manifest.json").read_text(encoding="utf-8"))
|
|
src_rel = man.get("source", "")
|
|
if src_rel:
|
|
(tmp / src_rel).parent.mkdir(parents=True, exist_ok=True)
|
|
shutil.copy2(repo / src_rel, tmp / src_rel)
|
|
csv = (dst / "wizards.csv").read_text(encoding="utf-8")
|
|
(dst / "wizards.csv").write_text(csv.replace("Timmy", "GARBAGE NAME"),
|
|
encoding="utf-8")
|
|
bad_rc, _ = run([sys.executable, led + "/verify_wizards.py",
|
|
"--root", str(tmp)], repo)
|
|
good_rc, _ = run([sys.executable, led + "/verify_wizards.py",
|
|
"--root", str(repo)], repo)
|
|
finally:
|
|
shutil.rmtree(tmp, ignore_errors=True)
|
|
ok = bad_rc == 1 and good_rc == 0
|
|
return ("REPAIRED" if ok else "STILL-OPEN",
|
|
"seeded mutation rc=%s, clean tree rc=%s" % (bad_rc, good_rc))
|
|
|
|
|
|
def probe_q115(repo):
|
|
"""Q115: an unreadable folder must not read as a mass deletion."""
|
|
txt = Path("/root/.hermes/scripts/troupe_pipe_monitor.py").read_text(
|
|
encoding="utf-8", errors="replace")
|
|
ok = "UNREADABLE" in txt and "carried" in txt
|
|
return ("REPAIRED" if ok else "UNMEASURED",
|
|
"monitor separates UNREADABLE=%s and carries the listing=%s"
|
|
% ("UNREADABLE" in txt, "carried" in txt))
|
|
|
|
|
|
def probe_q117(repo):
|
|
"""Q117: an invented probe value must be data, not a recovery."""
|
|
txt = read(repo, "wizard-work/zeph/q60_enforce.py")
|
|
ok = "KNOWN_PROBE" in txt and txt.count("KNOWN_PROBE") >= 3
|
|
return ("REPAIRED" if ok else "STILL-OPEN",
|
|
"q60_enforce.py KNOWN_PROBE occurrences=%d"
|
|
% txt.count("KNOWN_PROBE"))
|
|
|
|
|
|
def probe_q118(repo):
|
|
"""Q118: a failed listing must be retried and report attempts/last."""
|
|
txt = Path("/root/.hermes/scripts/troupe_pipe_monitor.py").read_text(
|
|
encoding="utf-8", errors="replace")
|
|
retry = "for attempt in range(1, tries + 1)" in txt
|
|
fields = "attempts=" in txt and "last=" in txt
|
|
return ("REPAIRED" if retry and fields else "STILL-OPEN",
|
|
"retry loop=%s, attempts=/last= fields=%s" % (retry, fields))
|
|
|
|
|
|
def probe_q119(repo):
|
|
"""Q119: an unmatched demand must not be silently 'info'."""
|
|
txt = read(repo, "wizard-work/sol/classify.py")
|
|
ok = "unclassified" in txt and "Fallback" in txt
|
|
return ("REPAIRED" if ok else "STILL-OPEN",
|
|
"classify.py names an unclassified fallback in its header=%s" % ok)
|
|
|
|
|
|
def probe_q120(repo):
|
|
"""Q120: the env check must import real dependencies and report versions."""
|
|
txt = read(repo, "wizard-work/spark/python-env-check.py")
|
|
decl = "DEPENDENCIES" in txt
|
|
called = len(re.findall(r"check_package\(", txt)) >= 2
|
|
return ("REPAIRED" if decl and called else "STILL-OPEN",
|
|
"DEPENDENCIES table=%s, check_package call sites=%d"
|
|
% (decl, len(re.findall(r"check_package\(", txt))))
|
|
|
|
|
|
def probe_q121(repo):
|
|
"""Q121: fixture absence must be asserted per value, not over a join."""
|
|
txt = read(repo, "wizard-work/zeph/q60_enforce.py")
|
|
per_value = "for value in KNOWN_FIXTURE.values()" in txt or \
|
|
"KNOWN_FIXTURE.values()" in txt
|
|
mutant = "two_entry" in txt
|
|
ok = per_value and mutant
|
|
return ("REPAIRED" if ok else "STILL-OPEN",
|
|
"per-value absence=%s, two-entry mutant cell=%s"
|
|
% (per_value, mutant))
|
|
|
|
|
|
def probe_q122(repo):
|
|
"""Q122: the census CHECK must not gate on a wall clock."""
|
|
rc, out = run([sys.executable,
|
|
"wizard-work/ledger/workqueue-census-v2/CHECK"], repo)
|
|
skipped = "SKIP" in out.upper()
|
|
return ("REPAIRED" if rc == 0 else "STILL-OPEN",
|
|
"census CHECK rc=%s, clock leg reads %s"
|
|
% (rc, "SKIP" if skipped else "graded"))
|
|
|
|
|
|
def unmade(reason):
|
|
def probe(repo):
|
|
return "UNMEASURED", reason
|
|
return probe
|
|
|
|
|
|
PROBES = {
|
|
100: probe_q100, 101: probe_q101, 102: probe_q102, 103: probe_q103,
|
|
104: probe_q104, 105: probe_q105, 106: probe_q106, 107: probe_q107,
|
|
109: probe_q109, 110: probe_q110, 111: probe_q111, 112: probe_q112,
|
|
113: probe_q113, 115: probe_q115, 117: probe_q117, 118: probe_q118,
|
|
119: probe_q119, 120: probe_q120, 121: probe_q121, 122: probe_q122,
|
|
51: unmade("gate-wide probe window: needs the live gate, not a file read"),
|
|
52: unmade("archive attribution: needs pipeline logs this tree does not hold"),
|
|
53: unmade("digest domain + state.db: needs the live database"),
|
|
65: unmade("population claim over 87 verifiers; the Q87 gate owns it now"),
|
|
114: unmade("free-tier rows contradict six provider endpoints: network"),
|
|
116: unmade("OpenTrain validThrough is per-render: network, time-lapsed"),
|
|
}
|
|
|
|
PIN_OPEN = []
|
|
PIN_OPENED = [51, 52, 53, 65, 100, 101, 102, 103, 104, 105, 106, 107, 109,
|
|
110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122]
|
|
# Q57's state lives in WORK-QUEUE.md's closure record (appended at the foot);
|
|
# it is not probed here because its opening was a **Status: line, so it never
|
|
# entered PIN_OPENED -- see the PIN_COUNTS comment above.
|
|
|
|
# Q147 (2026-11-01): the record count, the id count and the record-only count
|
|
# move with any append to WORK-QUEUE.md -- this one added Q147, which is a
|
|
# record and an id and a record-only id, and no heading. Re-taken at the commit
|
|
# that carries the record: 106 -> 107 records, 137 -> 138 ids, 72 -> 73
|
|
# record_ids, 51 -> 52 record_only; headings, heading_ids, open and opened
|
|
# unchanged (97 / 86 / 0 / 26), so no id changed its state.
|
|
# Q148 (2026-11-01): the same move for the same reason -- one appended record,
|
|
# one appended id, no heading: 107 -> 108 records, 138 -> 139 ids, 73 -> 74
|
|
# record_ids, 52 -> 53 record_only; headings, heading_ids, open and opened
|
|
# unchanged (97 / 86 / 0 / 26), so again no id changed its state.
|
|
# Q150 (2026-11-01): the same move again -- one appended record, one appended
|
|
# id, no heading: 109 -> 110 records, 140 -> 141 ids, 75 -> 76 record_ids,
|
|
# 54 -> 55 record_only; headings, heading_ids, open and opened unchanged
|
|
# (97 / 86 / 0 / 26). Q150 is a same-tick repair, so it never sat open and is
|
|
# not registered as a probe -- CHECK-q150 is its regression guard, not a
|
|
# closure probe (the Q138 rule for same-tick ids).
|
|
# Q57 (2026-11-01): the closure record appended at the foot of WORK-QUEUE.md
|
|
# adds one record and one record id -- Q57 gets its first **Q57 — ** record.
|
|
# Q57 carries a heading (## Q57 @ 10700), so record_only, ids, headings,
|
|
# heading_ids, open and opened are unchanged (97 / 86 / 0 / 26 / 55 / 141);
|
|
# Q57 was never in PIN_OPENED (its opening was a **Status: open...** line,
|
|
# not a **Q57 — OPEN** record), and no id changed its state.
|
|
# Q88 (2026-11-01): the closure record appended at the foot of WORK-QUEUE.md
|
|
# adds one heading (## Q88 closure) and one record (**Q88 — DONE ...). Q88
|
|
# already carried a heading (## Q88 @ 12283), so heading_ids is unchanged while
|
|
# headings moves 97 -> 98; records 111 -> 112, and Q88 was heading-only until
|
|
# this append, so record_ids 77 -> 78 with record_only unchanged at 55.
|
|
# open, opened, ids and heading_ids are all unchanged (0 / 26 / 141 / 86): the
|
|
# append closes an id, it does not open one.
|
|
# Q151 (2026-11-01): the closure record appended at the foot of WORK-QUEUE.md
|
|
# adds one heading (## Q151 closure) and one record (**Q151 — OPENED and
|
|
# REPAIRED in the same tick ...). Q151 is a new id with no earlier heading, so
|
|
# everything that counts a distinct id moves together: headings 98 -> 99,
|
|
# heading_ids 86 -> 87, records 112 -> 113, record_ids 78 -> 79, ids 141 -> 142;
|
|
# record_only stays 55 (the new id has a heading, so it is not record-only) and
|
|
# open / opened stay 0 / 26 -- a same-tick "OPENED and REPAIRED" is a closure
|
|
# (the Q138 rule), so no probe is registered for it and CHECK-q151 is its guard.
|
|
# Q152 (2026-11-01): the same move again -- one heading (## Q152 closure) and
|
|
# one record (**Q152 — OPENED and REPAIRED ...) for a new id, so headings
|
|
# 99 -> 100, heading_ids 87 -> 88, records 113 -> 114, record_ids 79 -> 80,
|
|
# ids 142 -> 143; record_only stays 55 and open / opened stay 0 / 26 (same-tick
|
|
# closure, no probe; CHECK-2026-11-01-posts-census is its guard).
|
|
# Q153 (2026-11-02): the same move again -- one heading (## Q153 closure) and
|
|
# one record (**Q153 — OPENED and REPAIRED ...) for a new id, so headings
|
|
# 100 -> 101, heading_ids 88 -> 89, records 114 -> 115, record_ids 80 -> 81,
|
|
# ids 143 -> 144; record_only stays 55 and open / opened stay 0 / 26 (same-tick
|
|
# closure, no probe; CHECK-q153 is its guard). Measured after the append, not
|
|
# predicted.
|
|
# Q155 (2026-11-02): the same move again -- one heading (## Q155 closure) and
|
|
# one record (**Q155 — OPENED and REPAIRED ...) for a new id, so headings
|
|
# 101 -> 102, heading_ids 89 -> 90, records 115 -> 116, record_ids 81 -> 82,
|
|
# ids 144 -> 145; record_only stays 55 and open / opened stay 0 / 26 (same-tick
|
|
# closure, no probe; CHECK-q155 is its guard). Measured after the append by
|
|
# `open_set.py --check`, which read exactly these five moves and no others.
|
|
# Q85 (2026-11-02): the append at c05f05a was the first in the queue's recent
|
|
# history to land WITHOUT this pin move -- it added one heading (## Q85
|
|
# closure) and one record (**Q85 -- DONE ...), so the pin read three faults at
|
|
# HEAD (headings 102 -> 103, records 116 -> 117, record_ids 82 -> 83) until
|
|
# Q156 re-took it. Q85 already carried a heading, so heading_ids and ids did
|
|
# not move with that append; record_only stayed 55.
|
|
# Q156 (2026-11-02): the same move again -- one heading (## Q156 closure) and
|
|
# one record (**Q156 -- OPENED and REPAIRED ...) for a new id, so headings
|
|
# 103 -> 104, heading_ids 90 -> 91, records 117 -> 118, record_ids 83 -> 84,
|
|
# ids 145 -> 146; record_only stays 55 and open / opened stay 0 / 26 (same-tick
|
|
# closure, no probe; CHECK-q156 is its guard). Measured on a byte-identical
|
|
# candidate queue before the append and confirmed by --check after it.
|
|
# Q157 (2026-11-02): one heading (## Q157 closure) and one record (**Q157 --
|
|
# OPENED and REPAIRED ...) for a new id, so headings 104 -> 105, heading_ids
|
|
# 91 -> 92, records 118 -> 119, record_ids 84 -> 85, ids 146 -> 147;
|
|
# record_only stays 55 and open / opened stay 0 / 26 (same-tick closure, no
|
|
# probe; CHECK-q157 is its guard). Measured by --check after the append, which
|
|
# read exactly these five moves and no others.
|
|
PIN_COUNTS = {"headings": 105, "heading_ids": 92, "records": 119,
|
|
"record_ids": 85, "ids": 147, "open": 0, "opened": 26,
|
|
"record_only": 55}
|
|
|
|
PIN_STATE = {
|
|
100: "REPAIRED", 101: "REPAIRED", 102: "REPAIRED", 103: "REPAIRED",
|
|
104: "REPAIRED", 105: "REPAIRED", 106: "REPAIRED", 107: "REPAIRED",
|
|
109: "REPAIRED", 110: "REPAIRED", 111: "REPAIRED", 112: "REPAIRED",
|
|
113: "REPAIRED", 115: "REPAIRED", 117: "REPAIRED", 118: "REPAIRED",
|
|
119: "REPAIRED", 120: "REPAIRED", 121: "REPAIRED", 122: "REPAIRED",
|
|
51: "UNMEASURED", 52: "UNMEASURED", 53: "UNMEASURED", 65: "UNMEASURED",
|
|
114: "UNMEASURED", 116: "UNMEASURED",
|
|
}
|
|
|
|
|
|
# ---------------------------------------------------------------- the selftest
|
|
|
|
FIXTURES = [
|
|
("open-then-done",
|
|
"**Q5 \u2014 OPEN (a).** body\n**Q5 \u2014 DONE at `abc`.**\n", 5, "CLOSED"),
|
|
("opened-and-repaired-in-place",
|
|
"**Q7 \u2014 OPENED and REPAIRED in the same tick (volt).** body\n",
|
|
7, "CLOSED"),
|
|
("open-with-no-close",
|
|
"**Q9 \u2014 OPEN (pipe).** body\n", 9, "OPEN"),
|
|
("heading-only",
|
|
"## Q11 \u2014 A section title\nbody\n", 11, "SECTION"),
|
|
("heading-then-record",
|
|
"## Q13 \u2014 A section title\nbody\n**Q13 \u2014 DONE.**\n", 13, "CLOSED"),
|
|
("bold-not-a-declaration",
|
|
"**Q15 measured.** prose, no dash\n", 15, None),
|
|
("width-boundary",
|
|
"**Q1000 \u2014 OPEN (x).**\n**Q100 \u2014 DONE.**\n", 100, "CLOSED"),
|
|
("reopened-after-done",
|
|
"**Q17 \u2014 DONE.**\n**Q17 \u2014 REOPENED (pipe).**\n", 17, "OPEN"),
|
|
]
|
|
|
|
|
|
def graded(repo, text):
|
|
"""mode_check's rc with its output swallowed -- for the mutant cells."""
|
|
buf = io.StringIO()
|
|
try:
|
|
with redirect_stdout(buf):
|
|
return mode_check(repo, text)
|
|
finally:
|
|
buf.close()
|
|
|
|
|
|
def selftest():
|
|
cells = []
|
|
for name, text, qid, want in FIXTURES:
|
|
_, state = parse(text)
|
|
got = state.get(qid, {}).get("state")
|
|
cells.append((name, got == want, "got=%r want=%r" % (got, want)))
|
|
repo, text = load_repo(str(Path(__file__).resolve().parents[3]))
|
|
if repo is not None and text is not None:
|
|
once = parse(text)
|
|
cells.append(("parse-is-deterministic", once == parse(text), ""))
|
|
cells.append(("gate-green-control", graded(repo, text) == 0, "rc"))
|
|
cells.append(("gate-new-open-id",
|
|
graded(repo, text + "\n**Q999 \u2014 OPEN (x).**\n") == 1,
|
|
"rc"))
|
|
cells.append(("gate-done-turned-open",
|
|
graded(repo, text.replace("**Q117 \u2014 DONE",
|
|
"**Q117 \u2014 OPEN", 1)) == 1,
|
|
"rc"))
|
|
cells.append(("gate-heading-dropped",
|
|
graded(repo, re.sub(r"(?m)^## Q5 \u2014.*\n", "", text,
|
|
count=1)) == 1, "rc"))
|
|
bad = [c for c in cells if not c[1]]
|
|
for name, ok, detail in cells:
|
|
print("%-28s %s %s" % (name, "PASS" if ok else "FAIL", detail))
|
|
print("SELFTEST %s (%d cells, %d failed)"
|
|
% ("OK" if not bad else "FAILED", len(cells), len(bad)))
|
|
return 0 if not bad else 1
|
|
|
|
|
|
def parse_text_roundtrip():
|
|
return "**Q1 \u2014 OPEN (x).**\n"
|
|
|
|
|
|
# ---------------------------------------------------------------- the modes
|
|
|
|
def load_repo(arg):
|
|
root = Path(arg).resolve()
|
|
q = root / QUEUE
|
|
if not q.is_file():
|
|
print("cannot grade: no %s under %s" % (QUEUE, root))
|
|
return None, None
|
|
return root, q.read_text(encoding="utf-8")
|
|
|
|
|
|
def mode_check(repo, text):
|
|
decls, state = parse(text)
|
|
c = counts(decls, state)
|
|
got = open_ids(state)
|
|
print("queue: %d lines, %d headings/%d ids, %d records/%d ids, "
|
|
"%d record-only ids" % (len(text.splitlines()), c["headings"],
|
|
c["heading_ids"], c["records"],
|
|
c["record_ids"], c["record_only"]))
|
|
print("declared open: %d; ids ever opened: %d" % (len(got), c["opened"]))
|
|
faults = []
|
|
for key in sorted(PIN_COUNTS):
|
|
if c[key] != PIN_COUNTS[key]:
|
|
faults.append("count %s moved %d -> %d" % (key, PIN_COUNTS[key], c[key]))
|
|
if got != PIN_OPEN:
|
|
added = [q for q in got if q not in PIN_OPEN]
|
|
gone = [q for q in PIN_OPEN if q not in got]
|
|
faults.append("open set moved: +%s -%s" % (added, gone))
|
|
if opened_ids(decls) != PIN_OPENED:
|
|
faults.append("the set of ever-opened ids moved")
|
|
for f in faults:
|
|
print("FAIL %s" % f)
|
|
print("CHECK %s" % ("OK: 0 open, %d ever opened, counts match the pin"
|
|
% len(PIN_OPENED)
|
|
if not faults else "%d fault(s)" % len(faults)))
|
|
return 0 if not faults else 1
|
|
|
|
|
|
def mode_order(repo, text):
|
|
"""Line order must be commit order, or 'last record' is not 'latest'."""
|
|
decls, _ = parse(text)
|
|
recs = [d for d in decls if d["kind"] == "record"]
|
|
rc, out = run(["git", "blame", "--porcelain", "--", QUEUE], repo)
|
|
if rc != 0 or not out:
|
|
print("cannot grade order: git blame failed")
|
|
return 2
|
|
by_line = {}
|
|
commit = None
|
|
for ln in out.splitlines():
|
|
m = re.match(r"^([0-9a-f]{40}) \d+ (\d+)(?: \d+)?$", ln)
|
|
if m:
|
|
commit = m.group(1)
|
|
by_line[int(m.group(2))] = commit
|
|
times = {}
|
|
stamps = []
|
|
pending = 0
|
|
for d in recs:
|
|
c = by_line.get(d["line"])
|
|
if c is None:
|
|
print("cannot grade order: no blame entry for line %d" % d["line"])
|
|
return 2
|
|
if set(c) == {"0"}:
|
|
pending += 1 # appended, not yet committed
|
|
continue
|
|
if c not in times:
|
|
trc, tout = run(["git", "show", "-s", "--format=%ct", c], repo)
|
|
if trc != 0:
|
|
print("cannot grade order: no timestamp for %s" % c[:12])
|
|
return 2
|
|
times[c] = int(tout.strip())
|
|
stamps.append((d["line"], times[c], c))
|
|
if not stamps:
|
|
print("cannot grade order: no committed record lines")
|
|
return 2
|
|
bad = []
|
|
for (l1, t1, c1), (l2, t2, c2) in zip(stamps, stamps[1:]):
|
|
if t2 < t1:
|
|
bad.append("line %d (%s) is newer than line %d (%s)"
|
|
% (l2, c2[:8], l1, c1[:8]))
|
|
print("record order: %d commits over %d committed records (%d pending "
|
|
"commit); %d inversion(s)"
|
|
% (len(times), len(stamps), pending, len(bad)))
|
|
for b in bad[:5]:
|
|
print("FAIL %s" % b)
|
|
print("CHECK %s" % ("OK: line order is commit order, so 'last record' is "
|
|
"'latest'" if not bad else "%d inversion(s)" % len(bad)))
|
|
return 0 if not bad else 1
|
|
|
|
|
|
def mode_table(repo, text):
|
|
decls, state = parse(text)
|
|
for q in opened_ids(decls):
|
|
d = state[q]
|
|
print("Q%-4d %-6s :%-6d %s" % (q, d["state"], d["line"], d["word"][:90]))
|
|
return 0
|
|
|
|
|
|
def mode_closures(repo, text):
|
|
decls, state = parse(text)
|
|
want = opened_ids(decls)
|
|
if want != PIN_OPENED:
|
|
print("cannot grade closures: the ever-opened set moved, run --check")
|
|
return 2
|
|
faults = []
|
|
rows = []
|
|
for q in want:
|
|
probe = PROBES.get(q)
|
|
if probe is None:
|
|
rows.append((q, "UNMEASURED", "no probe registered"))
|
|
continue
|
|
try:
|
|
got, ev = probe(repo)
|
|
except Exception as exc: # noqa: BLE001
|
|
print("Q%-4d UNGRADABLE %s: %s" % (q, type(exc).__name__, exc))
|
|
return 2
|
|
rows.append((q, got, ev))
|
|
tally = {}
|
|
for q, got, ev in rows:
|
|
tally[got] = tally.get(got, 0) + 1
|
|
pin = PIN_STATE.get(q)
|
|
mark = " " if got == pin else "!"
|
|
print("%sQ%-4d %-10s %s" % (mark, q, got, ev))
|
|
if got != pin:
|
|
faults.append("Q%d moved %s -> %s" % (q, pin, got))
|
|
print("closure tally: %s" % ", ".join("%s %d" % kv for kv in sorted(tally.items())))
|
|
for f in faults:
|
|
print("FAIL %s -- re-pin with the commit that moved it" % f)
|
|
print("CHECK %s" % ("OK: %d ever-opened ids, %d measured, states match the pin"
|
|
% (len(want), len(rows) - tally.get("UNMEASURED", 0))
|
|
if not faults else "%d fault(s)" % len(faults)))
|
|
return 0 if not faults else 1
|
|
|
|
|
|
def main(argv=None):
|
|
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
ap.add_argument("--repo", default=str(Path(__file__).resolve().parents[3]))
|
|
ap.add_argument("--check", action="store_true", help="grade the declared set")
|
|
ap.add_argument("--closures", action="store_true", help="grade measured states")
|
|
ap.add_argument("--order", action="store_true", help="line order vs commit order")
|
|
ap.add_argument("--table", action="store_true", help="print the open set")
|
|
ap.add_argument("--selftest", action="store_true", help="parser cells")
|
|
args = ap.parse_args(argv)
|
|
if args.selftest:
|
|
return selftest()
|
|
repo, text = load_repo(args.repo)
|
|
if repo is None:
|
|
return 2
|
|
if args.table:
|
|
return mode_table(repo, text)
|
|
if args.order:
|
|
return mode_order(repo, text)
|
|
if args.closures:
|
|
return mode_closures(repo, text)
|
|
return mode_check(repo, text)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|