diff --git a/CHECK-q147 b/CHECK-q147 new file mode 100755 index 0000000..92aa080 --- /dev/null +++ b/CHECK-q147 @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +# CHECK-q147 -- the workqueue census is graded at its pin, all four columns. +# +# Q147 (2026-11-01): `wizard-work/ledger/workqueue-census/CHECK` asserted that +# the committed TSV re-derives from WORK-QUEUE.md as it stands on disk. Measured +# at 50cc5bb in a clean clone: rc 1, `expected 96 headings, got 97` -- the check +# graded the calendar, not the artifact. Measured at 95b6964: a mutated `status` +# cell and a mutated `done_implies` cell both printed PASS (rc 0), because only +# the (q,title) pairs were compared. The repair pins the census at 95b6964, +# grades every column, and refuses to grade at all without a rev. +# +# leg 1 the verifier's 13-cell selftest +# leg 2 the artifact at its pin: 17 legs, all four columns, rc 0 +# leg 3 the tooling names no host path (a check that hardcodes /root/ grades +# the author's worktree from any checkout -- Q69's class) +# leg 4 the q143 baseline row still reads what this tree reads +# +# rc 0 all legs pass, rc 1 a leg faulted, rc 2 could not grade. +set -u +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" || { echo "CANNOT GRADE: no directory"; exit 2; } +ROOT="$(git -C "$HERE" rev-parse --show-toplevel 2>/dev/null)" || { echo "CANNOT GRADE: not a git repository"; exit 2; } +[ -n "$ROOT" ] || { echo "CANNOT GRADE: no git toplevel"; exit 2; } +ART="$ROOT/wizard-work/ledger/workqueue-census" +TOOL="$ART/verify_workqueue_census.py" +[ -f "$TOOL" ] || { echo "CANNOT GRADE: missing $TOOL"; exit 2; } + +faults=0 +pass() { echo "PASS $1"; } +fail() { echo "FAIL $1"; faults=$((faults+1)); } + +# leg 1 -- the selftest +if python3 "$TOOL" --selftest >/tmp/q147-selftest.$$ 2>&1; then + pass "selftest $(tail -1 /tmp/q147-selftest.$$ | sed 's/selftest: //')" +else + fail "selftest"; tail -3 /tmp/q147-selftest.$$ +fi +rm -f /tmp/q147-selftest.$$ + +# leg 2 -- the artifact at its pin +out="$(python3 "$TOOL" --check --repo "$ROOT" 2>&1)"; rc=$? +case "$rc" in + 0) pass "artifact $(echo "$out" | tail -1 | sed 's/VERDICT: //')" ;; + 1) fail "artifact rc=1"; echo "$out" | grep '^FAIL' | head -3 ;; + *) fail "artifact rc=$rc (could not grade)"; echo "$out" | tail -2 ;; +esac + +# leg 3 -- no host path in the tooling it grades itself with +if grep -n '/root/' "$TOOL" "$ART/CHECK" "$ART/extract_workqueue_census.py" >/tmp/q147-host.$$ 2>&1; then + fail "host path in the tooling"; head -3 /tmp/q147-host.$$ +else + pass "tooling names no host path" +fi +rm -f /tmp/q147-host.$$ + +# leg 4 -- the baseline row agrees with what this tree reads +BASE="$ROOT/wizard-work/volt/q143-check-sweep/check_entry_baseline.tsv" +row="$(grep -P '^wizard-work/ledger/workqueue-census/CHECK\t' "$BASE" 2>/dev/null)" +if [ -z "$row" ]; then + fail "baseline row missing" +elif [ "$(printf '%s' "$row" | cut -f2)" = "0" ]; then + pass "baseline row rc=0" +else + fail "baseline row rc=$(printf '%s' "$row" | cut -f2)" +fi + +echo "q147: $((4-faults)) of 4 leg(s) passed" +[ "$faults" -eq 0 ] || exit 1 +exit 0 diff --git a/wizard-work/ledger/workqueue-census/CHECK b/wizard-work/ledger/workqueue-census/CHECK old mode 100644 new mode 100755 index 993c51f..4ec7a6b --- a/wizard-work/ledger/workqueue-census/CHECK +++ b/wizard-work/ledger/workqueue-census/CHECK @@ -1,58 +1,47 @@ #!/usr/bin/env bash -# CHECK -- workqueue-census extraction verification. +# CHECK -- workqueue-census: the census re-derives from WORK-QUEUE.md AT ITS PIN. # -# Verdict: exit 0 iff the committed workqueue-census.tsv re-derives exactly from -# WORK-QUEUE.md (96 headings, header exact, no duplicate/empty q, round-trip -# equality of the (q, title) pair), and the committed copy is byte-identical to -# the ledger output dir's copy. +# What was wrong (Q147, measured at 50cc5bb in a clean clone): this entry point +# asserted that the committed TSV re-derives from WORK-QUEUE.md as it stands on +# disk. The queue is the one document every lane appends to, so the check graded +# the calendar: rc 0 for one day, then `expected 96 headings, got 97`, rc 1 +# forever. It also compared only the (q,title) pairs -- a mutated `status` and a +# mutated `done_implies` both printed PASS, rc 0 (measured at 95b6964). # -# Single bare command whose exit code IS the verdict: -# bash /root/troupe-standup/wizard-work/ledger/workqueue-census/CHECK +# What it grades now, at the rev the manifest pins: +# 1 the pin resolves and WORK-QUEUE.md at it hashes to the manifest's blob +# 2 the committed TSV header is exact and every row is four cells +# 3 the TSV equals an independent re-derivation, all four columns, doc order +# 4 the markdown render equals the same derivation, row for row +# 5 the manifest's counts (rows, distinct q, reopened q, columns) are measured +# 6 extracted_at_utc parses as UTC and is not older than the pin's commit +# and prints `currency:` -- how far HEAD has moved past the pin -- as an +# advisory that never decides the verdict. +# +# rc 0 the artifact is true at its pin +# rc 1 a graded fault +# rc 2 it could not grade (no repo, no manifest, no rev, unresolvable rev, +# WORK-QUEUE.md absent at the pin, unreadable artifact) set -u -cd "$(dirname "${BASH_SOURCE[0]}")" || exit 1 -REPO_ROOT="$(pwd)" -# WORK-QUEUE.md lives at the troupe repo root; the CHECK script sits in -# wizard-work/ledger/workqueue-census/, so climb out of it. -REPO_ROOT="$(cd "$REPO_ROOT/../../.." && pwd)" -cd "$REPO_ROOT" || exit 1 +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" || { echo "CANNOT GRADE: no such directory"; exit 2; } +REPO="$(git -C "$HERE" rev-parse --show-toplevel 2>/dev/null)" || { echo "CANNOT GRADE: $HERE is not in a git repository"; exit 2; } +[ -n "$REPO" ] || { echo "CANNOT GRADE: no git toplevel for $HERE"; exit 2; } -python3 - "$REPO_ROOT" <<'PY' -import re -import sys +TOOL="$HERE/verify_workqueue_census.py" +[ -f "$TOOL" ] || { echo "CANNOT GRADE: missing $TOOL"; exit 2; } -repo = sys.argv[1] -src_path = f"{repo}/WORK-QUEUE.md" -census_dir = f"{repo}/wizard-work/ledger/workqueue-census" -tsv_path = f"{census_dir}/workqueue-census.tsv" +# The basename is spelled on the invocation line so the Q65 wiring census reads +# this entry point as an invocation and not as prose (same directory, so the +# bare-basename rule applies). Measured: `q63_verify_scan.py --repo .` classes +# this file `wired-invoke` at the landing rev. +python3 "$HERE/verify_workqueue_census.py" --selftest >/dev/null 2>&1 \ + || { echo "FAIL: selftest did not read green"; python3 "$HERE/verify_workqueue_census.py" --selftest | tail -5; exit 1; } +echo "PASS selftest (13 cells)" -# --- 1. re-derive from source --- -src = open(src_path, encoding="utf-8").read() -heads = [(m.group(1), " ".join(m.group(2).split())) for m in re.finditer(r"^##\s+(Q\d+)(.*)$", src, re.M)] -assert len(heads) == 96, f"expected 96 headings, got {len(heads)}" - -# --- 2. read committed tsv --- -lines = open(tsv_path, encoding="utf-8").read().splitlines() -header, data = lines[0], lines[1:] -assert header == "q\ttitle\tstatus\tdone_implies", f"bad header: {header!r}" -assert len(data) == 96, f"expected 96 data rows, got {len(data)}" - -# --- 3. round-trip equality of the (q, title) pairs, as a multiset (Q labels -# are legitimately re-opened, so equal labels may appear more than once) --- -derived_pairs = heads # list of (q, title) -committed_pairs = [] -for r in data: - parts = r.split("\t") - assert len(parts) == 4, f"row not 4 cols: {r!r}" - assert parts[0], "empty q" - committed_pairs.append((parts[0], parts[1])) - -from collections import Counter - -assert Counter(committed_pairs) == Counter(derived_pairs), ( - "title/q multiset differs between source and committed TSV" -) -assert all(q for q, _ in committed_pairs), "empty q present" - -print(f"CHECK workqueue-census: PASS (96 rows, header exact, round-trip OK)") -PY -exit $? \ No newline at end of file +python3 "$TOOL" --check --repo "$REPO" +rc=$? +case "$rc" in + 0) echo "CHECK workqueue-census: PASS"; exit 0 ;; + 1) echo "CHECK workqueue-census: FAIL"; exit 1 ;; + *) echo "CHECK workqueue-census: CANNOT GRADE (rc=$rc)"; exit 2 ;; +esac diff --git a/wizard-work/ledger/workqueue-census/README.md b/wizard-work/ledger/workqueue-census/README.md index 3ffa51a..4ea37e4 100644 --- a/wizard-work/ledger/workqueue-census/README.md +++ b/wizard-work/ledger/workqueue-census/README.md @@ -1,13 +1,20 @@ -# Work queue census (extract, 2026-10-28) +# Work queue census (extract, pinned at `95b6964`) ## What this is -A census table of every Q-section heading in the troupe work queue (`WORK-QUEUE.md`). +A census table of every Q-section heading in the troupe work queue (`WORK-QUEUE.md`) +**as it stood at commit `95b69640feeb` (2026-10-28)**, the rev that wrote it. One row per heading: the verbatim question label (`q`), the verbatim heading title, the verbatim `**Status:**` line, and the verbatim first line of the `**Done means:**` obligation. +A census is the class a subject held when it was read. `WORK-QUEUE.md` is the one +document every lane appends to, so this artifact names the rev it read and is graded +at that rev — not at whatever the file says today. + ## Source -- `WORK-QUEUE.md` in the repo root (96 `## Q` headings). +- `WORK-QUEUE.md` at `95b69640feeb0fa1c451bf84fd03895a38d6e27b` + (blob `c431b2576f6fbf0f306a91be5e2740e8370c0cdc`, 96 `## Q` headings). +- Both are recorded in `manifest.json` (`rev`, `source_blob`) and graded by `CHECK`. ## Columns | Column | Meaning | @@ -18,7 +25,7 @@ obligation. | `done_implies` | First line of the `**Done means:**` obligation | ## Findings -- **96 rows** parsed from the source. +- **96 rows** parsed from the source at the pin. - **11 Q labels are re-opened** (the file is a running log and re-enters old items): `Q37, Q38, Q39, Q43, Q60, Q72, Q79, Q81, Q82, Q83, Q93`. These are **not** duplicates of distinct questions; they are the same label @@ -27,7 +34,21 @@ obligation. spaces so the TSV is one row per Q. ## Reproduce - python3 extract_workqueue_census.py + python3 extract_workqueue_census.py # re-write at the pinned rev + python3 extract_workqueue_census.py --rev # re-pin and re-write + +`extract_workqueue_census.py` is a wrapper over the verifier's `--write`, so the +builder and the checker cannot disagree about what a census is. ## Verify bash CHECK + +`CHECK` runs `verify_workqueue_census.py --selftest` (13 cells) and then `--check`, +which grades 17 legs at the pin: the pin resolves, the queue blob at it matches the +manifest, the TSV re-derives **cell by cell in all four columns** in document order, +the markdown render matches the same derivation, the manifest's counts are measured, +and `extracted_at_utc` is not older than the pin's commit. It also prints a +`currency:` line saying how far HEAD has moved past the pin — advisory only, because +a census of a growing document is stale by construction. + +Exit codes: `0` true at the pin, `1` a graded fault, `2` could not grade. diff --git a/wizard-work/ledger/workqueue-census/extract_workqueue_census.py b/wizard-work/ledger/workqueue-census/extract_workqueue_census.py old mode 100644 new mode 100755 index 99c6b19..9b0d317 --- a/wizard-work/ledger/workqueue-census/extract_workqueue_census.py +++ b/wizard-work/ledger/workqueue-census/extract_workqueue_census.py @@ -1,159 +1,64 @@ #!/usr/bin/env python3 -"""Extract a census table from the troupe work queue. +"""Extract the workqueue census -- a wrapper over the verifier's --write. -Source of record: /root/troupe-standup/WORK-QUEUE.md -- the queue's Q-section -headings (96 of them), each carrying a status line and a "Done means:" line. +Q147 (2026-11-01): this file used to be a second implementation of the same +derivation, with three absolute host paths baked in (`SRC`, `OUT`, `REPO_OUT`), +a schema string of its own, and a literal `extracted_at_utc`. Two copies of one +rule is how the quill lane's artifact came to have a generator and a verifier +that disagreed about what a bare command is (Q142); one copy is how the ledger +directory census stopped being able to disagree with itself (Q141). -Output (toward /root/.hermes/wizard-outputs/ledger/workqueue-census/ and the -committed /root/troupe-standup/wizard-work/ledger/workqueue-census/): - - workqueue-census.tsv : tab-separated census - - workqueue-census.md : rendered markdown table - - manifest.json : machine-readable row/column record +So this is now a wrapper: it calls `verify_workqueue_census.py --write`, which +derives the rows, writes the TSV, the markdown render and the manifest, and +pins the rev it read. There is nothing here to drift. -Every row carries the verbatim heading title, the verbatim status text, and the -verbatim first line of the "Done means:" obligation. No field is derived or -inferred; extraction is unambiguous string capture. +USAGE + python3 extract_workqueue_census.py # re-write at the pinned rev + python3 extract_workqueue_census.py --rev # re-pin and re-write + python3 extract_workqueue_census.py --out DIR # write a copy elsewhere + +Exit codes: 0 wrote, 2 could not (no repo, no pin, unresolvable rev). """ +import argparse import json -import re +import os +import subprocess import sys -from pathlib import Path -SRC = Path("/root/troupe-standup/WORK-QUEUE.md") -OUT = Path("/root/.hermes/wizard-outputs/ledger/workqueue-census") -REPO_OUT = Path("/root/troupe-standup/wizard-work/ledger/workqueue-census") - -# Heading: '## Q ' -- the title is captured verbatim from the -# line after the label (some headings carry a '§k' sub-mark; we keep it). -HEADING_RE = re.compile(r"^##\s+(Q\d+)(.*)$", re.M) - -# Status: '**Status: **' -- text up to the closing '**'. -STATUS_RE = re.compile(r"\*\*Status:\s*(.*?)\*\*", re.S) - -# Done means: first line immediately following '**Done means:**'. -DONE_RE = re.compile(r"\*\*Done means:\*\s*(.+)$", re.M) - - -def parse_sections(text): - """Return (rows, duplicates) where rows is a list of dicts.""" - headings = HEADING_RE.findall(text) - q_numbers = [h[0] for h in headings] - duplicates = sorted( - {q for q in q_numbers if q_numbers.count(q) > 1} - ) - - rows = [] - for (q, title), m in zip(headings, HEADING_RE.finditer(text)): - block = text[m.end():] - nxt = HEADING_RE.search(block) - if nxt is not None: - block = block[: nxt.start()] - status_m = STATUS_RE.search(block) - status = clean(status_m.group(1)) if status_m else "" - done_m = DONE_RE.search(block) - done = clean(done_m.group(1)) if done_m else "" - rows.append( - { - "q": q, - "title": clean(title), - "status": status, - "done_implies": done, - } - ) - return rows, duplicates - - -def clean(s): - """Collapse all whitespace (newlines/tabs) to single spaces - keeps the - census one row per Q in both the TSV and the markdown table.""" - return " ".join(str(s).split()) +HERE = os.path.dirname(os.path.abspath(__file__)) +TOOL = os.path.join(HERE, "verify_workqueue_census.py") +MANIFEST = os.path.join(HERE, "manifest.json") def main(): - if not SRC.is_file(): - print(f"FATAL: source not found: {SRC}", file=sys.stderr) - return 1 + ap = argparse.ArgumentParser() + ap.add_argument("--rev", help="rev to pin (default: the rev the manifest names)") + ap.add_argument("--out", help="write the artifact to another directory") + a = ap.parse_args() - text = SRC.read_text(encoding="utf-8") - rows, duplicates = parse_sections(text) + rev = a.rev + if not rev: + try: + rev = json.load(open(MANIFEST, encoding="utf-8"))["rev"] + except (OSError, ValueError, KeyError) as exc: + print("CANNOT GRADE: no pin in %s and no --rev given (%s)" % (MANIFEST, exc), + file=sys.stderr) + return 2 - print(f"source: {SRC}") - print(f"rows parsed: {len(rows)}") - print(f"duplicates (re-opened Q labels): {duplicates or 'none'}") - print(f"distinct Q labels: {len({r['q'] for r in rows})}") - - # Spot-checks (informational; real verification lives in CHECK). - by_q = {r["q"]: r for r in rows} - for q, needle in (("Q1", "CLOSED — 0/15 recovered"), ("Q2", "DONE — recovered.")): - st = by_q.get(q, {}).get("status", "") - print(f" spot[{q}]: {'OK' if needle in st else 'MISMATCH'} ({st[:50]!r})") - - # ---- write outputs (ledger output dir + troupe committed dir) ---- - out_dirs = [OUT, REPO_OUT] - for d in out_dirs: - d.mkdir(parents=True, exist_ok=True) - - def write(path, content): - path.write_text(content, encoding="utf-8", newline="\n") - - # TSV - tsv_path = OUT / "workqueue-census.tsv" - tsv_content = "q\ttitle\tstatus\tdone_implies\n" - for r in rows: - tsv_content += "\t".join( - [ - r["q"], - r["title"].replace("\t", " "), - r["status"].replace("\t", " "), - r["done_implies"].replace("\t", " "), - ] - ) + "\n" - write(tsv_path, tsv_content) - write(REPO_OUT / "workqueue-census.tsv", tsv_content) - - # Markdown table - md_path = OUT / "workqueue-census.md" - md_content = "# Work queue census (extract, 2026-10-28)\n\n" - md_content += "Source: `WORK-QUEUE.md` (line count recorded in `manifest.json`).\n\n" - md_content += "| Q | Title | Status | Done means |\n" - md_content += "|---|---|---|---|\n" - for r in rows: - md_content += ( - "| " - + r["q"] - + " | " - + r["title"].replace("|", "\\|") - + " | " - + r["status"].replace("|", "\\|") - + " | " - + r["done_implies"].replace("|", "\\|") - + " |\n" - ) - md_content += ( - f"\n*Census rows: {len(rows)}. Q labels re-opened: {', '.join(duplicates) if duplicates else 'none'}.*\n" - ) - write(md_path, md_content) - write(REPO_OUT / "workqueue-census.md", md_content) - - # manifest - manifest = { - "schema": "workqueue-census/v1", - "source": str(SRC), - "rows": len(rows), - "columns": ["q", "title", "status", "done_implies"], - "distinct_q_labels": len({r["q"] for r in rows}), - "reopened_q_labels": duplicates, - "extracted_at_utc": "2026-10-28T00:00:00Z", - } - write(OUT / "manifest.json", json.dumps(manifest, indent=2)) - write(REPO_OUT / "manifest.json", json.dumps(manifest, indent=2)) - - print(f"wrote: {tsv_path}") - print(f"wrote: {md_path}") - print(f"wrote: {REPO_OUT / 'workqueue-census.tsv'} (committed copy)") - print(f"wrote: {REPO_OUT / 'workqueue-census.md'} (committed copy)") - print(f"wrote: {REPO_OUT / 'manifest.json'} (committed copy)") + cmd = [sys.executable, TOOL, "--write", "--rev", rev, "--repo", HERE] + if a.out: + cmd += ["--out", a.out] + p = subprocess.run(cmd, capture_output=True, text=True) + sys.stdout.write(p.stdout) + sys.stderr.write(p.stderr) + if p.returncode != 0: + return 2 + man = json.load(open(os.path.join(a.out or HERE, "manifest.json"), encoding="utf-8")) + print("pin: %s rows: %d distinct q: %d reopened: %d" + % (man["rev"][:12], man["rows"], man["distinct_q_labels"], + len(man["reopened_q_labels"]))) + print("verify with: bash %s/CHECK" % HERE) return 0 diff --git a/wizard-work/ledger/workqueue-census/manifest.json b/wizard-work/ledger/workqueue-census/manifest.json index f4a6109..dd621e7 100644 --- a/wizard-work/ledger/workqueue-census/manifest.json +++ b/wizard-work/ledger/workqueue-census/manifest.json @@ -1,6 +1,8 @@ { - "schema": "workqueue-census/v1", - "source": "/root/troupe-standup/WORK-QUEUE.md", + "schema": "workqueue-census/v2", + "source": "WORK-QUEUE.md", + "rev": "95b69640feeb0fa1c451bf84fd03895a38d6e27b", + "source_blob": "c431b2576f6fbf0f306a91be5e2740e8370c0cdc", "rows": 96, "columns": [ "q", @@ -22,5 +24,6 @@ "Q83", "Q93" ], - "extracted_at_utc": "2026-10-28T00:00:00Z" -} \ No newline at end of file + "generated_by": "verify_workqueue_census.py --write", + "extracted_at_utc": "2026-11-01T11:42:21Z" +} diff --git a/wizard-work/ledger/workqueue-census/verify_workqueue_census.py b/wizard-work/ledger/workqueue-census/verify_workqueue_census.py new file mode 100755 index 0000000..301e049 --- /dev/null +++ b/wizard-work/ledger/workqueue-census/verify_workqueue_census.py @@ -0,0 +1,536 @@ +#!/usr/bin/env python3 +"""verify_workqueue_census.py -- grade the workqueue-census artifact at a pinned rev. + +WHY THIS EXISTS (Q147, 2026-11-01) + The artifact `wizard-work/ledger/workqueue-census/` is a census of the `## Q` + sections of `WORK-QUEUE.md`, written 2026-10-28 at `95b6964`. Its CHECK asserted + that the committed TSV re-derives from WORK-QUEUE.md **as it stands on disk**. + WORK-QUEUE.md is the one document every lane appends to, so that assertion is a + function of the clock, not of the artifact: it read rc 0 for one day and a + traceback (`expected 96 headings, got 97`) ever after -- and it never graded the + two columns that carry the census's substance. + + A census is the class a subject held WHEN IT WAS READ. Without a rev in the + artifact, the same rows read as current forever (Q141's rule, applied here). + +WHAT IT GRADES + Subject `WORK-QUEUE.md` at the rev the manifest pins (`manifest["rev"]`). + Artifact the committed `workqueue-census.tsv`, its `workqueue-census.md` + render, and `manifest.json`. + Legs 1 the pin resolves and the queue blob at it hashes to the manifest's + 2 the TSV header is exact and every row has four non-empty-safe cells + 3 the TSV equals an independent re-derivation at the pin, cell by + cell, in document order -- all four columns, not (q,title) alone + 4 the markdown render equals the same derivation, row for row + 5 the manifest's counts equal what was measured (rows, distinct q, + reopened q, queue blob, schema, repo-relative source) + 6 `extracted_at_utc` parses as UTC and is not older than the pin's + commit date (a literal timestamp is not a measurement) + Advisory `currency:` compares the pin with HEAD and says how far past it the + document has moved. It never decides the verdict: a census of a + moving document is stale by construction, and a check that reds for + that would be the defect it replaces. + +EXIT CODES + 0 pass + 1 a graded fault + 2 could not grade (no git repo, no manifest, no rev, unresolvable rev, + WORK-QUEUE.md absent at the rev, unreadable artifact) + +USAGE + python3 verify_workqueue_census.py --check [--repo DIR] + python3 verify_workqueue_census.py --write --rev [--repo DIR] [--out DIR] + python3 verify_workqueue_census.py --selftest +""" + +from __future__ import annotations + +import argparse +import json +import os +import re +import shutil +import subprocess +import sys +import tempfile +from collections import Counter +from datetime import datetime, timezone + +ARTIFACT_REL = os.path.join("wizard-work", "ledger", "workqueue-census") +SRC_REL = "WORK-QUEUE.md" +TSV_NAME = "workqueue-census.tsv" +MD_NAME = "workqueue-census.md" +MAN_NAME = "manifest.json" +SCHEMA = "workqueue-census/v2" +COLUMNS = ["q", "title", "status", "done_implies"] +TS_FMT = "%Y-%m-%dT%H:%M:%SZ" + +HEADING = re.compile(r"^##\s+(Q\d+)(.*)$", re.M) +STATUS = re.compile(r"\*\*Status:\s*(.*?)\*\*", re.S) +DONE = re.compile(r"\*\*Done means:\*\s*(.+)$", re.M) +MD_ROW = re.compile(r"^\|\s*(Q\d+)\s*\|(.*)\|\s*$", re.M) +MD_PIPE = re.compile(r"(?` heading, four verbatim cells.""" + rows = [] + marks = list(HEADING.finditer(text)) + for i, m in enumerate(marks): + end = marks[i + 1].start() if i + 1 < len(marks) else len(text) + block = text[m.end():end] + sm = STATUS.search(block) + dm = DONE.search(block) + rows.append({ + "q": m.group(1), + "title": clean(m.group(2)), + "status": clean(sm.group(1)) if sm else "", + "done_implies": clean(dm.group(1)) if dm else "", + }) + return rows + + +def read_tsv(text): + lines = text.split("\n") + if lines and lines[-1] == "": + lines.pop() + if not lines: + raise Ungradable("committed TSV is empty") + return lines[0].split("\t"), [ln.split("\t") for ln in lines[1:]] + + +def read_md(text): + """Rows of the rendered table, with markdown pipe escapes undone. + + Split on UNESCAPED pipes only: a cell whose text contains `|` is written as + `\\|` by render_md, and splitting on every pipe would tear that cell in two + and report a mismatch the render does not have. + """ + rows = [] + for m in MD_ROW.finditer(text): + cells = [c.strip().replace("\\|", "|") for c in MD_PIPE.split(m.group(2))] + rows.append([m.group(1)] + cells) + return rows + + +def counts(rows): + qs = [r["q"] for r in rows] + distinct = sorted(set(qs)) + reopened = sorted({q for q in qs if qs.count(q) > 1}) + return distinct, reopened + + +def check(repo, rev=None, verbose=False): + """Return rc 0/1/2. Raises Ungradable only internally; the caller maps it.""" + art = os.path.join(repo, ARTIFACT_REL) + if not os.path.isdir(art): + raise Ungradable("artifact directory missing: %s" % ARTIFACT_REL) + try: + man = json.load(open(os.path.join(art, MAN_NAME), encoding="utf-8")) + except OSError as exc: + raise Ungradable("manifest unreadable: %s" % exc) + except ValueError as exc: + raise Ungradable("manifest is not JSON: %s" % exc) + + pin = rev or man.get("rev") + if not pin or not isinstance(pin, str): + raise Ungradable("manifest names no rev -- a census with no rev has no subject") + try: + pin_sha = git(repo, "rev-parse", "--verify", pin + "^{commit}").strip() + except Ungradable as exc: + raise Ungradable("pin %r does not resolve: %s" % (pin, exc)) + + try: + queue_text = git(repo, "show", "%s:%s" % (pin_sha, SRC_REL)) + except Ungradable as exc: + raise Ungradable("%s is absent at the pin: %s" % (SRC_REL, exc)) + derived = derive(queue_text) + distinct, reopened = counts(derived) + + faults, passes = [], [] + + def leg(name, ok, detail=""): + (passes if ok else faults).append((name, ok, detail)) + if verbose or not ok: + print(("PASS " if ok else "FAIL ") + name + ("" if ok else " " + str(detail))) + + # --- 1. the pin binds the artifact --------------------------------------- + blob = git(repo, "rev-parse", "%s:%s" % (pin_sha, SRC_REL)).strip() + leg("schema", man.get("schema") == SCHEMA, + "manifest schema %r != %r" % (man.get("schema"), SCHEMA)) + leg("source is repo-relative", man.get("source") == SRC_REL, + "manifest source %r -- an absolute host path cannot be re-run in a clone" + % (man.get("source"),)) + leg("manifest rev is the pin", man.get("rev") == pin_sha, + "manifest rev %r != resolved %r" % (man.get("rev"), pin_sha)) + leg("queue blob at pin", man.get("source_blob") == blob, + "manifest source_blob %r != %r" % (man.get("source_blob"), blob)) + + # --- 2-3. the TSV --------------------------------------------------------- + try: + tsv_text = open(os.path.join(art, TSV_NAME), encoding="utf-8").read() + except OSError as exc: + raise Ungradable("committed TSV unreadable: %s" % exc) + header, committed = read_tsv(tsv_text) + leg("tsv header", header == COLUMNS, "header %r != %r" % (header, COLUMNS)) + bad = [i for i, r in enumerate(committed, 1) + if len(r) != 4 or not r[0] or any("\n" in c for c in r)] + leg("every row is four cells with a q", not bad, + "first bad row %s" % (bad[0] if bad else None)) + leg("row count", len(committed) == len(derived), + "committed %d != derived %d at %s" % (len(committed), len(derived), pin_sha[:7])) + mism = [] + for i, (row, want) in enumerate(zip(committed, derived), 1): + if len(row) != 4: + continue + for col, (got, exp) in enumerate(zip(row, [want[c] for c in COLUMNS])): + if got != exp: + mism.append((i, want["q"], COLUMNS[col], got, exp)) + leg("cells equal the derivation", not mism, + "%d cell(s) differ; first: row %d %s.%s committed=%r derived=%r" % ( + len(mism), mism[0][0], mism[0][1], mism[0][2], mism[0][3][:60], mism[0][4][:60]) + if mism else "") + leg("q labels are the derivation's multiset", + Counter(r[0] for r in committed) == Counter(w["q"] for w in derived), + "duplicate/renamed q labels differ from the pin") + + # --- 4. the markdown render ---------------------------------------------- + try: + md_text = open(os.path.join(art, MD_NAME), encoding="utf-8").read() + except OSError as exc: + raise Ungradable("markdown render unreadable: %s" % exc) + md_rows = read_md(md_text) + leg("md row count", len(md_rows) == len(derived), + "md %d != derived %d" % (len(md_rows), len(derived))) + md_mism = [] + for i, (row, want) in enumerate(zip(md_rows, derived), 1): + exp = [want[c] for c in COLUMNS] + if len(row) != 4: + md_mism.append((i, want["q"], "cells", len(row), 4)) + continue + for c in range(4): + if row[c] != exp[c]: + md_mism.append((i, want["q"], COLUMNS[c], row[c][:40], exp[c][:40])) + leg("md cells equal the derivation", not md_mism, + "first mismatch %s" % (md_mism[0],) if md_mism else "") + + # --- 5. the manifest's counts --------------------------------------------- + leg("manifest rows", man.get("rows") == len(derived), + "manifest %r != derived %d" % (man.get("rows"), len(derived))) + leg("manifest distinct q", man.get("distinct_q_labels") == len(distinct), + "manifest %r != measured %d" % (man.get("distinct_q_labels"), len(distinct))) + leg("manifest reopened q", man.get("reopened_q_labels") == reopened, + "manifest %r != measured %r" % (man.get("reopened_q_labels"), reopened)) + leg("manifest columns", man.get("columns") == COLUMNS, + "manifest %r != %r" % (man.get("columns"), COLUMNS)) + + # --- 6. the timestamp is a measurement ------------------------------------ + ts = man.get("extracted_at_utc") + when = None + try: + when = datetime.strptime(ts, TS_FMT).replace(tzinfo=timezone.utc) + except (TypeError, ValueError): + pass + leg("extracted_at_utc parses", when is not None, "%r is not %s" % (ts, TS_FMT)) + if when is not None: + try: + pin_date = datetime.strptime( + git(repo, "show", "-s", "--format=%ad", "--date=short", pin_sha).strip(), + "%Y-%m-%d").replace(tzinfo=timezone.utc) + leg("extracted_at_utc is not older than the pin", when >= pin_date, + "timestamp %s precedes the pin's commit date %s" + % (ts, pin_date.strftime("%Y-%m-%d"))) + except Ungradable as exc: + raise Ungradable("cannot date the pin: %s" % exc) + + # --- advisory: how far HEAD has moved ------------------------------------ + try: + head = git(repo, "rev-parse", "HEAD").strip() + head_rows = derive(git(repo, "show", "%s:%s" % (head, SRC_REL))) + a = Counter((r["q"], r["title"]) for r in derived) + b = Counter((r["q"], r["title"]) for r in head_rows) + added, removed = sum((b - a).values()), sum((a - b).values()) + changed = 0 + bq = {r["q"]: r for r in head_rows} + aq = {r["q"]: r for r in derived} + for q in aq: + if q in bq and any(aq[q][c] != bq[q][c] for c in COLUMNS): + changed += 1 + print("currency: HEAD %s is past the pin %s -- %d added, %d removed, %d changed " + "(advisory only)" % (head[:12], pin_sha[:12], added, removed, changed)) + except (Ungradable, ValueError): + print("currency: could not compare with HEAD (advisory only)") + + for name, _, _ in passes: + print("PASS " + name) + if faults: + print("\nVERDICT: FAIL -- %d of %d leg(s) faulted at %s" + % (len(faults), len(faults) + len(passes), pin_sha[:7])) + return 1 + print("\nVERDICT: PASS -- %d rows re-derived at %s, all four columns, %d leg(s)" + % (len(derived), pin_sha[:12], len(passes))) + return 0 + + +def render_tsv(rows): + out = ["\t".join(COLUMNS)] + for r in rows: + out.append("\t".join(r[c].replace("\t", " ").replace("\n", " ") for c in COLUMNS)) + return "\n".join(out) + "\n" + + +def render_md(rows, rev): + out = ["# Work queue census (extract, pinned at %s)" % rev[:7], "", + "Source: `%s`, read at commit `%s`." % (SRC_REL, rev), "", + "| Q | Title | Status | Done means |", "|---|---|---|---|"] + for r in rows: + cells = [r[c].replace("|", "\\|") for c in COLUMNS] + out.append("| " + " | ".join(cells) + " |") + out.append("") + distinct, reopened = counts(rows) + out.append("*Census rows: %d. Distinct q labels: %d. Re-opened: %s.*" + % (len(rows), len(distinct), ", ".join(reopened) if reopened else "none")) + return "\n".join(out) + "\n" + + +def write_artifact(repo, rev, out_dir=None): + pin_sha = git(repo, "rev-parse", "--verify", rev + "^{commit}").strip() + queue_text = git(repo, "show", "%s:%s" % (pin_sha, SRC_REL)) + blob = git(repo, "rev-parse", "%s:%s" % (pin_sha, SRC_REL)).strip() + rows = derive(queue_text) + distinct, reopened = counts(rows) + dest = out_dir or os.path.join(repo, ARTIFACT_REL) + os.makedirs(dest, exist_ok=True) + open(os.path.join(dest, TSV_NAME), "w", encoding="utf-8").write(render_tsv(rows)) + open(os.path.join(dest, MD_NAME), "w", encoding="utf-8").write(render_md(rows, pin_sha)) + man = { + "schema": SCHEMA, + "source": SRC_REL, + "rev": pin_sha, + "source_blob": blob, + "rows": len(rows), + "columns": COLUMNS, + "distinct_q_labels": len(distinct), + "reopened_q_labels": reopened, + "generated_by": "verify_workqueue_census.py --write", + "extracted_at_utc": datetime.now(timezone.utc).strftime(TS_FMT), + } + open(os.path.join(dest, MAN_NAME), "w", encoding="utf-8").write( + json.dumps(man, indent=2) + "\n") + print("wrote %s: %d rows, pin %s, blob %s" % (dest, len(rows), pin_sha[:12], blob[:12])) + return dest, rows + + +def selftest(): + """Cells on a throwaway repo: the defect and the six ways it must red.""" + d = tempfile.mkdtemp(prefix="q147-selftest-") + env = dict(os.environ, GIT_AUTHOR_NAME="t", GIT_AUTHOR_EMAIL="t@t", + GIT_COMMITTER_NAME="t", GIT_COMMITTER_EMAIL="t@t") + subprocess.run(["git", "init", "-q", d], check=True, env=env) + art = os.path.join(d, ARTIFACT_REL) + os.makedirs(art, exist_ok=True) + + queue_v1 = ( + "# queue\n\n## Q1 — first item\n\n**Status: OPEN.** Body.\n\n" + "**Done means:** the first thing lands.\n\n" + "## Q2 — second item\n\n**Status: DONE at abc123.** Body.\n\n" + "**Done means:** the second thing lands.\n\n" + "## Not an item\n\ntext\n") + open(os.path.join(d, SRC_REL), "w").write(queue_v1) + subprocess.run(["git", "-C", d, "add", "-A"], check=True, env=env) + subprocess.run(["git", "-C", d, "commit", "-qm", "v1"], check=True, env=env) + + cells, failed = [], 0 + + def cell(name, rc_got, rc_want, extra=""): + nonlocal failed + ok = rc_got == rc_want + cells.append((name, ok, rc_got, rc_want, extra)) + if not ok: + failed += 1 + + def run(args, repo): + p = subprocess.run([sys.executable, __file__, *args, "--repo", repo], + capture_output=True, text=True) + return p.returncode, p.stdout + p.stderr + + # green control, written at the pin + write_artifact(d, "HEAD") + rc, out = run(["--check"], d) + cell("green-control", rc, 0, out.strip().splitlines()[-1][:70]) + + mpath = os.path.join(art, MAN_NAME) + tpath = os.path.join(art, TSV_NAME) + orig_man = open(mpath).read() + orig_tsv = open(tpath).read() + + def restore(): + open(mpath, "w").write(orig_man) + open(tpath, "w").write(orig_tsv) + + # 1. a status cell moved -- the column the old CHECK could not see + rows = orig_tsv.split("\n") + p = rows[1].split("\t") + p[2] = "MUTATED STATUS" + rows[1] = "\t".join(p) + open(tpath, "w").write("\n".join(rows)) + rc, out = run(["--check"], d) + cell("status-cell-reds", rc, 1, "MUTATED STATUS" if "MUTATED" in out else "silent") + restore() + + # 2. a done_implies cell moved + rows = orig_tsv.split("\n") + p = rows[2].split("\t") + p[3] = "MUTATED DONE" + rows[2] = "\t".join(p) + open(tpath, "w").write("\n".join(rows)) + rc, _ = run(["--check"], d) + cell("done-cell-reds", rc, 1) + restore() + + # 3. a markdown render cell moved -- and the FAIL line prints instead of a + # traceback (a formatter handed a tuple raises before it can say anything; + # that is the defect Q146 found in another lane's entry point). + mpath_md = os.path.join(art, MD_NAME) + orig_md = open(mpath_md).read() + open(mpath_md, "w").write(orig_md.replace("| OPEN. |", "| MUTATED MD |", 1)) + rc, out = run(["--check"], d) + cell("md-cell-reds", rc, 1, + "traceback" if "Traceback" in out else ("named" if "FAIL md cells" in out else "silent")) + open(mpath_md, "w").write(orig_md) + + # 4. a row dropped + rows = orig_tsv.split("\n") + open(tpath, "w").write("\n".join(rows[:-2] + [""])) + rc, _ = run(["--check"], d) + cell("dropped-row-reds", rc, 1) + restore() + + # 4. the manifest's row count lies + man = json.loads(orig_man) + man["rows"] = 99 + open(mpath, "w").write(json.dumps(man)) + rc, _ = run(["--check"], d) + cell("manifest-count-reds", rc, 1) + restore() + + # 5. a manifest with no rev -- ungradable, not a pass + man = json.loads(orig_man) + del man["rev"] + open(mpath, "w").write(json.dumps(man)) + rc, _ = run(["--check"], d) + cell("no-rev-ungradable", rc, 2) + restore() + + # 6. a rev that does not resolve -- ungradable + man = json.loads(orig_man) + man["rev"] = "0" * 40 + open(mpath, "w").write(json.dumps(man)) + rc, _ = run(["--check"], d) + cell("unknown-rev-ungradable", rc, 2) + restore() + + # 7. the moving subject: the queue grows at HEAD, the pin still green + open(os.path.join(d, SRC_REL), "a").write( + "\n## Q3 — third item\n\n**Status: OPEN.**\n\n**Done means:** third.\n") + subprocess.run(["git", "-C", d, "commit", "-qam", "v2"], check=True, env=env) + rc, out = run(["--check"], d) + cell("queue-grows-pin-stays-green", rc, 0, + "advisory" if "1 added" in out else "no advisory line") + + # 8. the pretender: the same grown queue, re-pinned without re-writing + man = json.loads(orig_man) + man["rev"] = subprocess.run(["git", "-C", d, "rev-parse", "HEAD"], + capture_output=True, text=True).stdout.strip() + open(mpath, "w").write(json.dumps(man)) + rc, _ = run(["--check"], d) + cell("repinned-without-rewrite-reds", rc, 1) + restore() + + # 9. a host-absolute source in the manifest + man = json.loads(orig_man) + man["source"] = os.path.join(d, SRC_REL) + open(mpath, "w").write(json.dumps(man)) + rc, _ = run(["--check"], d) + cell("host-path-source-reds", rc, 1) + restore() + + # 10. a timestamp older than the pin + man = json.loads(orig_man) + man["extracted_at_utc"] = "2000-01-01T00:00:00Z" + open(mpath, "w").write(json.dumps(man)) + rc, _ = run(["--check"], d) + cell("stale-timestamp-reds", rc, 1) + restore() + + # 11. two takes at one rev are byte-identical + write_artifact(d, "HEAD") + a = open(tpath, "rb").read() + write_artifact(d, "HEAD") + b = open(tpath, "rb").read() + cell("write-is-deterministic", 0 if a == b else 1, 0, + "" if a == b else "%d vs %d bytes" % (len(a), len(b))) + + shutil.rmtree(d, ignore_errors=True) + print() + for name, ok, got, want, extra in cells: + print(" %-30s %s rc=%d want=%d %s" + % (name, "ok " if ok else "FAIL", got, want, extra)) + print("\nselftest: %d cell(s), %d passed, %d failed" + % (len(cells), len(cells) - failed, failed)) + return 1 if failed else 0 + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--repo", default=".") + ap.add_argument("--rev") + ap.add_argument("--check", action="store_true") + ap.add_argument("--write", action="store_true") + ap.add_argument("--out") + ap.add_argument("--selftest", action="store_true") + ap.add_argument("--verbose", action="store_true") + a = ap.parse_args() + + if a.selftest: + return selftest() + repo = os.path.abspath(a.repo) + try: + repo = git(repo, "rev-parse", "--show-toplevel").strip() + except Ungradable as exc: + print("CANNOT GRADE: not a git repository: %s" % exc) + return 2 + if a.write: + if not a.rev: + print("--write needs --rev") + return 2 + try: + write_artifact(repo, a.rev, a.out) + except Ungradable as exc: + print("CANNOT GRADE: %s" % exc) + return 2 + return 0 + try: + return check(repo, rev=a.rev, verbose=a.verbose) + except Ungradable as exc: + print("CANNOT GRADE: %s" % exc) + return 2 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/wizard-work/ledger/workqueue-census/workqueue-census.md b/wizard-work/ledger/workqueue-census/workqueue-census.md index d65e3fd..66493ff 100644 --- a/wizard-work/ledger/workqueue-census/workqueue-census.md +++ b/wizard-work/ledger/workqueue-census/workqueue-census.md @@ -1,6 +1,6 @@ -# Work queue census (extract, 2026-10-28) +# Work queue census (extract, pinned at 95b6964) -Source: `WORK-QUEUE.md` (line count recorded in `manifest.json`). +Source: `WORK-QUEUE.md`, read at commit `95b69640feeb0fa1c451bf84fd03895a38d6e27b`. | Q | Title | Status | Done means | |---|---|---|---| @@ -101,4 +101,4 @@ Source: `WORK-QUEUE.md` (line count recorded in `manifest.json`). | Q97 | — a contract-graded refusal accepts an argparse usage error, so a renamed flag turns the whole malformed axis green *(no lane owns it; opened 2026-10-27 by the pipe, at `9878f12`)* | open and unclaimed. | * a refusal is graded on the contract **and** on evidence that it is about the input — either the message must not match the argparse failure shapes (`usage:` lead, `unrecognized arguments`, `error: argument`) or it must name the path the probe passed — and a renamed-flag mutant reds the malformed axis at a fixed head, with the same treatment applied to the read axis (which is where the hole is older). **Evidence:** the mutant diff, both sweep summaries with their rc, and the judge calls above; the new cell must be shown to fail on the mutant and pass on the clean head. | | Q98 | — seven committed test files resolve their module from a path outside the repo, and the class guard Q61 promised was never written *(no lane owns it; opened 2026-10-27 by the pipe, at `5886bdd`)* | open and unclaimed. | * a committed check that fails when any `test_*.py` under `wizard-work/` resolves an imported module | -*Census rows: 96. Q labels re-opened: Q37, Q38, Q39, Q43, Q60, Q72, Q79, Q81, Q82, Q83, Q93.* +*Census rows: 96. Distinct q labels: 85. Re-opened: Q37, Q38, Q39, Q43, Q60, Q72, Q79, Q81, Q82, Q83, Q93.* diff --git a/wizard-work/volt/q143-check-sweep/check_entry_baseline.tsv b/wizard-work/volt/q143-check-sweep/check_entry_baseline.tsv index 0396aaf..c529b9e 100644 --- a/wizard-work/volt/q143-check-sweep/check_entry_baseline.tsv +++ b/wizard-work/volt/q143-check-sweep/check_entry_baseline.tsv @@ -4,12 +4,18 @@ # row-level re-take (Q146): wizard-work/ledger/CHECK-live-wizard-roster-2026-10-29 # code 1 -> 0, measured with this directory's own run_entry (--timeout 120) in the # Q146 tick; every other row below is d299373's reading, unchanged. +# row-level re-take (Q147): wizard-work/ledger/workqueue-census/CHECK +# code 1 -> 0, measured with this directory's own run_entry (--timeout 120) in the +# Q147 tick after the census was re-pinned at 95b6964; the row above it is +# unchanged. Note: this entry point now runs a 13-cell selftest plus a 17-leg +# check, so its reading is a function of the pin and not of the queue's length. CHECK 0 verify_selftest_sweep_q93_refactor: ALL GREEN (0 failed, all checks) CHECK-2026-11-01-ledger-dir-census 0 VERDICT: rc 0 -- the committed CSV is the derivation at the pinned rev CHECK-ledger-dir-census 0 VERDICT: rc 0 -- the committed CSV is the derivation at the pinned rev CHECK-q-checkparen 0 verify_fix: 0 leg(s) faulted CHECK-q143 0 q143: 2 leg(s), all passed CHECK-q146 0 q146: 4 leg(s), no fault +CHECK-q147 0 q147: 4 of 4 leg(s) passed CHECK-quill-draft-compliance 1 VERDICT: FAIL CHECK-sol-lane-triage-2026-10-29 0 VERIFY OK (216 files, categories re-derived, all paths present) CHECK-triage-2026-11-01 0 PASS: Triage-2026-11-01.json re-derives 8/8 items from seed evidence; decision_counts={'approve': 6, 'table': 2}, categories={'archive_fix': 5, 'app_pr': 1, 'ge @@ -58,7 +64,7 @@ wizard-work/ledger/CHECK-wizards 0 VERDICT TRUE: wizards.csv replays from WIZARD wizard-work/ledger/CHECK-workqueue-census 1 FAIL: row count mismatch wizard-work/ledger/CHECK.py 0 CHECK PASS: 50 rows | top=public-apis/public-apis stars=492140 wizard-work/ledger/workqueue-census-v2/CHECK 0 ALL CHECKS PASSED (97 rows, 86 distinct labels, 11 reopened) -wizard-work/ledger/workqueue-census/CHECK 1 Traceback (most recent call last): +wizard-work/ledger/workqueue-census/CHECK 0 CHECK workqueue-census: PASS wizard-work/null/CHECK 0 LANE GATE GREEN wizard-work/null/agentloop/CHECK 0 VERDICT: every leg passed wizard-work/sol/CHECK 0 OK: triage digest verified (15 items, 3 HOT / 10 FOUNDATIONAL / 2 NOISE).