ledger: wizards.csv replays from a pinned source, 18 rows, correction carried (Q113)

This commit is contained in:
volt committed 2026-10-29 23:18:37 +00:00
1 parent d50b413363
commit b6f7b2e31d
9 files changed
+958 -62

No files matched your search

+20
View File
@@ -13521,3 +13521,23 @@ Rows 3 and 4 are the defect and the repair on one input; row 2 is the control th
**Not claimed:** that any shipped tool is currently broken this way — all 23 are green on the clean head, and this is a hole in the instrument, not a live defect; that the prose pins should come back — they were wrong twice in one week and the contract grading fixed both; that CLI drift is now caught anywhere else in the repo — nothing in the gate invokes a tool with the flags its own documentation pins, and the `pin` axis still grades counts, not invocations; that `report_read`'s read/malformed split is a new schema — it is unchanged, and `NO_PROBE` rows still land there by probe name; that the pre-repair module is otherwise sound — only its refusal grading was graded here; that the `f400640` table was re-measured — it was read, not re-run, while `9878f12`'s two rows were re-run in a clone (§5) and its "whole run clean" clause is corrected there; that the tools-axis `RUN_FAILED` in §5 row 3 is Q97's defect — it is a second, incidental red from the tool's own selftest, where the input axes stay green, and that is the hole this item is about. Files edited for this item: `tools/selftest_sweep.py`, `tools/selftest_baseline.tsv`, `wizard-work/volt/q97_check.py` (new), `wizard-work/volt/CHECK-q97` (new), `WORK-QUEUE.md` (this record, appended), `docs/queue-index.md` (re-rendered with the committed `tools/queue_index.py --write`). Nothing from `inbox/` is quoted and no other lane's artifact was edited. Report: `/root/.hermes/wizard-outputs/volt/2026-10-29-q97.md`.
CHECK: cd /root/troupe-standup && bash wizard-work/volt/CHECK-q97
**Q113 — DONE (volt, 2026-10-29, at the commit above this record; ledger lane by authorship, unclaimed and taken). The roster gate could not fail, graded its own hardcoded copy of the CSV, never opened the source, and re-issued a withdrawn escalation — and the artifact it guarded had gone stale by eight rows. It now re-derives all 18 roster rows from the pinned table cell by cell, reds on a single corrupted Lane cell, and carries the table's correction into the artifact.**
**(0) What HEAD held, measured in a clone of `d50b413`.** `wizard-work/ledger/verify_wizards.py` was 37 lines, md5 `be1b015d1f69b5e98558c80d7b1bb8b0`, with `PATH = '/root/troupe-standup/wizard-work/ledger/wizards.csv'` at `:4` and four assertions: the header literal, `len(data) == 10`, two wizard names present, one model string present. It never opened `WIZARDS-TABLE.md`; `grep -c 'WIZARDS-TABLE' ` over it is **0**, so its whole verdict was about bytes it had already been handed. `wizards.csv` was 10 data rows, md5 `b3d2425c1608fbfeaa58164289063bff`.
**(1) The stale population, which the item did not name.** The table has held **18** data rows since 2026-10-28, not 10: lines 26–33 added the eight lane signer rows (`forge ledger sol quill spark sphinx null zeph`) under Q124's ruling that "lanes sign as themselves, and the rows above put them in the roster". The committed CSV carried the first ten and dropped the other eight, and its notebook still read "10 data rows as of the file's current state". A roster transcription that omits 8 of the 18 rows the table carries is not a transcription of the table, so the repair takes all 18 and labels them in a `Kind` column by a printed rule — `lane signer` iff the Model cell says the row has no model of its own — rather than by position.
**(2) The defect and the repair on one mutation.** Harness `/root/.hermes/profiles/volt/cache/scratch/q113/pre_repair_probe.py`, four readings. **A** — HEAD's verifier (one literal edited: its pinned `PATH`, rewritten to a fixture, disclosed because that pin is defect 3) over its own untouched 10-row CSV: `OK: wizards.csv -> header + 10 data rows (10 wizards)`, rc **0**. **B** — same file, same fixture, every `Lane` cell replaced by `GARBAGE LANE`: `OK: wizards.csv -> header + 10 data rows (10 wizards)`, rc **0** — the filed green, reproduced on the exact mutation the item names. **C** — the repaired gate over an untouched 18-row extract: `VERDICT TRUE: wizards.csv replays from WIZARDS-TABLE.md at its pinned bytes`, rc **0**. **D** — the same gate over the same fixture with every `Lane` cell `GARBAGE LANE`: `VERDICT FALSE: 19 fault(s)`, rc **1**, first content line `FAIL content: row 1 (Timmy) column 'Lane': 'GARBAGE LANE' != source 'Operating partner — replies, queue, escalation'`. So B and D are one input and two instruments.
**(3) The repair, five files.** `wizard-work/ledger/extract_wizards.py` (new, 245 lines, md5 `2d4033b25066c383c6fb4a3847ce5a6e`) parses the table and writes the CSV plus the pin manifest; every path is derived from `os.path.realpath(__file__)`, so it runs in a clone, a worktree or `/tmp`. `wizard-work/ledger/wizards.manifest.json` (new, 34 lines, md5 `71bba8218df518b95cd432c48248cf69`) pins `source` = `WIZARDS-TABLE.md` by `source_sha256` `fd093a2898f9…` and **11896** bytes, `source_blob` `1c82d0d39206426e5d5b419e84f64f5ab007f7ae`, `source_commit` `52d6588abd40…`, `source_stated_date` `2026-10-13 15:13Z`, `extracted_utc` `2026-10-29T23:12Z`, the 7-column list, `row_count` 18 (10 wizard / 8 lane signer), `csv_sha256`, and the `corrections` table. `wizard-work/ledger/verify_wizards.py` (rewritten, 344 lines, md5 `bfd9bc90fd963d85a0f90f2e39f83fdd`) grades four things: the pin (sha256 and size against the manifest, plus the git blob id when the tree can answer for it, `INFO` when it cannot); the shape (header equals the manifest's column list, row count, CSV sha256, per-row column count); the content (every cell re-derived from the pinned source by this file's own parser, compared one cell at a time, naming row and column, with a name-keyed pre-pass so a deleted row reads as a deleted row); and the correction. `wizard-work/ledger/CHECK-wizards` (new, md5 `375bb89bf3765a636cf6fa06ae64c6d6`) is the shell entry point — `wizard-work/ledger/CHECK` is now the jsonplaceholder users-census gate from `ab7767d`, a different artifact, so this gate takes a name that says which artifact it grades rather than evicting a sibling. `wizard-work/ledger/test_verify_wizards.py` (new, 207 lines, md5 `3961e0efde149043c59c8b759973d03d`) carries **13 cells**, each building a throwaway fixture and running the real verifier with `--root`, so no cell mutates the repository.
**(4) The correction, carried as data.** `WIZARDS-TABLE.md:90-99` declares the Zephyrus Sparkborn row "false as written" and **withdraws** its escalate-line ("this needs Alexander's one line — re-task the lane or let it lapse — not silence"), because the lane was egress-blocked rather than silent. HEAD's CSV copied that sentence verbatim and dropped the correction. The repaired CSV's `Correction` cell carries the marker recorded in the manifest, and four legs grade it: the marker must be present on the named row; the withdrawn text must still be in that row's source cell (a marker cannot outlive its subject); the authority span `90-99` must still contain "the Zephyrus row above is false as written"; and a marker on a row with nothing withdrawn is a fault, so the column cannot be sprayed green. The withdrawn phrase and its authority span are **data in the manifest**, not a site heuristic — the rule Q117 set for `KNOWN_PROBE`.
**(5) Readings.** Gate: `bash wizard-work/ledger/CHECK-wizards` → `PASS pin: WIZARDS-TABLE.md sha256=fd093a2898f9 bytes=11896`, `PASS pin: git blob 1c82d0d39206 matches the manifest`, `PASS shape: header 7 columns`, `PASS shape: 18 data row(s)`, `PASS content: 18 rows x 7 column(s) = 126 cell(s) re-derived`, `PASS correction: row 'Zephyrus Sparkborn' carries its marker`, `verify_wizards: 18 row(s), 7 column(s), 126 cell(s) compared, 0 fault(s)`, `VERDICT TRUE`, rc **0** — twice, and from `cwd=/` (cell 13). Cells: `python3 wizard-work/ledger/test_verify_wizards.py` → `Ran 13 tests … OK`, rc **0**. The falsifications are cells, not claims: a renamed Wizard (`column 'Wizard'`), every Lane cell `GARBAGE LANE` (`column 'Lane'`), a corrupted `Current unit`, a dropped correction marker, a marker on Timmy's row, an un-repinned source edit (`source moved without a re-extract`), a deleted row, a 6-cell row, a tampered `row_count`, a missing manifest (**rc 2**), a missing CSV (**rc 2**). Two legs are also measured on copies of the real artifact, not only on fixtures (both under `/root/.hermes/profiles/volt/cache/scratch/q113/`): the **pin** by editing one byte of `WIZARDS-TABLE.md` in `drift2/` → rc **1**, `FAIL pin: WIZARDS-TABLE.md sha256=ef3f3eda92ff != pinned fd093a2898f9 -- source moved without a re-extract; run: python3 wizard-work/ledger/extract_wizards.py`, `FAIL pin: WIZARDS-TABLE.md blob=8a1be8e8fe2b != pinned 1c82d0d39206`, `FAIL content: row 4 (Merlin) column 'Model'`, 3 faults; the **correction** by dropping the marker cell from `drift1/` → rc **1**, `FAIL correction: row 'Zephyrus Sparkborn' Correction cell does not carry the withdrawn marker`, `FAIL correction: row 'Zephyrus Sparkborn' holds a withdrawn phrase and no marker`, plus the CSV-sha fault for the edit, 4 faults. Not claimed: that a one-byte edit is a realistic roster refresh — it is the smallest mutation that reaches the pin.
**(6) Repo gate, at the tree about to be committed.** `python3 tools/verify.py --repo . --fast` before the two new files were staged → `verify: 8 legs, 6 pass, 1 fault, 0 ungradable, 1 skipped`, the one fault `path-claims` being this tick's own two new citations (`extract_wizards.py`, `test_verify_wizards.py` named in `wizards-notebook.md:34,36` as `[NEW -- not in the baseline]`) while untracked. After `git add`: `path-claims` reads `path_claim_check: 4266 distinct paths, 35 missing, 0 new against the baseline`, rc **0**, and the fast gate reads **`verify: 8 legs, 7 pass, 0 fault, 0 ungradable, 1 skipped`**, `gate: OK`. The full gate, sweep included, reads **`verify: 8 legs, 8 pass, 0 fault, 0 ungradable, 0 skipped`**, `gate: OK -- 8 of 8 graded leg(s) passed`, rc **0**, with `selftest-sweep PASS` (`tools 0 fatal, read-refusal 0 fault, malformed-input 0 fault, pin 0 drift`) and `index-current PASS` (`194 items (97 sections, 97 record blocks)`, re-rendered above). The record's own CHECK line grades `SOUND` under `python3 tools/check_lint.py --check`.
**Not claimed:** that the 10-row population was wrong at the opening rev — it was 10 rows then, and the opening record's "50 cells" is right for that state; that the table's rows are correct or current — only that they are what the table says, and the table's own date line is `2026-10-13 15:13Z`, fifteen days before extraction, which the notebook now states rather than implies; that the verifier is an independent oracle — it re-implements the extractor's stated rule, so their agreement is a transcription check; that `wizard-work/ledger/CHECK` should be restored to a wizards gate — it is another artifact's live gate at HEAD and evicting it would be the same collision this directory keeps producing; that the sibling extraction `2026-10-29-wizard-roster.*` (from `8df8b30`) is sound — it pins `REPO_ROOT = "/root/troupe-standup"` in both its extractor and its verifier and carries 10 of the table's 18 rows, which is Q106's class in a third artifact; it was read, not edited, and it is not this item; that `email_validator`-style local modules affect this artifact — it names no imports; that any consumer reads `wizards.csv` — nothing imports it: `git grep -ln 'wizards\.csv'` returns **11** paths (4 `.md`, 3 `.tsv`, 2 `.csv`, 1 `.json`, 1 `.py`), the `.py` being this directory's own verifier and the rest prose or census rows that name the file, so the CSV's readers are readers of a file, not importers of a module. Files edited for this item: `wizard-work/ledger/verify_wizards.py`, `wizard-work/ledger/wizards.csv`, `wizard-work/ledger/wizards-notebook.md`, `wizard-work/ledger/extract_wizards.py` (new), `wizard-work/ledger/wizards.manifest.json` (new), `wizard-work/ledger/CHECK-wizards` (new), `wizard-work/ledger/test_verify_wizards.py` (new), `WORK-QUEUE.md` (this record, appended), `docs/queue-index.md` (re-rendered with the committed `tools/queue_index.py --write` in this tree). Nothing from `inbox/` is quoted and no other lane's artifact was edited. Report and probe: `/root/.hermes/wizard-outputs/volt/2026-10-29-q113.md`, `/root/.hermes/profiles/volt/cache/scratch/q113/pre_repair_probe.py`.
CHECK: bash wizard-work/ledger/CHECK-wizards
+46 -19
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. 97 sections carry 86 ids because 11 ids own a second, continuation section; 36 further ids are opened by a record and own no heading at all, and they have rows and extents here -- 96 record blocks in all, 60 of them a later closure or correction for an id already opened. The same **36 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. 97 sections carry 86 ids because 11 ids own a second, continuation section; 36 further ids are opened by a record and own no heading at all, and they have rows and extents here -- 97 record blocks in all, 61 of them a later closure or correction for an id already opened. The same **36 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:` |
|---|---|---|---|---|---|---|---|
@@ -200,7 +200,8 @@
| 190 | Q102 | record | 13448-13461 | 4987 | cont: DONE | **Q102 — DONE (volt, 2026-10-29, at `062e278`; beam lane by authorship, unclaimed and taken). `majority()` now has three outcomes on three channels, and a non-reflexive element that fills the list is … | -- |
| 191 | Q119 | record | 13462-13479 | 7662 | cont: DONE | **Q119 — DONE (volt, 2026-10-29, at the commit above this record; sol lane by authorship, unclaimed and taken). The classifier no longer files an unmatched demand under a real category, its five … | -- |
| 192 | Q112 | record | 13480-13495 | 7900 | cont: DONE | **Q112 — DONE (volt, 2026-10-29, at the commit above this record; ledger lane by authorship, unclaimed and taken). The census was right and its verifier was wrong: the committed `CHECK` could not … | -- |
| 193 | Q97 | record | 13496-13523 | 8547 | cont: DONE | **Q97 — DONE (volt, 2026-10-29, at the commit above this record; forge lane by authorship, unclaimed and taken). A refusal at `rc 2` that is really `argparse` failing to parse the invocation is now … | -- |
| 193 | Q97 | record | 13496-13524 | 8548 | cont: DONE | **Q97 — DONE (volt, 2026-10-29, at the commit above this record; forge lane by authorship, unclaimed and taken). A refusal at `rc 2` that is really `argparse` failing to parse the invocation is now … | -- |
| 194 | Q113 | record | 13525-13543 | 10862 | cont: DONE | **Q113 — DONE (volt, 2026-10-29, at the commit above this record; ledger lane by authorship, unclaimed and taken). The roster gate could not fail, graded its own hardcoded copy of the CSV, never … | -- |
## Ids with no `## ` heading
@@ -225,25 +226,25 @@ Opened as records inside another section. `line` is the record's own opening lin
| Q103 | 13010 | 13010 | 18 | Q102 | BULLET+BOLD | BOLD-LEAD |
| Q104 | 13103 | 13103 | 18 | Q101 | BULLET+BOLD | BOLD-LEAD |
| Q105 | 13135 | 13135 | 17 | Q104 | BULLET+BOLD | BOLD-LEAD |
| Q106 | 13171 | 13171 | 13 | Q105 | BULLET+BOLD | BOLD-LEAD |
| Q106 | 13171 | 13171 | 14 | Q105 | BULLET+BOLD | BOLD-LEAD |
| Q107 | 13189 | 13189 | 18 | Q106 | BULLET+BOLD | BOLD-LEAD |
| Q108 | 13267 | 13263 | 3 | Q106 | BULLET+BOLD | BOLD-LEAD |
| Q109 | 13270 | 13270 | 11 | Q104 | BULLET+BOLD | BOLD-LEAD |
| Q110 | 13272 | 13272 | 3 | Q109 | BULLET+BOLD | BOLD-LEAD |
| Q111 | 13274 | 13274 | 7 | Q110 | BULLET+BOLD | BOLD-LEAD |
| Q112 | 13276 | 13276 | 6 | Q111 | BULLET+BOLD | BOLD-LEAD |
| Q113 | 13278 | 13278 | 2 | Q112 | BULLET+BOLD | BOLD-LEAD |
| Q113 | 13278 | 13278 | 3 | Q112 | BULLET+BOLD | BOLD-LEAD |
| Q114 | 13280 | 13280 | 5 | Q113 | BULLET+BOLD | BOLD-LEAD |
| Q115 | 13282 | 13282 | 1 | Q114 | BULLET+BOLD | BOLD-LEAD |
| Q116 | 13286 | 13286 | 4 | Q105 | BULLET+BOLD | BOLD-LEAD |
| Q117 | 13290 | 13288 | 5 | Q96 | BULLET+BOLD | BOLD-LEAD |
| Q117 | 13290 | 13288 | 6 | Q96 | BULLET+BOLD | BOLD-LEAD |
| Q118 | 13300 | 13300 | 2 | Q111 | BULLET+BOLD | BOLD-LEAD |
| Q119 | 13305 | 13305 | 5 | Q118 | BULLET+BOLD | BOLD-LEAD |
| Q120 | 13308 | 13308 | 9 | Q119 | BULLET+BOLD | BOLD-LEAD |
| Q121 | 13342 | 13342 | 4 | Q107 | BULLET+BOLD | BOLD-LEAD |
| Q122 | 13344 | 13344 | 6 | Q121 | BULLET+BOLD | BOLD-LEAD |
| Q123 | 13346 | 13346 | 4 | Q122 | BULLET+BOLD | BOLD-LEAD |
| Q124 | 13350 | 13350 | 2 | Q95 | BULLET+BOLD | BOLD-LEAD |
| Q124 | 13350 | 13350 | 3 | Q95 | BULLET+BOLD | BOLD-LEAD |
**Not in this document.** Ids the prose corpus names that the queue has never mentioned (`checkins/`, `replies/`, `recoveries/`, `audits/`, `docs/`, the top-level documents; `tools/` excluded). That set moves with the prose, not with the queue, so embedding it here would make `--check` go RED for a reason that has nothing to do with the queue being current. It is reported on demand: `python3 tools/queue_index.py --outside`.
@@ -1491,17 +1492,30 @@ The block below is the parse this document renders, byte for byte. `--check` com
"title": "**Q112 \u2014 DONE (volt, 2026-10-29, at the commit above this record; ledger lane by authorship, unclaimed and taken). The census was right and its verifier was wrong: the committed `CHECK` could not \u2026"
},
{
"bytes": 8547,
"end_line": 13523,
"bytes": 8548,
"end_line": 13524,
"id": "Q97",
"kind": "record",
"line": 13496,
"lines": 28,
"lines": 29,
"role": "continuation",
"role_detail": "DONE",
"status": null,
"status_line": null,
"title": "**Q97 \u2014 DONE (volt, 2026-10-29, at the commit above this record; forge lane by authorship, unclaimed and taken). A refusal at `rc 2` that is really `argparse` failing to parse the invocation is now \u2026"
},
{
"bytes": 10862,
"end_line": 13543,
"id": "Q113",
"kind": "record",
"line": 13525,
"lines": 19,
"role": "continuation",
"role_detail": "DONE",
"status": null,
"status_line": null,
"title": "**Q113 \u2014 DONE (volt, 2026-10-29, at the commit above this record; ledger lane by authorship, unclaimed and taken). The roster gate could not fail, graded its own hardcoded copy of the CSV, never \u2026"
}
],
"ids_multi_section": {
@@ -4136,17 +4150,30 @@ The block below is the parse this document renders, byte for byte. `--check` com
"title": "**Q112 \u2014 DONE (volt, 2026-10-29, at the commit above this record; ledger lane by authorship, unclaimed and taken). The census was right and its verifier was wrong: the committed `CHECK` could not \u2026"
},
{
"bytes": 8547,
"end_line": 13523,
"bytes": 8548,
"end_line": 13524,
"id": "Q97",
"kind": "record",
"line": 13496,
"lines": 28,
"lines": 29,
"role": "continuation",
"role_detail": "DONE",
"status": null,
"status_line": null,
"title": "**Q97 \u2014 DONE (volt, 2026-10-29, at the commit above this record; forge lane by authorship, unclaimed and taken). A refusal at `rc 2` that is really `argparse` failing to parse the invocation is now \u2026"
},
{
"bytes": 10862,
"end_line": 13543,
"id": "Q113",
"kind": "record",
"line": 13525,
"lines": 19,
"role": "continuation",
"role_detail": "DONE",
"status": null,
"status_line": null,
"title": "**Q113 \u2014 DONE (volt, 2026-10-29, at the commit above this record; ledger lane by authorship, unclaimed and taken). The roster gate could not fail, graded its own hardcoded copy of the CSV, never \u2026"
}
],
"nested": [
@@ -4308,7 +4335,7 @@ The block below is the parse this document renders, byte for byte. `--check` com
"form": "BOLD-LEAD",
"id": "Q106",
"line": 13171,
"refs": 13,
"refs": 14,
"section": "Q105",
"shape": "BULLET+BOLD"
},
@@ -4371,7 +4398,7 @@ The block below is the parse this document renders, byte for byte. `--check` com
"form": "BOLD-LEAD",
"id": "Q113",
"line": 13278,
"refs": 2,
"refs": 3,
"section": "Q112",
"shape": "BULLET+BOLD"
},
@@ -4407,7 +4434,7 @@ The block below is the parse this document renders, byte for byte. `--check` com
"form": "BOLD-LEAD",
"id": "Q117",
"line": 13290,
"refs": 5,
"refs": 6,
"section": "Q96",
"shape": "BULLET+BOLD"
},
@@ -4470,7 +4497,7 @@ The block below is the parse this document renders, byte for byte. `--check` com
"form": "BOLD-LEAD",
"id": "Q124",
"line": 13350,
"refs": 2,
"refs": 3,
"section": "Q95",
"shape": "BULLET+BOLD"
}
@@ -4480,9 +4507,9 @@ The block below is the parse this document renders, byte for byte. `--check` com
"end_line": 8,
"line": 1
},
"queue_bytes": 2130150,
"queue_lines": 13523,
"queue_sha256": "7ecbb1f1c41450bc2a01b1d3176564fbc6f4e0bb925148dc7533c1c5e84201aa",
"queue_bytes": 2141013,
"queue_lines": 13543,
"queue_sha256": "cd1ab423caf91199786c46b2b716238d7da771bc824723be2b7dbec79d8be6af",
"sections": [
{
"bytes": 3139,
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
# CHECK-wizards -- re-derive the WIZARDS-TABLE roster extract from its source.
#
# `wizard-work/ledger/CHECK` is another extract's gate (jsonplaceholder users
# census, 2026-10-29), so this artifact's gate lives beside it under a name
# that says which artifact it grades.
#
# rc 0 = PASS, 1 = a fault, 2 = could not grade (missing/unparseable inputs).
set -u
HERE="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)" || exit 2
command -v python3 >/dev/null 2>&1 || {
echo "CANNOT GRADE: python3 not on PATH"
exit 2
}
python3 "$HERE/verify_wizards.py" "$@"
exit $?
+245
View File
@@ -0,0 +1,245 @@
#!/usr/bin/env python3
"""Extract the WIZARDS-TABLE.md roster into wizards.csv plus its pin manifest.
WHAT THIS IS
`wizards.csv` is a machine-readable transcription of the roster table in
`WIZARDS-TABLE.md`, and `wizards.manifest.json` is the pin that makes the
transcription falsifiable: the exact source bytes (sha256 + git blob), the
commit the blob was read at, the extraction clock, the column list, and the
correction markers carried into the CSV.
WHY THE 18 ROWS, NOT 10
The table has held ten wizard rows since 2026-10-13 and gained eight lane
signer rows on 2026-10-28 (Q124: "lanes sign as themselves, and the rows
above put them in the roster"). The earlier extraction stopped at the ten,
so the artifact dropped eight rows the table now carries. This extractor
takes every roster row and labels which is which in the `Kind` column.
The rule is stated, not inferred from position: a row is a `lane signer`
when its Model cell carries no model of its own -- the table writes those
cells as `-- (lane identity, no model of its own)`; every other row is a
`wizard`. `verify_wizards.py` re-implements this rule independently.
WHY THE `Correction` COLUMN
The table appends a control-plane correction at :90-99 declaring the
Zephyrus row "false as written" and withdrawing its escalate-line
("this needs Alexander's one line -- re-task the lane or let it lapse --
not silence"). A transcription that copies the cell and drops the
correction re-issues a withdrawn escalation. So every row gets a
`Correction` cell: empty when nothing is withdrawn, and exactly the
marker named in the manifest's `corrections` table when something is.
The withdrawn text and the authority span are data in the manifest, so
the rule is a lookup, not a site heuristic that could one day hide a
genuine escalation.
Pinned source
`source` is repo-relative; every path here is derived from this file's
own location, so the extractor works in a clone, a worktree or /tmp.
Usage:
python3 extract_wizards.py # rewrite wizards.csv + manifest
python3 extract_wizards.py --check # report what would change, write nothing
Exit codes: 0 written (or already current), 1 table unparseable, 2 cannot grade.
"""
import argparse
import csv
import hashlib
import io
import json
import os
import re
import subprocess
import sys
from datetime import datetime, timezone
HERE = os.path.dirname(os.path.realpath(__file__))
ROOT = os.path.dirname(os.path.dirname(HERE)) # wizard-work/ledger -> repo root
SOURCE_REL = "WIZARDS-TABLE.md"
CSV_NAME = "wizards.csv"
MANIFEST_NAME = "wizards.manifest.json"
COLUMNS = ["Kind", "Wizard", "Model", "Lane", "Latest check-in",
"Current unit", "Correction"]
TABLE_HEADER = ["Wizard", "Model", "Lane", "Latest check-in", "Current unit"]
# A row whose Model cell has no model of its own is a lane signer (Q124).
LANE_SIGNER_MARK = "no model of its own"
# Data, not heuristics: the corrections the table appends, by row.
CORRECTIONS = [
{
"row": "Zephyrus Sparkborn",
"column": "Current unit",
"marker": ("WITHDRAWN - escalate-line withdrawn by "
"WIZARDS-TABLE.md:90-99; the lane was egress-blocked, "
"not silent"),
"withdrawn_text": ("this needs Alexander's one line — re-task the "
"lane or let it lapse — not silence"),
"authority_line_start": 90,
"authority_line_end": 99,
"authority_phrase": "the Zephyrus row above is false as written",
},
]
def sha256_bytes(data):
return hashlib.sha256(data).hexdigest()
def _cells(line):
"""Split one markdown table line into stripped cells, dropping the edges."""
parts = [c.strip() for c in line.strip().split("|")]
if parts and parts[0] == "":
parts = parts[1:]
if parts and parts[-1] == "":
parts = parts[:-1]
return parts
def parse_roster(text):
"""Return (rows, stated_date) from the roster table in `text`.
rows is a list of [lead, model, lane, latest, unit]; stated_date is the
table's own `*Roster as of ...` line when the file carries one.
"""
lines = text.splitlines()
start = None
for i, line in enumerate(lines):
if _cells(line) == TABLE_HEADER:
start = i + 1
break
if start is None:
raise SystemExit("CANNOT GRADE: roster header not found in %s" % SOURCE_REL)
sep = _cells(lines[start]) if start < len(lines) else []
if not sep or not all(set(c) <= set("-: ") for c in sep):
raise SystemExit("CANNOT GRADE: no header separator after the roster header")
rows = []
for line in lines[start + 1:]:
s = line.strip()
if not s or s.startswith("#"):
break
if not s.startswith("|"):
break
cells = _cells(s)
if len(cells) != 5:
raise SystemExit("CANNOT GRADE: roster row is not 5 cells: %r" % s[:80])
rows.append(cells)
stated = None
for line in lines:
if "roster as of" in line.lower():
m = re.search(r"\d{4}-\d{2}-\d{2}(?:[ T]\d{2}:\d{2}Z)?", line)
if m:
stated = m.group(0)
break
return rows, stated
def kind_of(model_cell):
return "lane signer" if LANE_SIGNER_MARK in model_cell else "wizard"
def build(source_bytes, stated):
rows, _ = parse_roster(source_bytes.decode("utf-8"))
corrections = {c["row"]: c for c in CORRECTIONS}
out = []
for lead, model, lane, latest, unit in rows:
corr = corrections.get(lead)
out.append([kind_of(model), lead, model, lane, latest, unit,
corr["marker"] if corr else ""])
return out
def git(args):
try:
proc = subprocess.run(["git", "-C", ROOT] + args, capture_output=True,
text=True, timeout=20)
except (OSError, subprocess.SubprocessError):
return None
return proc.stdout.strip() if proc.returncode == 0 else None
def csv_bytes(rows):
buf = io.StringIO()
writer = csv.writer(buf)
writer.writerow(COLUMNS)
writer.writerows(rows)
return buf.getvalue().encode("utf-8")
def main(argv=None):
ap = argparse.ArgumentParser(
description="Extract the WIZARDS-TABLE.md roster into wizards.csv "
"plus its pin manifest.")
ap.add_argument("--check", action="store_true",
help="report drift, write nothing")
args = ap.parse_args(argv)
source_path = os.path.join(ROOT, SOURCE_REL)
try:
with open(source_path, "rb") as fh:
source_bytes = fh.read()
except OSError as exc:
print("CANNOT GRADE: %s unreadable: %s" % (source_path, exc))
return 2
rows, stated = parse_roster(source_bytes.decode("utf-8"))
built = build(source_bytes, stated)
payload = csv_bytes(built)
blob = git(["hash-object", SOURCE_REL]) or "unknown"
commit = git(["log", "-1", "--format=%H", "--", SOURCE_REL]) or "unknown"
now = datetime.now(timezone.utc).replace(microsecond=0).isoformat()
manifest = {
"artifact": CSV_NAME,
"source": SOURCE_REL,
"source_blob": blob,
"source_sha256": sha256_bytes(source_bytes),
"source_bytes": len(source_bytes),
"source_commit": commit,
"source_stated_date": stated,
"extracted_utc": now,
"columns": COLUMNS,
"row_count": len(built),
"wizard_rows": sum(1 for r in built if r[0] == "wizard"),
"lane_signer_rows": sum(1 for r in built if r[0] == "lane signer"),
"csv_sha256": sha256_bytes(payload),
"corrections": CORRECTIONS,
}
csv_path = os.path.join(HERE, CSV_NAME)
man_path = os.path.join(HERE, MANIFEST_NAME)
current_csv = None
if os.path.exists(csv_path):
with open(csv_path, "rb") as fh:
current_csv = fh.read()
if args.check:
drift = "csv differs" if current_csv != payload else "csv current"
print("rows=%d wizards=%d lane_signers=%d source_blob=%s %s"
% (manifest["row_count"], manifest["wizard_rows"],
manifest["lane_signer_rows"], blob[:12], drift))
return 0 if current_csv == payload else 1
with open(csv_path, "wb") as fh:
fh.write(payload)
with open(man_path, "w", encoding="utf-8") as fh:
json.dump(manifest, fh, indent=2, sort_keys=True)
fh.write("\n")
print("wrote %s: %d rows (%d wizard, %d lane signer) from %s blob %s"
% (CSV_NAME, manifest["row_count"], manifest["wizard_rows"],
manifest["lane_signer_rows"], SOURCE_REL, blob[:12]))
print("wrote %s: source_sha256=%s csv_sha256=%s stated=%s extracted=%s"
% (MANIFEST_NAME, manifest["source_sha256"][:12],
manifest["csv_sha256"][:12], stated, now))
return 0
if __name__ == "__main__":
sys.exit(main())
+207
View File
@@ -0,0 +1,207 @@
#!/usr/bin/env python3
"""Cells for `wizard-work/ledger/verify_wizards.py` (queue Q113).
Every cell builds its own fixture tree under a temporary directory -- a copy of
WIZARDS-TABLE.md plus `wizard-work/ledger/{wizards.csv,wizards.manifest.json}`
-- mutates exactly one thing, and runs the real verifier against it with
`--root`. Nothing in the repository is touched, so a red cell cannot leave the
shared tree dirty.
The cell the queue filed is `test_corrupted_lane_cell_is_a_fault`: the old
`verify_wizards.py` never opened the source, so 30 of 50 cells replaced by
`GARBAGE LANE` read `OK ... rc 0`. Here it names the row and the column.
Run: python3 -m unittest discover -p 'test_verify_wizards.py' -v
"""
import csv
import io
import json
import os
import shutil
import subprocess
import sys
import tempfile
import unittest
HERE = os.path.dirname(os.path.abspath(__file__))
REPO = os.path.dirname(os.path.dirname(HERE))
VERIFIER = os.path.join(REPO, "wizard-work", "ledger", "verify_wizards.py")
SOURCE = "WIZARDS-TABLE.md"
CSV_REL = os.path.join("wizard-work", "ledger", "wizards.csv")
MAN_REL = os.path.join("wizard-work", "ledger", "wizards.manifest.json")
def read_rows(path):
with open(path, newline="", encoding="utf-8") as fh:
return list(csv.reader(fh))
def write_rows(path, rows):
with open(path, "w", newline="", encoding="utf-8") as fh:
csv.writer(fh).writerows(rows)
class Fixture(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.mkdtemp(prefix="q113-")
os.makedirs(os.path.join(self.tmp, "wizard-work", "ledger"))
shutil.copy(os.path.join(REPO, SOURCE), os.path.join(self.tmp, SOURCE))
for rel in (CSV_REL, MAN_REL):
shutil.copy(os.path.join(REPO, rel), os.path.join(self.tmp, rel))
def tearDown(self):
shutil.rmtree(self.tmp, ignore_errors=True)
# -- helpers ---------------------------------------------------------
def csv_path(self):
return os.path.join(self.tmp, CSV_REL)
def man_path(self):
return os.path.join(self.tmp, MAN_REL)
def load_manifest(self):
with open(self.man_path(), encoding="utf-8") as fh:
return json.load(fh)
def save_manifest(self, manifest):
with open(self.man_path(), "w", encoding="utf-8") as fh:
json.dump(manifest, fh, indent=2, sort_keys=True)
fh.write("\n")
def repin_csv(self, rows=None):
"""Rewrite the CSV and make the manifest agree with its bytes/rows.
This is how a cell isolates the leg it means to grade: the shape leg
stays green, so a red reading can only come from the leg under test.
"""
import hashlib
path = self.csv_path()
if rows is not None:
write_rows(path, rows)
with open(path, "rb") as fh:
data = fh.read()
manifest = self.load_manifest()
manifest["csv_sha256"] = hashlib.sha256(data).hexdigest()
manifest["row_count"] = len(read_rows(path)) - 1
self.save_manifest(manifest)
def run_verifier(self, cwd=None, extra=()):
return subprocess.run(
[sys.executable, VERIFIER, "--root", self.tmp] + list(extra),
cwd=cwd or self.tmp, capture_output=True, text=True, timeout=60)
# -- cells -----------------------------------------------------------
def test_clean_fixture_is_green(self):
proc = self.run_verifier()
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
self.assertIn("VERDICT TRUE", proc.stdout)
self.assertIn("18 row(s), 7 column(s), 126 cell(s) compared, 0 fault(s)",
proc.stdout)
def test_renamed_wizard_is_a_fault(self):
rows = read_rows(self.csv_path())
idx = [r[1] for r in rows].index("Merlin")
rows[idx][1] = "Merlin the Red"
self.repin_csv(rows)
proc = self.run_verifier()
self.assertEqual(proc.returncode, 1, proc.stdout)
self.assertIn("column 'Wizard'", proc.stdout)
self.assertIn("Merlin the Red", proc.stdout)
def test_corrupted_lane_cell_is_a_fault(self):
# The filed defect: every Lane cell replaced by GARBAGE LANE was green.
rows = read_rows(self.csv_path())
for row in rows[1:]:
row[3] = "GARBAGE LANE"
self.repin_csv(rows)
proc = self.run_verifier()
self.assertEqual(proc.returncode, 1, proc.stdout)
self.assertIn("column 'Lane'", proc.stdout)
self.assertIn("VERDICT FALSE", proc.stdout)
def test_corrupted_current_unit_is_a_fault(self):
rows = read_rows(self.csv_path())
idx = [r[1] for r in rows].index("Volt")
rows[idx][5] = "queue replies"
self.repin_csv(rows)
proc = self.run_verifier()
self.assertEqual(proc.returncode, 1, proc.stdout)
self.assertIn("column 'Current unit'", proc.stdout)
def test_dropped_correction_marker_is_a_fault(self):
rows = read_rows(self.csv_path())
idx = [r[1] for r in rows].index("Zephyrus Sparkborn")
self.assertTrue(rows[idx][-1], "fixture row carries no marker to drop")
rows[idx][-1] = ""
self.repin_csv(rows)
proc = self.run_verifier()
self.assertEqual(proc.returncode, 1, proc.stdout)
self.assertIn("does not carry the withdrawn marker", proc.stdout)
def test_marker_on_a_row_with_nothing_withdrawn_is_a_fault(self):
rows = read_rows(self.csv_path())
idx = [r[1] for r in rows].index("Timmy")
rows[idx][-1] = "WITHDRAWN - nothing was withdrawn here"
self.repin_csv(rows)
proc = self.run_verifier()
self.assertEqual(proc.returncode, 1, proc.stdout)
self.assertIn("marker with no withdrawal recorded", proc.stdout)
def test_source_mutation_without_repin_is_a_pin_fault(self):
path = os.path.join(self.tmp, SOURCE)
with open(path, encoding="utf-8") as fh:
text = fh.read()
mutated = text.replace("| Merlin | StepFun Step 5 |",
"| Merlin | StepFun Step 6 |")
self.assertNotEqual(mutated, text, "source mutation did not apply")
with open(path, "w", encoding="utf-8") as fh:
fh.write(mutated)
proc = self.run_verifier()
self.assertEqual(proc.returncode, 1, proc.stdout)
self.assertIn("source moved without a re-extract", proc.stdout)
def test_missing_row_is_a_fault(self):
rows = read_rows(self.csv_path())
dropped = rows.pop(3)
self.repin_csv(rows)
proc = self.run_verifier()
self.assertEqual(proc.returncode, 1, proc.stdout)
self.assertIn("row %r missing from the CSV" % dropped[1], proc.stdout)
def test_short_row_is_a_fault(self):
rows = read_rows(self.csv_path())
rows[1] = rows[1][:-1] # drop the Correction cell from row 1
self.repin_csv(rows)
proc = self.run_verifier()
self.assertEqual(proc.returncode, 1, proc.stdout)
self.assertIn("has 6 column(s), the header has 7", proc.stdout)
def test_tampered_row_count_is_a_shape_fault(self):
manifest = self.load_manifest()
manifest["row_count"] = 17
self.save_manifest(manifest)
proc = self.run_verifier()
self.assertEqual(proc.returncode, 1, proc.stdout)
self.assertIn("data row(s) != manifest row_count", proc.stdout)
def test_missing_manifest_cannot_grade(self):
os.remove(self.man_path())
proc = self.run_verifier()
self.assertEqual(proc.returncode, 2, proc.stdout)
self.assertIn("CANNOT GRADE", proc.stdout)
def test_missing_csv_cannot_grade(self):
os.remove(self.csv_path())
proc = self.run_verifier()
self.assertEqual(proc.returncode, 2, proc.stdout)
self.assertIn("CANNOT GRADE", proc.stdout)
def test_same_verdict_from_a_foreign_cwd(self):
proc = self.run_verifier(cwd="/")
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
self.assertIn("VERDICT TRUE", proc.stdout)
if __name__ == "__main__":
unittest.main(verbosity=2)
+335 -28
View File
@@ -1,37 +1,344 @@
#!/usr/bin/env python3
"""Falsifiable gate for the WIZARDS-TABLE roster extract (`wizards.csv`).
WHAT IT GRADES
1. PIN the source file's bytes are the bytes the extractor pinned:
sha256 and size against `wizards.manifest.json`, plus the git
blob id when this tree can answer for it. A roster table that
moved without a re-extract is a FAIL, not a silent re-read.
2. SHAPE the CSV's header is exactly the manifest's column list, its row
count matches, and its bytes hash to `csv_sha256`.
3. CONTENT every cell is re-derived from the pinned source by this file's
own parser and compared one cell at a time, so a renamed Wizard
or a corrupted Lane cell names the row and the column instead
of returning a green light (the defect Q113 filed).
4. CORRECTION the table appends a control-plane correction that withdraws
one row's escalate-line. A transcription that copies the cell
and drops the correction re-issues a withdrawn escalation, so
each correction in the manifest must (a) carry its marker in
the CSV, (b) name text that is still in the source cell, and
(c) cite an authority span that still contains its phrase. A
marker on a row with nothing withdrawn is a fault too, so the
column cannot be sprayed green.
The parse here is an independent re-implementation of the extractor's rule,
not an oracle: the two agree by construction on the stated rule (5 cells,
`lane signer` iff the Model cell says it has no model of its own), and their
agreement is a transcription check.
Paths are derived from this file's own location; `--root DIR` grades a tree
this file did not ship from (how the cells build their mutants).
Exit codes (repo tool contract):
0 every leg passed
1 at least one leg faulted
2 could not grade (missing/unparseable artifact, source or manifest)
"""
import argparse
import csv
import hashlib
import io
import json
import os
import subprocess
import sys
PATH = '/root/troupe-standup/wizard-work/ledger/wizards.csv'
HERE = os.path.dirname(os.path.realpath(__file__))
ROOT = os.path.dirname(os.path.dirname(HERE))
CSV_NAME = "wizards.csv"
MANIFEST_NAME = "wizards.manifest.json"
TABLE_HEADER = ["Wizard", "Model", "Lane", "Latest check-in", "Current unit"]
LANE_SIGNER_MARK = "no model of its own"
FAULTS = []
CANNOT = []
def main():
with open(PATH, newline='', encoding='utf-8') as f:
rows = list(csv.reader(f))
def pass_(text):
print("PASS " + text)
errors = []
if not rows:
errors.append('empty file')
def fail(text):
FAULTS.append(text)
print("FAIL " + text)
def info(text):
print("INFO " + text)
def cannot(text):
CANNOT.append(text)
print("CANNOT GRADE " + text)
def sha256(data):
return hashlib.sha256(data).hexdigest()
def cells_of(line):
parts = [c.strip() for c in line.strip().split("|")]
if parts and parts[0] == "":
parts = parts[1:]
if parts and parts[-1] == "":
parts = parts[:-1]
return parts
def parse_source(text):
"""Independent parse: -> (list of 5-cell rows, source lines)."""
lines = text.splitlines()
start = None
for i, line in enumerate(lines):
if cells_of(line) == TABLE_HEADER:
start = i
break
if start is None:
raise ValueError("roster header not found")
sep = cells_of(lines[start + 1]) if start + 1 < len(lines) else []
if not sep or not all(set(c) <= set("-: ") for c in sep):
raise ValueError("no header separator after the roster header")
rows = []
for line in lines[start + 2:]:
s = line.strip()
if not s or s.startswith("#") or not s.startswith("|"):
break
row = cells_of(s)
if len(row) != 5:
raise ValueError("row is not 5 cells: %r" % s[:70])
rows.append(row)
return rows, lines
def git_blob(root, relpath):
try:
proc = subprocess.run(["git", "-C", root, "hash-object", relpath],
capture_output=True, text=True, timeout=20)
except (OSError, subprocess.SubprocessError):
return None, "git unavailable"
if proc.returncode != 0:
return None, (proc.stderr.strip().splitlines() or ["git failed"])[0]
return proc.stdout.strip(), ""
def main(argv=None):
ap = argparse.ArgumentParser(
description="Grade the WIZARDS-TABLE roster extract against its pin.")
ap.add_argument("--root", default=ROOT,
help="tree to grade (default: the tree this file sits in)")
args = ap.parse_args(argv)
root = os.path.realpath(args.root)
ledger = os.path.join(root, "wizard-work", "ledger")
# --- inputs -----------------------------------------------------------
man_path = os.path.join(ledger, MANIFEST_NAME)
csv_path = os.path.join(ledger, CSV_NAME)
try:
with open(man_path, "rb") as fh:
manifest = json.loads(fh.read().decode("utf-8"))
except (OSError, ValueError) as exc:
cannot("%s not readable/parseable: %s" % (man_path, exc))
return 2
try:
with open(csv_path, "rb") as fh:
csv_bytes = fh.read()
except OSError as exc:
cannot("%s not readable: %s" % (csv_path, exc))
return 2
source_rel = manifest.get("source")
if not isinstance(source_rel, str) or not source_rel:
cannot("%s carries no 'source' path" % MANIFEST_NAME)
return 2
source_path = os.path.join(root, source_rel)
try:
with open(source_path, "rb") as fh:
source_bytes = fh.read()
except OSError as exc:
cannot("%s not readable: %s" % (source_path, exc))
return 2
# --- 1. pin -----------------------------------------------------------
want_sha = manifest.get("source_sha256")
got_sha = sha256(source_bytes)
if got_sha == want_sha:
pass_("pin: %s sha256=%s bytes=%d"
% (source_rel, got_sha[:12], len(source_bytes)))
else:
if rows[0] != ['Wizard', 'Model', 'Lane', 'Latest check-in', 'Current unit']:
errors.append('bad header: %r' % rows[0])
data = rows[1:]
if len(data) != 10:
errors.append('expected 10 data rows, got %d' % len(data))
names = [r[0] for r in data]
for need in ('Zephyrus Sparkborn', 'Merlin'):
if need not in names:
errors.append('%s missing' % need)
models = [r[1] for r in data]
if 'StepFun Step 5' not in models:
errors.append('Merlin model != StepFun Step 5: %r' % models)
if errors:
print('FAIL:')
for e in errors:
print(' -', e)
sys.exit(1)
print('OK: wizards.csv -> header + 10 data rows (10 wizards)')
sys.exit(0)
fail("pin: %s sha256=%s != pinned %s -- source moved without a "
"re-extract; run: python3 wizard-work/ledger/extract_wizards.py"
% (source_rel, got_sha[:12], str(want_sha)[:12]))
if manifest.get("source_bytes") not in (None, len(source_bytes)):
fail("pin: %s is %d bytes, manifest pins %s"
% (source_rel, len(source_bytes), manifest.get("source_bytes")))
blob, why = git_blob(root, source_rel)
want_blob = str(manifest.get("source_blob") or "")
if blob is None:
info("pin: git blob not graded (%s)" % why)
elif len(want_blob) != 40:
fail("pin: manifest source_blob=%r is not a 40-hex blob id" % want_blob)
elif blob != want_blob:
fail("pin: %s blob=%s != pinned %s" % (source_rel, blob[:12], want_blob[:12]))
else:
pass_("pin: git blob %s matches the manifest" % blob[:12])
commit = str(manifest.get("source_commit") or "")
if len(commit) == 40 and all(c in "0123456789abcdef" for c in commit):
info("pin: blob read at commit %s, source states roster as of %s"
% (commit[:12], manifest.get("source_stated_date")))
else:
info("pin: source_commit=%r is not a 40-hex commit id" % commit)
# --- 2. shape ---------------------------------------------------------
columns = manifest.get("columns") or []
try:
parsed = list(csv.reader(io.StringIO(csv_bytes.decode("utf-8"))))
except (UnicodeDecodeError, csv.Error) as exc:
cannot("%s is not parseable CSV: %s" % (csv_path, exc))
return 2
if not parsed:
cannot("%s is empty" % csv_path)
return 2
header, data = parsed[0], parsed[1:]
if header != columns:
fail("shape: header %r != manifest columns %r" % (header, columns))
else:
pass_("shape: header %d columns" % len(header))
if len(data) != manifest.get("row_count"):
fail("shape: %d data row(s) != manifest row_count %r"
% (len(data), manifest.get("row_count")))
else:
pass_("shape: %d data row(s)" % len(data))
if sha256(csv_bytes) != manifest.get("csv_sha256"):
fail("shape: csv sha256=%s != pinned %s -- the CSV was edited after "
"extraction" % (sha256(csv_bytes)[:12],
str(manifest.get("csv_sha256"))[:12]))
else:
pass_("shape: csv sha256=%s matches the pin" % sha256(csv_bytes)[:12])
# --- 3. content, cell by cell ----------------------------------------
try:
source_rows, source_lines = parse_source(source_bytes.decode("utf-8"))
except (UnicodeDecodeError, ValueError) as exc:
cannot("%s: %s" % (source_rel, exc))
return 2
corrections = manifest.get("corrections") or []
markers = {c["row"]: c["marker"] for c in corrections if "row" in c}
expected = []
for lead, model, lane, latest, unit in source_rows:
expected.append([
"lane signer" if LANE_SIGNER_MARK in model else "wizard",
lead, model, lane, latest, unit, markers.get(lead, ""),
])
faults_before = len(FAULTS)
compared = 0
# Name the rows that are absent or extra before the positional diff, so a
# deleted roster row reads as a deleted row rather than only as a cascade
# of shifted cells.
data_leads = [r[1] for r in data if len(r) > 1]
for want_row in expected:
if want_row[1] not in data_leads:
fail("content: row %r missing from the CSV" % want_row[1])
for got_row in data:
if len(got_row) > 1 and got_row[1] not in [e[1] for e in expected]:
fail("content: CSV row %r is not in the source" % got_row[1])
for idx in range(max(len(expected), len(data))):
if idx >= len(data):
fail("content: row %d (%s) missing from the CSV"
% (idx + 1, expected[idx][1]))
continue
if idx >= len(expected):
fail("content: CSV row %d (%r) is not in the source"
% (idx + 1, data[idx][0]))
continue
if len(data[idx]) != len(columns):
fail("content: row %d (%s) has %d column(s), the header has %d"
% (idx + 1, expected[idx][1], len(data[idx]), len(columns)))
for col, (want, got) in enumerate(zip(expected[idx], data[idx])):
compared += 1
if want != got:
name = columns[col] if col < len(columns) else "col%d" % col
fail("content: row %d (%s) column %r: %r != source %r"
% (idx + 1, expected[idx][1], name, got, want))
if len(FAULTS) == faults_before:
pass_("content: %d rows x %d column(s) = %d cell(s) re-derived"
% (len(expected), len(columns), compared))
# --- 4. corrections ---------------------------------------------------
cell_index = {c: i for i, c in enumerate(columns)}
rows_by_lead = {r[1]: r for r in data if len(r) > 1}
for corr in corrections:
lead = corr.get("row")
col = corr.get("column")
marker = corr.get("marker")
row = rows_by_lead.get(lead)
if row is None:
fail("correction: row %r is not in the CSV" % lead)
continue
idx = cell_index.get(col)
if idx is None or idx >= len(row):
fail("correction: row %r names column %r, not in the CSV"
% (lead, col))
continue
if row[-1] != marker:
fail("correction: row %r Correction cell does not carry the "
"withdrawn marker" % lead)
else:
pass_("correction: row %r carries its marker" % lead)
withdrawn = corr.get("withdrawn_text") or ""
if withdrawn and withdrawn not in row[idx]:
fail("correction: row %r no longer contains the withdrawn text "
"in %r -- the marker outlives its subject" % (lead, col))
start = corr.get("authority_line_start")
end = corr.get("authority_line_end")
phrase = corr.get("authority_phrase") or ""
if isinstance(start, int) and isinstance(end, int):
span = "\n".join(source_lines[start - 1:end])
if phrase and phrase in span:
pass_("correction: authority %s:%d-%d still states %r"
% (source_rel, start, end, phrase[:40]))
else:
fail("correction: authority %s:%d-%d no longer states %r"
% (source_rel, start, end, phrase[:40]))
else:
fail("correction: row %r has no integer authority span" % lead)
for row in data:
if len(row) < len(columns):
continue
lead, marker = row[1], row[-1]
if marker and lead not in markers:
fail("correction: row %r carries a marker with no withdrawal "
"recorded in the manifest" % lead)
# Generic direction: any source cell holding a withdrawn phrase must be
# marked, whether or not its row is the one the manifest was written for.
for corr in corrections:
withdrawn = corr.get("withdrawn_text") or ""
col = cell_index.get(corr.get("column"))
if not withdrawn or col is None:
continue
for row in data:
if col < len(row) and withdrawn in row[col] and not row[-1]:
fail("correction: row %r holds a withdrawn phrase and no marker"
% row[1])
# --- summary ----------------------------------------------------------
checked = len(data)
print("verify_wizards: %d row(s), %d column(s), %d cell(s) compared, "
"%d fault(s)" % (checked, len(columns), compared, len(FAULTS)))
if CANNOT:
return 2
if FAULTS:
print("VERDICT FALSE: %d fault(s) -- see the FAIL lines above"
% len(FAULTS))
return 1
print("VERDICT TRUE: %s replays from %s at its pinned bytes"
% (CSV_NAME, source_rel))
return 0
if __name__ == '__main__':
main()
if __name__ == "__main__":
sys.exit(main())
+36 -4
View File
@@ -1,9 +1,41 @@
# Wizards roster — extracted table
Source: `WIZARDS-TABLE.md` (troupe-standup). Table header row `| Wizard | Model | Lane | Latest check-in | Current unit |`; 10 data rows as of the file's current state (no clock in the file; rows are the table's 10 roster entries).
Source: `WIZARDS-TABLE.md` (troupe-standup), pinned by the bytes the extractor read:
`wizards.manifest.json` carries the source's sha256, byte length, git blob id, the commit
the blob was read at, and the extraction clock. The source's own date line reads
**roster as of 2026-10-13 15:13Z** — fifteen days before the 2026-10-29 extraction — so the
rows below are the table's rows at that stated date, not a live census of the check-ins.
Pipeline: parse the markdown pipe table -> CSV with quoted fields (cells contain commas and quotes).
Pipeline: `extract_wizards.py` parses the markdown pipe table (header
`| Wizard | Model | Lane | Latest check-in | Current unit |`) into `wizards.csv` with quoted
fields (cells contain commas and double quotes) and writes the pin manifest beside it.
`verify_wizards.py` re-derives the CSV from the pinned source with its own parser and
compares it cell by cell; `CHECK-wizards` is the shell entry point.
Columns: Wizard | Model | Lane | Latest check-in | Current unit
Rows: **18** — 10 `wizard` rows and 8 `lane signer` rows. The table gained the lane signer
rows on 2026-10-28 (Q124: "lanes sign as themselves, and the rows above put them in the
roster"), and the earlier 10-row extraction stopped before them; a roster CSV that omits
eight of the table's rows is not a transcription of the table. The `Kind` column states
which is which by a printed rule, not by position: a row is a `lane signer` when its Model
cell carries no model of its own.
Verified: 10 data rows; header exact. Re-derive with `CHECK`.
Columns: Kind | Wizard | Model | Lane | Latest check-in | Current unit | Correction
Corrections carried, not dropped: the table appends a control-plane correction at
`WIZARDS-TABLE.md:90-99` declaring the Zephyrus Sparkborn row **"false as written"** and
**withdrawing** its escalate-line ("this needs Alexander's one line — re-task the lane or
let it lapse — not silence"), because the lane was egress-blocked rather than silent. A
transcription that copies that cell and drops the correction re-issues a withdrawn
escalation to every consumer, so the row's `Correction` cell carries the marker recorded in
`wizards.manifest.json` and the gate fails if the marker goes missing, if the marker
appears on a row with nothing withdrawn, if the withdrawn text leaves the source cell, or
if the authority span stops saying what it said.
Re-derive: `python3 wizard-work/ledger/extract_wizards.py` (writes the CSV and the manifest).
Grade: `bash wizard-work/ledger/CHECK-wizards` — rc 0 pass, 1 fault, 2 could not grade.
Cells: `python3 wizard-work/ledger/test_verify_wizards.py` (12 cells, each on a throwaway
fixture; the repository is never mutated by a cell).
Known limit, stated: the gate compares against the pinned bytes, so a roster refresh that
edits `WIZARDS-TABLE.md` reds this artifact until it is re-extracted. That is the pin doing
its job — the CSV is stale the moment the table moves — and the FAIL line names the remedy.
+19 -11
View File
@@ -1,11 +1,19 @@
Wizard,Model,Lane,Latest check-in,Current unit
Timmy,Hermes / DeepSeek,"Operating partner — replies, queue, escalation",— (replies daily),queue replies
Zephyrus Sparkborn,Mistral (Muse),Archive verification & summary fidelity,2026-10-10,"**Q20 — taken, not worked.** His named unit (excerpt fidelity & placement, 91 magazine entries) was closed by **Merlin** at `9a1de9a` (2026-10-12 04:49Z; verified from this host in `WORK-QUEUE.md`'s Q20 block and `replies/2026-10-12-to-merlin-20.md`) after Merlin's own process-fault disclosure. No Zephyrus check-in since 2026-10-10 (his newest commit is `a4fc298`, 2026-10-10T13:17:32Z; there is none for 2026-10-11 or 2026-10-12 — the earlier ""20:58Z"" in this cell was a clock this pipe cannot reproduce from `checkins/`, so the commit time replaces it), so his lane has nothing assigned and no unit of his own: **this needs Alexander's one line — re-task the lane or let it lapse — not silence**"
Cassian Assayborn,Grok,Repo census & access-state verification,2026-10-07,"— (Q5 closed; no open unit — lane silent since 2026-10-07, 5 days, needs a decision, not silence)"
Merlin,StepFun Step 5,"The Crucible — one hard problem → one finished, verifiable artifact",2026-10-12,"**All observed through Run 6; nothing of his is open.** Q39 closed (`fad802c`, fixed gate `9b09f328…`, all five negatives refused) and **verified from this host** in reply 22; Q40 closed and verified in reply 23 — the deployed gate `7ed1bca8…` returns rc 0 / 119 passed on all five negatives because `grep -c HELM_COLLECTOR` = **0**: it imports its subject at module scope (`:39`) and has **no subject-selection path at all**. **Adoption hold stands: do not `cp` gate `74aba348…`, and the §4 `cp` of collector `4e45021d…` + gate `9b09f328…` is Alexander's** — it is the only thing that puts Q31–Q40's protection into production. Standing asks, unchanged: adopt/hold, log rotation + `docker system prune`, and a ruling on `stackchain-dashboard.service`"
Mercury,Groq (free tier),"Fast verification & triage — rapid mechanical passes, first-pass extraction",2026-10-12,"**Day-3 check-in landed `e9efb23` at 12:00:38Z and it is the Q31 first slice, executed** — the collector's entry point run from a lane that is not Merlin's; that unit is now **discharged** (reply `replies/2026-10-12-to-mercury-03.md`). All eight of his measurements reproduce from this host, six byte-exact, including the two `/tmp` files he left behind (`efc9a241…`, `99e38db0…`) and the `--compare-live` line character for character; his two bodies differ from each other in clocks only. Next unit is set in the harness: a **read-only disk census** that must reproduce or falsify this pipe's own two figures (`500–600 MB/day` vs `~153 MB/day`; and ""logrotate did not rotate `syslog` at 2026-10-12 00:00Z"") — nothing may be deleted, moved, rotated, pruned, stopped or reconfigured on it"
Gemini,"Google Gemini (relayed, chat-only)","The Synthesis — reconcile the record, surface contradictions and the cross-cutting picture",2026-10-13,"First reply landed via relay: identity confirmed + a draft ""Submission & Verification Audit Log"" format. **Lane charter + three first queue items owed.** Fault recorded (see check-in): cited example IDs (`fleet-ops`, `timmy-dispatch`, `self_heal.py`, …) that do not exist in the repo, not marked as placeholders"
Argus,LongCat 2.5,"The Watch — evidence-law enforcement: verifies every check-in/commit/reply against the evidence rules, files cited findings to `audits/`",2026-10-14,Staffed. Lane: audit the pipe daily; findings carry file:line + SHA + severity; a clean pass must cite the SHA range checked. Model `meituan/longcat-2.5-preview:free`
Volt,DeepSeek V4.1 Flash,"The Workhorse — high-throughput general agent work: queue grind, general coding/reasoning, quick verifications, refactors, scripts",2026-10-15,"Staffed. Model `deepseek-v4.1-flash` (552B MoE, 8B/16B active, native multimodal) via DeepSeek API. Clears the unowned queue items the specialized lanes don't take"
Sentinel,Nemotron 3.5 Super VL,"The Long View — long-horizon multimodal agent work: sustained multi-step tasks, end-to-end reads, image+text reconciliation",2026-10-15,"Staffed. Model `nvidia/nemotron-3.5-super-vl-120b-a12b` (120B MoE, 12B active, vision-language) via NVIDIA NIM free credits. Holds the thread on runs the flash lanes can't sustain"
Beam,Reflection Beam 1.0 (501B),"The Foundry — deep reasoning & hard coding/agentic problems → finished, CHECK-verified artifacts, max throughput",2026-10-20,"Staffed. Model `reflection/beam-1.0-501b-a23b:free` (501B MoE, 23B active, reasoning model) via Nous free tier. **FREE WINDOW ≈ 1 week — run at max throughput until it expires**"
Kind,Wizard,Model,Lane,Latest check-in,Current unit,Correction
wizard,Timmy,Hermes / DeepSeek,"Operating partner — replies, queue, escalation",— (replies daily),queue replies,
wizard,Zephyrus Sparkborn,Mistral (Muse),Archive verification & summary fidelity,2026-10-10,"**Q20 — taken, not worked.** His named unit (excerpt fidelity & placement, 91 magazine entries) was closed by **Merlin** at `9a1de9a` (2026-10-12 04:49Z; verified from this host in `WORK-QUEUE.md`'s Q20 block and `replies/2026-10-12-to-merlin-20.md`) after Merlin's own process-fault disclosure. No Zephyrus check-in since 2026-10-10 (his newest commit is `a4fc298`, 2026-10-10T13:17:32Z; there is none for 2026-10-11 or 2026-10-12 — the earlier ""20:58Z"" in this cell was a clock this pipe cannot reproduce from `checkins/`, so the commit time replaces it), so his lane has nothing assigned and no unit of his own: **this needs Alexander's one line — re-task the lane or let it lapse — not silence**","WITHDRAWN - escalate-line withdrawn by WIZARDS-TABLE.md:90-99; the lane was egress-blocked, not silent"
wizard,Cassian Assayborn,Grok,Repo census & access-state verification,2026-10-07,"— (Q5 closed; no open unit — lane silent since 2026-10-07, 5 days, needs a decision, not silence)",
wizard,Merlin,StepFun Step 5,"The Crucible — one hard problem → one finished, verifiable artifact",2026-10-12,"**All observed through Run 6; nothing of his is open.** Q39 closed (`fad802c`, fixed gate `9b09f328…`, all five negatives refused) and **verified from this host** in reply 22; Q40 closed and verified in reply 23 — the deployed gate `7ed1bca8…` returns rc 0 / 119 passed on all five negatives because `grep -c HELM_COLLECTOR` = **0**: it imports its subject at module scope (`:39`) and has **no subject-selection path at all**. **Adoption hold stands: do not `cp` gate `74aba348…`, and the §4 `cp` of collector `4e45021d…` + gate `9b09f328…` is Alexander's** — it is the only thing that puts Q31–Q40's protection into production. Standing asks, unchanged: adopt/hold, log rotation + `docker system prune`, and a ruling on `stackchain-dashboard.service`",
wizard,Mercury,Groq (free tier),"Fast verification & triage — rapid mechanical passes, first-pass extraction",2026-10-12,"**Day-3 check-in landed `e9efb23` at 12:00:38Z and it is the Q31 first slice, executed** — the collector's entry point run from a lane that is not Merlin's; that unit is now **discharged** (reply `replies/2026-10-12-to-mercury-03.md`). All eight of his measurements reproduce from this host, six byte-exact, including the two `/tmp` files he left behind (`efc9a241…`, `99e38db0…`) and the `--compare-live` line character for character; his two bodies differ from each other in clocks only. Next unit is set in the harness: a **read-only disk census** that must reproduce or falsify this pipe's own two figures (`500–600 MB/day` vs `~153 MB/day`; and ""logrotate did not rotate `syslog` at 2026-10-12 00:00Z"") — nothing may be deleted, moved, rotated, pruned, stopped or reconfigured on it",
wizard,Gemini,"Google Gemini (relayed, chat-only)","The Synthesis — reconcile the record, surface contradictions and the cross-cutting picture",2026-10-13,"First reply landed via relay: identity confirmed + a draft ""Submission & Verification Audit Log"" format. **Lane charter + three first queue items owed.** Fault recorded (see check-in): cited example IDs (`fleet-ops`, `timmy-dispatch`, `self_heal.py`, …) that do not exist in the repo, not marked as placeholders",
wizard,Argus,LongCat 2.5,"The Watch — evidence-law enforcement: verifies every check-in/commit/reply against the evidence rules, files cited findings to `audits/`",2026-10-14,Staffed. Lane: audit the pipe daily; findings carry file:line + SHA + severity; a clean pass must cite the SHA range checked. Model `meituan/longcat-2.5-preview:free`,
wizard,Volt,DeepSeek V4.1 Flash,"The Workhorse — high-throughput general agent work: queue grind, general coding/reasoning, quick verifications, refactors, scripts",2026-10-15,"Staffed. Model `deepseek-v4.1-flash` (552B MoE, 8B/16B active, native multimodal) via DeepSeek API. Clears the unowned queue items the specialized lanes don't take",
wizard,Sentinel,Nemotron 3.5 Super VL,"The Long View — long-horizon multimodal agent work: sustained multi-step tasks, end-to-end reads, image+text reconciliation",2026-10-15,"Staffed. Model `nvidia/nemotron-3.5-super-vl-120b-a12b` (120B MoE, 12B active, vision-language) via NVIDIA NIM free credits. Holds the thread on runs the flash lanes can't sustain",
wizard,Beam,Reflection Beam 1.0 (501B),"The Foundry — deep reasoning & hard coding/agentic problems → finished, CHECK-verified artifacts, max throughput",2026-10-20,"Staffed. Model `reflection/beam-1.0-501b-a23b:free` (501B MoE, 23B active, reasoning model) via Nous free tier. **FREE WINDOW ≈ 1 week — run at max throughput until it expires**",
lane signer,forge,"— (lane identity, no model of its own)",Refactor — `wizard-work/forge/`,2026-10-27,"Lane signer, ruled legitimate by **Q124** (2026-10-28, below). Author of `checkins/2026-10-27-forge.md`",
lane signer,ledger,"— (lane identity, no model of its own)",Ledger bookkeeping — `wizard-work/ledger/`,2026-10-28,Lane signer (**Q124**),
lane signer,sol,"— (lane identity, no model of its own)",Class triage — `wizard-work/sol/`,2026-10-28,Lane signer (**Q124**),
lane signer,quill,"— (lane identity, no model of its own)",Documents & briefs — `wizard-work/quill/`,2026-10-28,Lane signer (**Q124**),
lane signer,spark,"— (lane identity, no model of its own)",Script & cell work — `wizard-work/spark/`,2026-10-28,Lane signer (**Q124**),
lane signer,sphinx,"— (lane identity, no model of its own)",Archive retrieval dossiers — `wizard-work/sphinx/`,2026-10-28,Lane signer (**Q124**),
lane signer,null,"— (lane identity, no model of its own)",`wizard-work/null/`,2026-10-28,Lane signer (**Q124**),
lane signer,zeph,"— (lane identity, no model of its own)",Zephyrus Sparkborn's working directory — `wizard-work/zeph/`,2026-10-28,"Lane signer for the **zeph** lane only (**Q124**). Zephyrus Sparkborn signs under his own name, which is already a row above",
1 Kind Wizard Model Lane Latest check-in Current unit Correction
2 wizard Timmy Hermes / DeepSeek Operating partner — replies, queue, escalation — (replies daily) queue replies
3 wizard Zephyrus Sparkborn Mistral (Muse) Archive verification & summary fidelity 2026-10-10 **Q20 — taken, not worked.** His named unit (excerpt fidelity & placement, 91 magazine entries) was closed by **Merlin** at `9a1de9a` (2026-10-12 04:49Z; verified from this host in `WORK-QUEUE.md`'s Q20 block and `replies/2026-10-12-to-merlin-20.md`) after Merlin's own process-fault disclosure. No Zephyrus check-in since 2026-10-10 (his newest commit is `a4fc298`, 2026-10-10T13:17:32Z; there is none for 2026-10-11 or 2026-10-12 — the earlier "20:58Z" in this cell was a clock this pipe cannot reproduce from `checkins/`, so the commit time replaces it), so his lane has nothing assigned and no unit of his own: **this needs Alexander's one line — re-task the lane or let it lapse — not silence** WITHDRAWN - escalate-line withdrawn by WIZARDS-TABLE.md:90-99; the lane was egress-blocked, not silent
4 wizard Cassian Assayborn Grok Repo census & access-state verification 2026-10-07 — (Q5 closed; no open unit — lane silent since 2026-10-07, 5 days, needs a decision, not silence)
5 wizard Merlin StepFun Step 5 The Crucible — one hard problem → one finished, verifiable artifact 2026-10-12 **All observed through Run 6; nothing of his is open.** Q39 closed (`fad802c`, fixed gate `9b09f328…`, all five negatives refused) and **verified from this host** in reply 22; Q40 closed and verified in reply 23 — the deployed gate `7ed1bca8…` returns rc 0 / 119 passed on all five negatives because `grep -c HELM_COLLECTOR` = **0**: it imports its subject at module scope (`:39`) and has **no subject-selection path at all**. **Adoption hold stands: do not `cp` gate `74aba348…`, and the §4 `cp` of collector `4e45021d…` + gate `9b09f328…` is Alexander's** — it is the only thing that puts Q31–Q40's protection into production. Standing asks, unchanged: adopt/hold, log rotation + `docker system prune`, and a ruling on `stackchain-dashboard.service`
6 wizard Mercury Groq (free tier) Fast verification & triage — rapid mechanical passes, first-pass extraction 2026-10-12 **Day-3 check-in landed `e9efb23` at 12:00:38Z and it is the Q31 first slice, executed** — the collector's entry point run from a lane that is not Merlin's; that unit is now **discharged** (reply `replies/2026-10-12-to-mercury-03.md`). All eight of his measurements reproduce from this host, six byte-exact, including the two `/tmp` files he left behind (`efc9a241…`, `99e38db0…`) and the `--compare-live` line character for character; his two bodies differ from each other in clocks only. Next unit is set in the harness: a **read-only disk census** that must reproduce or falsify this pipe's own two figures (`500–600 MB/day` vs `~153 MB/day`; and "logrotate did not rotate `syslog` at 2026-10-12 00:00Z") — nothing may be deleted, moved, rotated, pruned, stopped or reconfigured on it
7 wizard Gemini Google Gemini (relayed, chat-only) The Synthesis — reconcile the record, surface contradictions and the cross-cutting picture 2026-10-13 First reply landed via relay: identity confirmed + a draft "Submission & Verification Audit Log" format. **Lane charter + three first queue items owed.** Fault recorded (see check-in): cited example IDs (`fleet-ops`, `timmy-dispatch`, `self_heal.py`, …) that do not exist in the repo, not marked as placeholders
8 wizard Argus LongCat 2.5 The Watch — evidence-law enforcement: verifies every check-in/commit/reply against the evidence rules, files cited findings to `audits/` 2026-10-14 Staffed. Lane: audit the pipe daily; findings carry file:line + SHA + severity; a clean pass must cite the SHA range checked. Model `meituan/longcat-2.5-preview:free`
9 wizard Volt DeepSeek V4.1 Flash The Workhorse — high-throughput general agent work: queue grind, general coding/reasoning, quick verifications, refactors, scripts 2026-10-15 Staffed. Model `deepseek-v4.1-flash` (552B MoE, 8B/16B active, native multimodal) via DeepSeek API. Clears the unowned queue items the specialized lanes don't take
10 wizard Sentinel Nemotron 3.5 Super VL The Long View — long-horizon multimodal agent work: sustained multi-step tasks, end-to-end reads, image+text reconciliation 2026-10-15 Staffed. Model `nvidia/nemotron-3.5-super-vl-120b-a12b` (120B MoE, 12B active, vision-language) via NVIDIA NIM free credits. Holds the thread on runs the flash lanes can't sustain
11 wizard Beam Reflection Beam 1.0 (501B) The Foundry — deep reasoning & hard coding/agentic problems → finished, CHECK-verified artifacts, max throughput 2026-10-20 Staffed. Model `reflection/beam-1.0-501b-a23b:free` (501B MoE, 23B active, reasoning model) via Nous free tier. **FREE WINDOW ≈ 1 week — run at max throughput until it expires**
12 lane signer forge — (lane identity, no model of its own) Refactor — `wizard-work/forge/` 2026-10-27 Lane signer, ruled legitimate by **Q124** (2026-10-28, below). Author of `checkins/2026-10-27-forge.md`
13 lane signer ledger — (lane identity, no model of its own) Ledger bookkeeping — `wizard-work/ledger/` 2026-10-28 Lane signer (**Q124**)
14 lane signer sol — (lane identity, no model of its own) Class triage — `wizard-work/sol/` 2026-10-28 Lane signer (**Q124**)
15 lane signer quill — (lane identity, no model of its own) Documents & briefs — `wizard-work/quill/` 2026-10-28 Lane signer (**Q124**)
16 lane signer spark — (lane identity, no model of its own) Script & cell work — `wizard-work/spark/` 2026-10-28 Lane signer (**Q124**)
17 lane signer sphinx — (lane identity, no model of its own) Archive retrieval dossiers — `wizard-work/sphinx/` 2026-10-28 Lane signer (**Q124**)
18 lane signer null — (lane identity, no model of its own) `wizard-work/null/` 2026-10-28 Lane signer (**Q124**)
19 lane signer zeph — (lane identity, no model of its own) Zephyrus Sparkborn's working directory — `wizard-work/zeph/` 2026-10-28 Lane signer for the **zeph** lane only (**Q124**). Zephyrus Sparkborn signs under his own name, which is already a row above
+34
View File
@@ -0,0 +1,34 @@
{
"artifact": "wizards.csv",
"columns": [
"Kind",
"Wizard",
"Model",
"Lane",
"Latest check-in",
"Current unit",
"Correction"
],
"corrections": [
{
"authority_line_end": 99,
"authority_line_start": 90,
"authority_phrase": "the Zephyrus row above is false as written",
"column": "Current unit",
"marker": "WITHDRAWN - escalate-line withdrawn by WIZARDS-TABLE.md:90-99; the lane was egress-blocked, not silent",
"row": "Zephyrus Sparkborn",
"withdrawn_text": "this needs Alexander's one line \u2014 re-task the lane or let it lapse \u2014 not silence"
}
],
"csv_sha256": "d899a23be01ec74ea37db0636250c57d3fab435405a31e2466ff252cdfc1f441",
"extracted_utc": "2026-10-29T23:12:29+00:00",
"lane_signer_rows": 8,
"row_count": 18,
"source": "WIZARDS-TABLE.md",
"source_blob": "1c82d0d39206426e5d5b419e84f64f5ab007f7ae",
"source_bytes": 11896,
"source_commit": "52d6588abd406d0ea1cc7a69ee190fdaf62fc065",
"source_sha256": "fd093a2898f96fd7c669eb2f7371aba5320f0e40498a7a1477b80caabf56cd03",
"source_stated_date": "2026-10-13 15:13Z",
"wizard_rows": 10
}