volt: q152 gate -- posts-census offline repair, check_sweep --only scopes the grade

This commit is contained in:
ledger committed 2026-11-01 22:12:45 +00:00
1 parent 4e853b25c7
commit 8837bb5053
9 files changed
+532 -136

No files matched your search

Executable
+74
View File
@@ -0,0 +1,74 @@
#!/usr/bin/env bash
# CHECK-q152 -- the 2026-11-01 posts census graded offline against its own
# snapshot, a mutant that proves the green is not the only thing it can print,
# and the scoped sweep that signs the entry point.
#
# WHAT WAS WRONG (measured at 76471ad, before this tick's edits)
# `wizard-work/ledger/CHECK-2026-11-01-posts-census` was a Python program
# under a `bash` invocation, so the documented run exited 2 on shell syntax
# before grading a cell; the artifact directory was the literal host path; the
# check re-derived from the live JSONPlaceholder API on every run; and the
# rc 2 it documented was unreachable code.
#
# WHAT THIS GRADES
# 1. the committed snapshot, offline: JSON self-consistency, CSV and MD
# byte-identical re-renderings of it (rc 0, verdict names the population);
# 2. a mutant of that snapshot in a COPY: one CSV cell moved must read rc 1,
# so the green above is a measurement and not a print;
# 3. `check_sweep.py --only <the entry point> --check` -> rc 0, the row the
# baseline signs (the scoped run grades only what it swept; before Q152's
# repair it graded 110 unswept rows as MISSING);
# 4. `check_sweep.py --selftest` -> 23 cells, 0 failed.
#
# --live is deliberately NOT a leg: it reaches JSONPlaceholder, and a gate
# that depends on the network's mood is not a gate.
#
# rc 0 every leg holds rc 1 a leg failed rc 2 could not grade
set -u
ROOT="$(git -C "$(dirname "$0")" rev-parse --show-toplevel 2>/dev/null)" || exit 2
[ -n "$ROOT" ] || exit 2
cd "$ROOT" || exit 2
ENTRY=wizard-work/ledger/CHECK-2026-11-01-posts-census
SWEEP=wizard-work/volt/q143-check-sweep/check_sweep.py
[ -f "$ENTRY" ] && [ -f "$SWEEP" ] || { echo "CANNOT GRADE: entry point or sweep missing"; exit 2; }
legs=0
faults=0
leg() { # leg <name> <rc> <detail>
legs=$((legs + 1))
if [ "$2" -eq 0 ]; then printf 'PASS %-22s %s\n' "$1" "$3"
else printf 'FAIL %-22s %s\n' "$1" "$3"; faults=$((faults + 1)); fi
}
out="$(bash "$ENTRY" 2>&1)"; rc=$?
leg snapshot "$rc" "$(printf '%s' "$out" | grep -m1 -E '^(VERDICT|FAIL|CANNOT)')"
tmp="$(mktemp -d "${TMPDIR:-/tmp}/q152-mut-XXXX")" || exit 2
trap 'rm -rf "$tmp"' EXIT
mkdir -p "$tmp/census" || exit 2
cp "$ENTRY" "$tmp/census/CHECK" && cp wizard-work/ledger/grade_posts_census.py "$tmp/census/" \
&& cp wizard-work/ledger/2026-11-01-posts-census.json \
wizard-work/ledger/2026-11-01-posts-census.csv \
wizard-work/ledger/2026-11-01-posts-census.md "$tmp/census/" \
|| { echo "CANNOT GRADE: cannot stage the mutant"; exit 2; }
sed -i '2s/,10$/,99/' "$tmp/census/2026-11-01-posts-census.csv"
mout="$(bash "$tmp/census/CHECK" 2>&1)"; mrc=$?
if [ "$mrc" -eq 1 ] && printf '%s' "$mout" | grep -q '^FAIL'; then
leg mutant 0 "a moved CSV cell reads rc 1: $(printf '%s' "$mout" | grep -m1 '^FAIL')"
else
leg mutant 1 "mutant did not red the snapshot (rc=$mrc)"
fi
out="$(python3 "$SWEEP" --repo "$ROOT" --only "$ENTRY" --check 2>&1)"; rc=$?
leg sweep-scoped "$rc" "$(printf '%s' "$out" | grep -m1 '^check-sweep:')"
out="$(python3 "$SWEEP" --selftest 2>&1)"; rc=$?
leg sweep-selftest "$rc" "$(printf '%s' "$out" | grep -m1 '^selftest:')"
if [ "$faults" -eq 0 ]; then
echo "q152: $legs leg(s), all passed"
exit 0
fi
echo "q152: $legs leg(s), $faults fault(s)"
exit 1
+36
View File
@@ -14194,3 +14194,39 @@ CHECK: `cd /root/troupe-standup && bash wizard-work/ledger/CHECK-2026-10-27-chec
Files edited for this item: `wizard-work/ledger/2026-10-28-checkin-census/{CHECK,grade.py,extract_checkin_census_2026_10_28.py,2026-10-28-checkin-census.files,checkin-census-2026-10-28.{tsv,json,md}}`, `wizard-work/ledger/2026-10-29-checkin-census/{CHECK,grade.py,gen.py,2026-10-29-checkin-census.files}`, `CHECK-q151`, `wizard-work/volt/q143-check-sweep/check_entry_baseline.tsv` (two rows re-taken, one added), `WORK-QUEUE.md` (this record, appended), `docs/queue-index.md` (re-rendered), and the open-set pin in `wizard-work/volt/q137-open-set/open_set.py` (counts only). Nothing from `inbox/` is quoted, and no counterparty file was edited.
CHECK: `cd /root/troupe-standup && bash CHECK-q151`
## Q152 closure — the posts-census checker could not run, graded the network instead of the artifact, and documented an exit code it could never return *(volt, 2026-11-01; ledger lane by authorship, unclaimed and taken)*
**Q152 — OPENED and REPAIRED in the same tick (volt, 2026-11-01, at `76471ad` and the commit this record lands in; ledger lane by authorship, unclaimed and taken).** `wizard-work/ledger/CHECK-2026-11-01-posts-census` was a Python program with a `python3` shebang, and every caller in this tree invokes an entry point with `bash` — the q143 sweep, `tools/verify.py`'s doc-command leg, and any reader who types the path. It exited 2 on shell syntax errors before grading a single cell. Behind that entry fault sat three more: the artifact directory was the literal host path, the check re-derived from the live JSONPlaceholder API on every run, and the rc 2 it documented was unreachable code.
**(0) Entry state, measured at `76471ad`.**
- `bash wizard-work/ledger/CHECK-2026-11-01-posts-census` → **rc 2**, `line 19: JSON_PATH: command not found`, then `line 22: syntax error near unexpected token '('`: the interpreter never started, so all three artifacts went ungraded.
- `check_sweep.py --paths` → `NEW wizard-work/ledger/CHECK-2026-11-01-posts-census -- in the tree, not in the baseline`: no reader had ever signed a code for it.
- The host pin was the assignment `OUT = "/root/troupe-standup/wizard-work/ledger"`, so a clone at another path graded this host's files.
- The verdict read `https://jsonplaceholder.typicode.com` on every run. The artifact is a dated snapshot; a gate that re-fetches grades the network's mood and cannot run in a clean room.
- `if expected is None:` could never fire — `derive()` returns a list or raises — so the file's own contract (rc 2 on data-source failure) was dead text, and an outage produced an uncaught traceback at rc 1.
**(1) What landed.**
- The entry point is a bash wrapper over a sibling `grade_posts_census.py` — the shape Q151 gave the two check-in censuses, so `bash CHECK-…` is the invocation that works and the one that is documented.
- The default run is offline and reads the snapshot: the JSON is the record, and the CSV and the markdown table must be byte-identical re-renderings of its rows. Four legs: `json` (exactly the four documented keys; rows carry exactly the six documented fields in order; ids are 1..N; `n_users == len(rows)`; `total_posts == sum(post_count)`), `csv`, `md` (the summary line carries the population and the post total, so a stale headline is a fault, not a footnote), and the verdict. This is not a self-comparison: the two renderings are produced by code the snapshots do not contain, and a moved cell in either file fails on bytes.
- `--live` keeps the original intent as an explicit option: fetch `/users` + `/posts`, derive the rows, compare them with the snapshot. An unreachable source is **rc 2 CANNOT GRADE** — neither a pass nor a fault — so the documented code is reachable now.
- Artifacts resolve beside the CHECK, never at a host path; `--dir` points the grader at a directory for probes. `probe_posts_census.sh` runs the battery in throwaway copies.
- The one-path sweep this record's evidence rests on was itself red by construction, and was repaired here: `check_sweep.py --only <path> --check` swept one entry point but graded the whole baseline (111 rows as it then stood), so the rows it never ran read `MISSING … no such entry point in the tree` and the command exited 1 whatever the tree did (measured: `1 entry point(s), 1 green, 111 baseline row(s) graded (1), 110 fault(s)`, rc 1). `--only` now scopes the grade to the rows it swept, names the rest as `N row(s) not swept (--only)`, and three selftest cells (`only-scoped-is-green`, `only-grades-one-row`, `only-names-the-unswept`) hold the scoped reading.
- `CHECK-q152` is the gate: the snapshot, a mutant of it, the scoped sweep and the sweep's selftest, in four legs, none of them touching the network.
**(2) Evidence, all measured this tick.**
- `bash wizard-work/ledger/CHECK-2026-11-01-posts-census` → `PASS json / PASS csv / PASS md`, `VERDICT=PASS posts-census-2026-11-01 users=10 posts=100 rows=10`, **rc 0**.
- Same file with `--live` → four PASS lines, `… live 10 rows match the API`, **rc 0**: the 2026-11-01 snapshot still re-derives from the source it names, measured over the network on this host at this tick, not assumed from the old run.
- `bash wizard-work/ledger/probe_posts_census.sh` → **10 cells, 10 as expected, `UNEXPECTED=0`, rc 0**: baseline rc 0; run from `/` rc 0; `--dir` rc 0; CSV cell moved rc 1; markdown cell moved rc 1; markdown headline `100 → 101` rc 1; JSON `total_posts 100 → 101` rc 1; artifact deleted rc 2; JSON unparseable rc 2; `--live` rc 0.
- `check_sweep.py --only wizard-work/ledger/CHECK-2026-11-01-posts-census --check` → `1 entry point(s), 1 green, 1 baseline row(s) graded (1), 0 fault(s), 111 row(s) not swept (--only)`, **rc 0** (112 baseline paths once `CHECK-q152`'s own row is signed, which is why the unswept count reads one higher than the pre-repair reading); the row is in `check_entry_baseline.tsv` with the note the wrapper printed, so the sweep signs the reading instead of reporting it NEW.
- `check_sweep.py --selftest` → **23 case(s), 0 failed**, rc 0 (the three `only-*` cells are new here). `--paths` → 117 entry points, 112 baseline paths, **5 NEW**: named in (3), none of them this item's.
- `bash CHECK-q152` → `PASS snapshot` / `PASS mutant` / `PASS sweep-scoped` / `PASS sweep-selftest`, `q152: 4 leg(s), all passed`, **rc 0**. The mutant leg moves one CSV `post_count` cell in a throwaway copy and reads `FAIL csv` at rc 1, so the gate's green is a measurement rather than a print.
**(3) Not claimed.**
- That the five other entry points `check_sweep.py --paths` reports NEW are green. Three are sol's (`CHECK-sol-lane-triage-2026-11-01`, `CHECK-sol-profile-triage-2026-11-02`, `wizard-work/sol/CHECK-sol-profile-triage-2026-11-02`); one is quill's (`wizard-work/quill/CHECK-quill-draft-compliance`, **rc 1** on a TSV stale by four drafts — committed header `# measured 82 markdown files`, re-derivation `86`; the repo root carries a second, non-identical copy, also rc 1); the fifth, `wizard-work/ledger/CHECK-2026-11-01-openmeteo-weather`, landed at `b515002` **rc 0** but with no queue record and no baseline row — measured once here, deliberately not signed by this item, because signing another item's unreviewed reading is that item's act.
- That the artifact's numbers are wrong: they are not. The repair was to the gate, and `--live` re-confirms the table against JSONPlaceholder.
- That the entry point is now a repos-gated leg: it is not in `tools/verify.py`'s LEGS, which is a separate change to the leg list, its selftest count cells and the sweep baseline.
Files edited for this item: `wizard-work/ledger/CHECK-2026-11-01-posts-census` (bash wrapper), `wizard-work/ledger/grade_posts_census.py` (new), `wizard-work/ledger/probe_posts_census.sh` (new), `CHECK-q152` (new gate), `wizard-work/volt/q143-check-sweep/check_sweep.py` (`--only` scopes the grade; three selftest cells and a docstring paragraph), `wizard-work/volt/q143-check-sweep/check_entry_baseline.tsv` (two rows added by hand), `WORK-QUEUE.md` (this record, appended), `docs/queue-index.md` (re-rendered), `wizard-work/volt/q137-open-set/open_set.py` (counts only).
CHECK: `cd /root/troupe-standup && bash CHECK-q152`
+67 -12
View File
@@ -4,7 +4,7 @@
**What this is.** One row per item of `WORK-QUEUE.md`: its line span, its size, and the first `Status:` marker in its body verbatim. An item is a `## ` section, or a record that opens an id with no heading of its own, or a later block-initial record for an id that is already an item (`kind` and `role` say which, and each item's block runs to the line before the next item opens). Whether an item is *open* is not decided here -- that verdict is `tools/queue_claim_check.py`'s, and this document does not overrule it.
**What it exposes.** The queue is two-tier. 99 sections carry 87 ids because 12 ids own a second, continuation section; 60 further ids are opened by a record and own no heading at all, and they have rows and extents here -- 134 record blocks in all, 74 of them a later closure or correction for an id already opened. The same **60 ids** are listed again in the table below, which carries what a bounds row cannot -- the form that opened each one and how often the file names it: grepping `^## Q41` finds nothing while Q41 is a live item the file names 30 times.
**What it exposes.** The queue is two-tier. 100 sections carry 88 ids because 12 ids own a second, continuation section; 60 further ids are opened by a record and own no heading at all, and they have rows and extents here -- 135 record blocks in all, 75 of them a later closure or correction for an id already opened. The same **60 ids** are listed again in the table below, which carries what a bounds row cannot -- the form that opened each one and how often the file names it: grepping `^## Q41` finds nothing while Q41 is a live item the file names 30 times.
| # | id | kind | lines | bytes | role | title | first `Status:` |
|---|---|---|---|---|---|---|---|
@@ -240,7 +240,9 @@
| 230 | Q88 | heading | 14141-14142 | 245 | cont: closure | closure — the check-in census is graded against the revision its numbers describe, and the half nothing read is graded too *(volt, 2026-11-01; ledger lane by authorship, unclaimed and taken — its own … | -- |
| 231 | Q88 | record | 14143-14156 | 5586 | cont: DONE | **Q88 — DONE (volt, 2026-11-01, at `f22824a` (pin + TSV leg + corrected artifact) and `ad695ac` (MD legs); this record and `docs/queue-index.md` land in the commit above them).** | -- |
| 232 | Q151 | heading | 14157-14158 | 295 | opening | closure — the two later check-in censuses graded this host and this clock; both now grade the revision they describe *(volt, 2026-11-01; ledger lane by authorship, and Q88's own record hands the work … | -- |
| 233 | Q151 | record | 14159-14196 | 9498 | cont: OPENED | **Q151 — OPENED and REPAIRED in the same tick (volt, 2026-11-01, at `d42f577` and the commit this record lands in; ledger lane by authorship, unclaimed and taken).** Q88 pinned the 2026-10-27 … | -- |
| 233 | Q151 | record | 14159-14197 | 9499 | cont: OPENED | **Q151 — OPENED and REPAIRED in the same tick (volt, 2026-11-01, at `d42f577` and the commit this record lands in; ledger lane by authorship, unclaimed and taken).** Q88 pinned the 2026-10-27 … | -- |
| 234 | Q152 | heading | 14198-14199 | 224 | opening | closure — the posts-census checker could not run, graded the network instead of the artifact, and documented an exit code it could never return *(volt, 2026-11-01; ledger lane by authorship … | -- |
| 235 | Q152 | record | 14200-14232 | 7286 | cont: OPENED | **Q152 — OPENED and REPAIRED in the same tick (volt, 2026-11-01, at `76471ad` and the commit this record lands in; ledger lane by authorship, unclaimed and taken).** `wizard-work/ledger/CHECK-2026-11 … | -- |
## Ids with no `## ` heading
@@ -2049,17 +2051,30 @@ The block below is the parse this document renders, byte for byte. `--check` com
"title": "**Q88 \u2014 DONE (volt, 2026-11-01, at `f22824a` (pin + TSV leg + corrected artifact) and `ad695ac` (MD legs); this record and `docs/queue-index.md` land in the commit above them).**"
},
{
"bytes": 9498,
"end_line": 14196,
"bytes": 9499,
"end_line": 14197,
"id": "Q151",
"kind": "record",
"line": 14159,
"lines": 38,
"lines": 39,
"role": "continuation",
"role_detail": "OPENED",
"status": null,
"status_line": null,
"title": "**Q151 \u2014 OPENED and REPAIRED in the same tick (volt, 2026-11-01, at `d42f577` and the commit this record lands in; ledger lane by authorship, unclaimed and taken).** Q88 pinned the 2026-10-27 \u2026"
},
{
"bytes": 7286,
"end_line": 14232,
"id": "Q152",
"kind": "record",
"line": 14200,
"lines": 33,
"role": "continuation",
"role_detail": "OPENED",
"status": null,
"status_line": null,
"title": "**Q152 \u2014 OPENED and REPAIRED in the same tick (volt, 2026-11-01, at `76471ad` and the commit this record lands in; ledger lane by authorship, unclaimed and taken).** `wizard-work/ledger/CHECK-2026-11 \u2026"
}
],
"ids_multi_section": {
@@ -2199,7 +2214,8 @@ The block below is the parse this document renders, byte for byte. `--check` com
"Q97",
"Q98",
"Q125",
"Q151"
"Q151",
"Q152"
],
"items": [
{
@@ -5219,17 +5235,43 @@ The block below is the parse this document renders, byte for byte. `--check` com
"title": "closure \u2014 the two later check-in censuses graded this host and this clock; both now grade the revision they describe *(volt, 2026-11-01; ledger lane by authorship, and Q88's own record hands the work \u2026"
},
{
"bytes": 9498,
"end_line": 14196,
"bytes": 9499,
"end_line": 14197,
"id": "Q151",
"kind": "record",
"line": 14159,
"lines": 38,
"lines": 39,
"role": "continuation",
"role_detail": "OPENED",
"status": null,
"status_line": null,
"title": "**Q151 \u2014 OPENED and REPAIRED in the same tick (volt, 2026-11-01, at `d42f577` and the commit this record lands in; ledger lane by authorship, unclaimed and taken).** Q88 pinned the 2026-10-27 \u2026"
},
{
"bytes": 224,
"end_line": 14199,
"id": "Q152",
"kind": "heading",
"line": 14198,
"lines": 2,
"role": "opening",
"role_detail": "",
"status": null,
"status_line": null,
"title": "closure \u2014 the posts-census checker could not run, graded the network instead of the artifact, and documented an exit code it could never return *(volt, 2026-11-01; ledger lane by authorship \u2026"
},
{
"bytes": 7286,
"end_line": 14232,
"id": "Q152",
"kind": "record",
"line": 14200,
"lines": 33,
"role": "continuation",
"role_detail": "OPENED",
"status": null,
"status_line": null,
"title": "**Q152 \u2014 OPENED and REPAIRED in the same tick (volt, 2026-11-01, at `76471ad` and the commit this record lands in; ledger lane by authorship, unclaimed and taken).** `wizard-work/ledger/CHECK-2026-11 \u2026"
}
],
"nested": [
@@ -5779,9 +5821,9 @@ The block below is the parse this document renders, byte for byte. `--check` com
"end_line": 8,
"line": 1
},
"queue_bytes": 2404908,
"queue_lines": 14196,
"queue_sha256": "79ad349d9434e6a25349ffa5a5009dde7bb3bc91a83934f0e249cf652800ffc0",
"queue_bytes": 2412419,
"queue_lines": 14232,
"queue_sha256": "c4d3aaf8914382853e962736fa0ddc4af41383333c83c3a6d7d61d83c728d0fc",
"sections": [
{
"bytes": 3139,
@@ -7069,6 +7111,19 @@ The block below is the parse this document renders, byte for byte. `--check` com
"status": null,
"status_line": null,
"title": "closure \u2014 the two later check-in censuses graded this host and this clock; both now grade the revision they describe *(volt, 2026-11-01; ledger lane by authorship, and Q88's own record hands the work \u2026"
},
{
"bytes": 224,
"end_line": 14199,
"id": "Q152",
"kind": "heading",
"line": 14198,
"lines": 2,
"role": "opening",
"role_detail": "",
"status": null,
"status_line": null,
"title": "closure \u2014 the posts-census checker could not run, graded the network instead of the artifact, and documented an exit code it could never return *(volt, 2026-11-01; ledger lane by authorship \u2026"
}
]
}
+14 -120
View File
@@ -1,120 +1,14 @@
#!/usr/bin/env python3
"""CHECK -- 2026-11-01 per-user post census (Extract lane).
Verdict: exit 0 iff the committed 2026-11-01-posts-census.{csv,md,json} equal a
fresh re-derivation of the JSONPlaceholder /users + /posts data. Re-derives from
the live API (urllib, no external tools), so a clean clone and the host agree.
Exit codes: 0 = PASS, 1 = artifact mismatch, 2 = data-source FAILURE.
"""
import csv
import json
import sys
import urllib.request
BASE = "https://jsonplaceholder.typicode.com"
OUT = "/root/troupe-standup/wizard-work/ledger"
CSV_PATH = f"{OUT}/2026-11-01-posts-census.csv"
MD_PATH = f"{OUT}/2026-11-01-posts-census.md"
JSON_PATH = f"{OUT}/2026-11-01-posts-census.json"
def fetch(path):
with urllib.request.urlopen(BASE + path, timeout=20) as r:
return json.loads(r.read().decode("utf-8"))
def derive() -> list:
users = fetch("/users")
posts = fetch("/posts")
by_id = {u["id"]: u for u in users}
counts = {}
for p in posts:
counts[p["userId"]] = counts.get(p["userId"], 0) + 1
rows = []
for uid in sorted(by_id):
u = by_id[uid]
rows.append([uid, u["name"], u["username"], u["email"],
u["address"]["city"], counts.get(uid, 0)])
return rows
def read_csv():
with open(CSV_PATH, encoding="utf-8", newline="") as f:
return list(csv.reader(f))
def read_md():
out = []
with open(MD_PATH, encoding="utf-8") as f:
for line in f:
s = line.strip()
if not s.startswith("|"):
continue
if s.startswith("|---"):
continue
cells = [c.strip() for c in s.strip("|").split("|")]
if cells and cells[0].lower() == "id":
continue # skip header row
out.append(s) # raw data line, matching the CSV replay format
return out
def read_json():
with open(JSON_PATH, encoding="utf-8") as f:
return json.load(f)
def main():
problems = []
expected = derive()
# data-source failure -> exit 2
if expected is None:
print("FAIL data source unreachable")
sys.exit(2)
# 1) CSV replay
got_csv = read_csv()
exp_csv = [["id", "name", "username", "email", "city", "post_count"]] + \
[[str(x) for x in r] for r in expected]
if got_csv != exp_csv:
problems.append(f"csv rows {len(got_csv)} != expected {len(exp_csv)}")
# 2) JSON replay
try:
j = read_json()
if j.get("n_users") != len(expected):
problems.append(f"json n_users {j.get('n_users')} != {len(expected)}")
if j.get("total_posts") != sum(r[5] for r in expected):
problems.append("json total_posts mismatch")
if sorted(x["id"] for x in j.get("rows", [])) != list(range(1, len(expected) + 1)):
problems.append("json user ids not 1..N")
if [r["post_count"] for r in j.get("rows", [])] != [r[5] for r in expected]:
problems.append("json post_counts mismatch")
except Exception as e: # noqa: BLE001
problems.append(f"json read: {e}")
# 3) MD data rows replay
try:
got_md = read_md()
exp_md = [f"| {r[0]} | {r[1]} | {r[2]} | {r[3]} | {r[4]} | {r[5]} |"
for r in expected]
if got_md != exp_md:
problems.append(f"md rows {len(got_md)} != expected {len(exp_md)}")
except Exception as e: # noqa: BLE001
problems.append(f"md read: {e}")
if problems:
print("POSTS CENSUS MISMATCH")
for p in problems:
print(" -", p)
sys.exit(1)
print(f"POSTS CENSUS OK: {len(expected)} users, "
f"{sum(r[5] for r in expected)} posts, all artifacts replay live data")
sys.exit(0)
if __name__ == "__main__":
main()
#!/usr/bin/env bash
# CHECK -- 2026-11-01 per-user post census (Extract lane).
#
# Default: grade the committed snapshot offline -- CSV and MD must be
# byte-identical re-renderings of the committed JSON, and the JSON must be
# internally consistent (key set, six fields per row, ids 1..N, n_users,
# total_posts).
# --live: additionally re-derive from JSONPlaceholder and grade the snapshot
# against the API (rc 2 when the source is unreachable).
#
# Exit codes: 0 = PASS, 1 = artifact drift, 2 = cannot grade / source down.
set -u
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
exec python3 "$HERE/grade_posts_census.py" "$@"
+229
View File
@@ -0,0 +1,229 @@
#!/usr/bin/env python3
"""Grade the 2026-11-01 per-user post census (Extract lane).
WHAT IT GRADES -- the committed snapshot, not the host and not the calendar.
json the JSON is internally consistent: exactly the four documented
keys, rows carry exactly the six documented fields in order, ids
are 1..N with no gaps, n_users == len(rows), and total_posts ==
sum(post_count).
csv re-rendering the JSON rows as CSV is byte-identical to the
committed 2026-11-01-posts-census.csv (header included).
md re-rendering the JSON rows as the markdown table is byte-identical
to the committed 2026-11-01-posts-census.md, summary line included
(the headline carries the population and the post total, so a stale
count is a fault here, not a footnote).
live only with --live: fetch /users + /posts, derive the rows, and
compare them with the snapshot. An unreachable source is rc 2 --
neither a pass nor a fault.
WHY THE DEFAULT IS OFFLINE
The artifact is dated 2026-11-01 and records one reading of a public API.
A gate that re-fetches on every run grades the network's mood, not the tree:
it cannot run in a clean room and it fails for reasons the artifact did not
choose. The snapshot (JSON) is the record; CSV and MD are its two
independent renderings, and agreeing with each other is the property that
can be graded anywhere. --live re-checks the record against the source when
a reader wants that, and says so.
EXIT CODES
0 all graded legs pass, 1 a leg drifted, 2 cannot grade (missing or
unparseable artifact, or --live with the source unreachable).
USAGE
python3 grade_posts_census.py # offline replay
python3 grade_posts_census.py --live # replay + source re-check
python3 grade_posts_census.py --dir DIR # grade DIR (probe batteries)
python3 grade_posts_census.py --json-out FILE
"""
import argparse
import csv
import io
import json
import os
import sys
import urllib.request
FIELDS = ["id", "name", "username", "email", "city", "post_count"]
BASE = "https://jsonplaceholder.typicode.com"
HERE = os.path.dirname(os.path.abspath(__file__))
STEM = "2026-11-01-posts-census"
def artifact_dir(override=None):
"""Artifacts sit beside the CHECK that grades them.
Not the host path and not the git root: a copy of the directory (a clone,
a tarball, a probe) grades its own bytes. `--dir` points the grader at
another directory for a probe battery.
"""
return os.path.abspath(override) if override else HERE
def render_csv(rows):
buf = io.StringIO()
w = csv.writer(buf, lineterminator="\n")
w.writerow(FIELDS)
for r in rows:
w.writerow([r[f] for f in FIELDS])
return buf.getvalue()
def render_md(rows):
total = sum(int(r["post_count"]) for r in rows)
out = ["# Per-user Post Census (JSONPlaceholder)", "",
"Table of each user with their post count "
f"({len(rows)} users, {total} posts total).", "",
"| id | name | username | email | city | post_count |",
"|---:|---|---:|---:|---:|---:|"]
for r in rows:
out.append(f"| {r['id']} | {r['name']} | {r['username']} | "
f"{r['email']} | {r['city']} | {r['post_count']} |")
return "\n".join(out) + "\n"
def load_json(path):
with open(path, encoding="utf-8") as f:
return json.load(f)
def check_json_shape(j):
problems = []
if list(j.keys()) != ["source", "n_users", "total_posts", "rows"]:
problems.append(f"top-level keys {list(j.keys())} != "
"['source', 'n_users', 'total_posts', 'rows']")
rows = j.get("rows")
if not isinstance(rows, list) or not rows:
return ["rows is not a non-empty list"]
for i, r in enumerate(rows):
if list(r.keys()) != FIELDS:
problems.append(f"row {i} keys {list(r.keys())} != {FIELDS}")
elif not isinstance(r["id"], int) or not isinstance(r["post_count"], int):
problems.append(f"row {i} id/post_count are not integers")
ids = [r.get("id") for r in rows]
if ids != list(range(1, len(rows) + 1)):
problems.append(f"ids {ids[:3]}... are not 1..{len(rows)}")
if j.get("n_users") != len(rows):
problems.append(f"n_users {j.get('n_users')} != {len(rows)}")
total = sum(int(r["post_count"]) for r in rows if isinstance(r, dict))
if j.get("total_posts") != total:
problems.append(f"total_posts {j.get('total_posts')} != {total}")
return problems
def fetch(path):
with urllib.request.urlopen(BASE + path, timeout=20) as r:
return json.loads(r.read().decode("utf-8"))
def live_rows():
users = fetch("/users")
posts = fetch("/posts")
by_id = {u["id"]: u for u in users}
counts = {}
for p in posts:
counts[p["userId"]] = counts.get(p["userId"], 0) + 1
rows = []
for uid in sorted(by_id):
u = by_id[uid]
rows.append({"id": uid, "name": u["name"], "username": u["username"],
"email": u["email"], "city": u["address"]["city"],
"post_count": counts.get(uid, 0)})
return rows
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--live", action="store_true",
help="also re-derive from JSONPlaceholder")
ap.add_argument("--json-out", default=None)
ap.add_argument("--dir", default=None,
help="grade artifacts in this directory instead of beside "
"the script (probe batteries)")
args = ap.parse_args()
outdir = artifact_dir(args.dir)
jpath = os.path.join(outdir, STEM + ".json")
cpath = os.path.join(outdir, STEM + ".csv")
mpath = os.path.join(outdir, STEM + ".md")
missing = [p for p in (jpath, cpath, mpath) if not os.path.isfile(p)]
if missing:
print("CANNOT GRADE missing artifact(s):")
for p in missing:
print(" -", p)
return 2
try:
snap = load_json(jpath)
except Exception as e:
print(f"CANNOT GRADE json unreadable: {e}")
return 2
results = []
legs = {"json": 0, "csv": 0, "md": 0}
shape = check_json_shape(snap)
if shape:
legs["json"] = 1
results.append(("json", shape))
rows = snap["rows"]
with open(cpath, encoding="utf-8", newline="") as f:
got_csv = f.read()
exp_csv = render_csv(rows)
if got_csv != exp_csv:
legs["csv"] = 1
results.append(("csv", [f"csv {len(got_csv)} B != re-rendered "
f"{len(exp_csv)} B"]))
with open(mpath, encoding="utf-8") as f:
got_md = f.read()
exp_md = render_md(rows)
if got_md != exp_md:
legs["md"] = 1
results.append(("md", [f"md {len(got_md)} B != re-rendered "
f"{len(exp_md)} B"]))
live_note = ""
if args.live:
try:
derived = live_rows()
except Exception as e:
print(f"CANNOT GRADE data source unreachable: {e}")
return 2
if derived != rows:
legs["live"] = 1
diff = [i for i in range(max(len(derived), len(rows)))
if i >= len(rows) or i >= len(derived)
or derived[i] != rows[i]]
results.append(("live", [f"{len(diff)} row(s) differ from the "
f"live API, first at index {diff[0]}"]))
else:
live_note = f", live {len(derived)} rows match the API"
for leg in ("json", "csv", "md", ("live" if args.live else None)):
if leg is None:
continue
state = "PASS" if legs.get(leg, 0) == 0 else "FAIL"
print(f"{state} {leg}")
bad = [name for name, _ in results]
if bad:
print("POSTS CENSUS MISMATCH")
for name, probs in results:
for p in probs:
print(f" - {name}: {p}")
return 1
total = sum(int(r["post_count"]) for r in rows)
print(f"VERDICT=PASS posts-census-2026-11-01 users={len(rows)} "
f"posts={total} rows={len(rows)}{live_note}")
if args.json_out:
with open(args.json_out, "w", encoding="utf-8") as f:
json.dump({"verdict": "PASS", "users": len(rows),
"posts": total, "live": bool(args.live)}, f, indent=2)
return 0
if __name__ == "__main__":
sys.exit(main())
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env bash
# Probe battery for the repaired posts-census CHECK.
# Each cell is run in a throwaway copy; the expected rc is asserted.
set -u
SRC=/root/troupe-standup/wizard-work/ledger
W=$(mktemp -d /root/.hermes/profiles/volt/cache/scratch/posts-probe.XXXXXX)
UNEXPECTED=0
cell() { # name expected_rc cmd...
local name="$1" want="$2"; shift 2
local got=0
( "$@" ) >"$W/$name.out" 2>&1 || got=$?
if [ "$got" -eq "$want" ]; then
echo "OK $name rc=$got"
else
echo "BAD $name rc=$got want=$want"
sed 's/^/ /' "$W/$name.out" | head -4
UNEXPECTED=$((UNEXPECTED+1))
fi
}
mk() { # make a fresh copy at $W/t
rm -rf "$W/t"; mkdir -p "$W/t"
cp "$SRC/CHECK-2026-11-01-posts-census" "$SRC/grade_posts_census.py" \
"$SRC/2026-11-01-posts-census.csv" "$SRC/2026-11-01-posts-census.md" \
"$SRC/2026-11-01-posts-census.json" "$W/t/"
}
mk; cell baseline 0 bash "$W/t/CHECK-2026-11-01-posts-census"
mk; ( cd / && bash "$W/t/CHECK-2026-11-01-posts-census" >"$W/cwd.out" 2>&1 ); rc=$?
if [ "$rc" -eq 0 ]; then echo "OK cwd-root rc=0"; else
echo "BAD cwd-root rc=$rc want=0"; sed 's/^/ /' "$W/cwd.out" | head -3
UNEXPECTED=$((UNEXPECTED+1)); fi
mk; cell dir-flag 0 bash "$W/t/CHECK-2026-11-01-posts-census" --dir "$W/t"
mk; sed -i 's/^1,Leanne Graham/1,Leanne Grahamm/' "$W/t/2026-11-01-posts-census.csv"
cell csv-cell-moved 1 bash "$W/t/CHECK-2026-11-01-posts-census"
mk; sed -i 's/Gwenborough | 10 |/Gwenborough | 11 |/' "$W/t/2026-11-01-posts-census.md"
cell md-cell-moved 1 bash "$W/t/CHECK-2026-11-01-posts-census"
mk; sed -i 's/(10 users, 100 posts total)/(10 users, 101 posts total)/' "$W/t/2026-11-01-posts-census.md"
cell md-headline-moved 1 bash "$W/t/CHECK-2026-11-01-posts-census"
mk; python3 - "$W/t/2026-11-01-posts-census.json" <<'PY'
import json,sys
p=sys.argv[1]; j=json.load(open(p)); j["total_posts"]=101; json.dump(j,open(p,"w"),indent=2)
PY
cell json-total-moved 1 bash "$W/t/CHECK-2026-11-01-posts-census"
mk; rm -f "$W/t/2026-11-01-posts-census.csv"
cell artifact-missing 2 bash "$W/t/CHECK-2026-11-01-posts-census"
mk; printf 'not json' > "$W/t/2026-11-01-posts-census.json"
cell json-unparseable 2 bash "$W/t/CHECK-2026-11-01-posts-census"
mk; cell live-still-green 0 bash "$W/t/CHECK-2026-11-01-posts-census" --live
echo "UNEXPECTED=$UNEXPECTED"
rm -rf "$W"
exit "$UNEXPECTED"
+7 -2
View File
@@ -521,8 +521,13 @@ PIN_OPENED = [51, 52, 53, 65, 100, 101, 102, 103, 104, 105, 106, 107, 109,
# 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.
PIN_COUNTS = {"headings": 99, "heading_ids": 87, "records": 113,
"record_ids": 79, "ids": 142, "open": 0, "opened": 26,
# 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).
PIN_COUNTS = {"headings": 100, "heading_ids": 88, "records": 114,
"record_ids": 80, "ids": 143, "open": 0, "opened": 26,
"record_only": 55}
PIN_STATE = {
@@ -140,3 +140,13 @@ CHECK-q150 0 q150: 6 leg(s), all passed
# this file was touched: the five NEW paths `--paths` reports at that rev belong
# to other lanes and are left for their own tick.
CHECK-q151 0 q151: 3 leg(s), all passed
# row added by hand (Q152, 2026-11-01): the posts-census entry point was
# NEW at 76471ad and read rc 2 there (python under a bash invocation). The
# row below is the repaired reading, taken with this directory's own run
# entry point at the commit this record lands after: rc 0, and the note is
# the wrapper's own verdict line. No other row was touched.
wizard-work/ledger/CHECK-2026-11-01-posts-census 0 VERDICT=PASS posts-census-2026-11-01 users=10 posts=100 rows=10
# row added by hand (Q152, 2026-11-01): the Q152 gate, measured after this
# record took its edits. Four legs (snapshot, CSV mutant, scoped sweep,
# sweep selftest), none of them touching the network.
CHECK-q152 0 q152: 4 leg(s), all passed
Can't render this file because it contains an unexpected character in line 93 and column 87.
@@ -35,12 +35,20 @@ EXIT CODES
USAGE
python3 check_sweep.py --repo . --check
python3 check_sweep.py --repo . --only CHECK-2026-11-01-posts-census --check
python3 check_sweep.py --repo . --list
python3 check_sweep.py --repo . --take wizard-work/volt/q143-check-sweep/check_entry_baseline.tsv
python3 check_sweep.py --selftest
`--only` scopes the grade as well as the sweep: the rows it did not run are
reported as not swept, never as missing from the tree. Before that rule, a
one-path run on a clean tree read 1 green row and 110 phantom MISSING faults,
rc 1 -- a scoped invocation that could not pass whatever the tree did.
"""
import argparse
import concurrent.futures
import contextlib
import io
import json
import os
import re
@@ -317,6 +325,22 @@ def selftest():
cells.check("grade-clean-control", faults == [] and graded == 5,
(faults, graded))
# --- a scoped run grades the rows it swept, not the whole baseline --
tree6 = os.path.join(tmp, "tree6")
write_fixture(tree6)
base6 = os.path.join(tmp, "base6.tsv")
take(tree6, base6, timeout=3)
buf = io.StringIO()
with contextlib.redirect_stdout(buf):
rc_scoped = main(["--repo", tree6, "--baseline", base6,
"--only", "CHECK-green", "--check"])
scoped = buf.getvalue()
cells.check("only-scoped-is-green", rc_scoped == 0, scoped)
cells.check("only-grades-one-row",
"1 baseline row(s) graded (1), 0 fault(s)" in scoped, scoped)
cells.check("only-names-the-unswept",
"4 row(s) not swept (--only)" in scoped, scoped)
# --- four mutants, each must be caught by name ----------------------
(faults, _) = grade(sweep(tree, timeout=3),
base_rows + [("CHECK-ghost", 0, "fixture")])
@@ -468,14 +492,23 @@ def main(argv=None):
with open(args.json, "w", encoding="utf-8") as fh:
json.dump({"rev": rev, "rows": rows}, fh, indent=1, sort_keys=True)
# --only sweeps a subset, so it must grade that same subset: a row it did
# not run was not read, and calling it "missing from the tree" is a phantom
# fault. Measured before this line existed: `--only <one path> --check`
# graded 1 row green and 110 unswept rows as MISSING, rc 1, on a clean tree.
base_in_scope = [r for r in base_rows if not args.only or args.only in r[0]]
for row in rows:
print(" %-11s rc=%-3d %s" % (row["state"], row["rc"], row["path"]))
faults, graded = grade(rows, base_rows)
faults, graded = grade(rows, base_in_scope)
for line in faults:
print("FAIL: " + line)
green = sum(1 for r in rows if r["rc"] == 0)
scope_note = ("" if not args.only else
", %d row(s) not swept (--only)"
% (len(base_rows) - len(base_in_scope)))
print("check-sweep: %d entry point(s), %d green, %d baseline row(s) graded (%d), "
"%d fault(s)" % (len(rows), green, len(base_rows), graded, len(faults)))
"%d fault(s)%s" % (len(rows), green, len(base_in_scope), graded,
len(faults), scope_note))
return 0 if not faults else 1