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. 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` 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 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:` | | # | 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 … | -- | | 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).** | -- | | 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 … | -- | | 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 ## 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).**" "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, "bytes": 9499,
"end_line": 14196, "end_line": 14197,
"id": "Q151", "id": "Q151",
"kind": "record", "kind": "record",
"line": 14159, "line": 14159,
"lines": 38, "lines": 39,
"role": "continuation", "role": "continuation",
"role_detail": "OPENED", "role_detail": "OPENED",
"status": null, "status": null,
"status_line": 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" "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": { "ids_multi_section": {
@@ -2199,7 +2214,8 @@ The block below is the parse this document renders, byte for byte. `--check` com
"Q97", "Q97",
"Q98", "Q98",
"Q125", "Q125",
"Q151" "Q151",
"Q152"
], ],
"items": [ "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" "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, "bytes": 9499,
"end_line": 14196, "end_line": 14197,
"id": "Q151", "id": "Q151",
"kind": "record", "kind": "record",
"line": 14159, "line": 14159,
"lines": 38, "lines": 39,
"role": "continuation", "role": "continuation",
"role_detail": "OPENED", "role_detail": "OPENED",
"status": null, "status": null,
"status_line": 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" "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": [ "nested": [
@@ -5779,9 +5821,9 @@ The block below is the parse this document renders, byte for byte. `--check` com
"end_line": 8, "end_line": 8,
"line": 1 "line": 1
}, },
"queue_bytes": 2404908, "queue_bytes": 2412419,
"queue_lines": 14196, "queue_lines": 14232,
"queue_sha256": "79ad349d9434e6a25349ffa5a5009dde7bb3bc91a83934f0e249cf652800ffc0", "queue_sha256": "c4d3aaf8914382853e962736fa0ddc4af41383333c83c3a6d7d61d83c728d0fc",
"sections": [ "sections": [
{ {
"bytes": 3139, "bytes": 3139,
@@ -7069,6 +7111,19 @@ The block below is the parse this document renders, byte for byte. `--check` com
"status": null, "status": null,
"status_line": 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" "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 #!/usr/bin/env bash
"""CHECK -- 2026-11-01 per-user post census (Extract lane). # 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 # Default: grade the committed snapshot offline -- CSV and MD must be
fresh re-derivation of the JSONPlaceholder /users + /posts data. Re-derives from # byte-identical re-renderings of the committed JSON, and the JSON must be
the live API (urllib, no external tools), so a clean clone and the host agree. # internally consistent (key set, six fields per row, ids 1..N, n_users,
# total_posts).
Exit codes: 0 = PASS, 1 = artifact mismatch, 2 = data-source FAILURE. # --live: additionally re-derive from JSONPlaceholder and grade the snapshot
""" # against the API (rc 2 when the source is unreachable).
import csv #
import json # Exit codes: 0 = PASS, 1 = artifact drift, 2 = cannot grade / source down.
import sys set -u
import urllib.request HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
exec python3 "$HERE/grade_posts_census.py" "$@"
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()
+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 # 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 # 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. # (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, # Q152 (2026-11-01): the same move again -- one heading (## Q152 closure) and
"record_ids": 79, "ids": 142, "open": 0, "opened": 26, # 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} "record_only": 55}
PIN_STATE = { 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 # this file was touched: the five NEW paths `--paths` reports at that rev belong
# to other lanes and are left for their own tick. # to other lanes and are left for their own tick.
CHECK-q151 0 q151: 3 leg(s), all passed 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 USAGE
python3 check_sweep.py --repo . --check 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 . --list
python3 check_sweep.py --repo . --take wizard-work/volt/q143-check-sweep/check_entry_baseline.tsv python3 check_sweep.py --repo . --take wizard-work/volt/q143-check-sweep/check_entry_baseline.tsv
python3 check_sweep.py --selftest 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 argparse
import concurrent.futures import concurrent.futures
import contextlib
import io
import json import json
import os import os
import re import re
@@ -317,6 +325,22 @@ def selftest():
cells.check("grade-clean-control", faults == [] and graded == 5, cells.check("grade-clean-control", faults == [] and graded == 5,
(faults, graded)) (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 ---------------------- # --- four mutants, each must be caught by name ----------------------
(faults, _) = grade(sweep(tree, timeout=3), (faults, _) = grade(sweep(tree, timeout=3),
base_rows + [("CHECK-ghost", 0, "fixture")]) base_rows + [("CHECK-ghost", 0, "fixture")])
@@ -468,14 +492,23 @@ def main(argv=None):
with open(args.json, "w", encoding="utf-8") as fh: with open(args.json, "w", encoding="utf-8") as fh:
json.dump({"rev": rev, "rows": rows}, fh, indent=1, sort_keys=True) 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: for row in rows:
print(" %-11s rc=%-3d %s" % (row["state"], row["rc"], row["path"])) 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: for line in faults:
print("FAIL: " + line) print("FAIL: " + line)
green = sum(1 for r in rows if r["rc"] == 0) 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), " 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 return 0 if not faults else 1