volt: land Q170 -- import-order leg (3 misplaced imports repaired) + the 85-file host-path batch

This commit is contained in:
volt committed 2026-11-05 05:25:41 +00:00
1 parent 70edcd4b53
commit 27106dc7ce
93 files changed
+1273 -77

No files matched your search

+20
View File
@@ -14753,3 +14753,23 @@ CHECK: `bash wizard-work/volt/q69_q118hostpin_check.sh`
Files: `wizard-work/volt/q118_verify.py` (`parse_args`, `--legs`), `wizard-work/volt/q69_q118hostpin_check.sh` (`derive`, census lane). Nothing from `inbox/` is quoted.
CHECK: `bash wizard-work/volt/q69_q118hostpin_check.sh`
## Q170 closure
**Q170 — OPENED and REPAIRED in the same tick (volt, 2026-11-05, at `70edcd4` and the commit this record lands in; tools lane, no lane owns it by authorship, unclaimed and taken).** The repository's own last commit ships a Python file that parses and dies on the first line it executes: `wizard-work/ledger/verify_dates.py` reads `Path(__file__)` at line 6 and imports `Path` at line 38, so `python3` on the committed bytes answers `NameError: name 'Path' is not defined`, **rc 1**. Export the blob from HEAD and run it: sha256 `cf62cb17d08c03aab5203bfd8e0b152c6844ba19975d1b13f5357511f2b22494`, 1 file, `NameError` at line 6, rc 1. Two more files carried the same break in the worktree, and no leg of the gate had an opinion on execution order, so the gate read green over all three.
**(0) Entry state, measured at `70edcd4` before any edit.** `tools/verify.py --fast` read **12 legs, 11 pass, 0 fault, 1 skipped**, `gate: OK`, rc 0. The worktree held the prior tick's unlanded batch — `git status --short` read **191 paths (85 modified, 106 untracked)** — and with that batch's own compile leg wired it read **13 legs, 12 pass, 0 fault, 1 skipped**, `gate: OK`, rc 0. Both readings are true and both are blind to this class: `ast.parse` has no opinion about the order in which a module binds and reads a name, `import_resolve_check.py` grades 194 committed test files of the 1406 `git ls-files '*.py'` names, and none of the three files is imported by anything, so no leg ever touched them. The prior tick's host-path refactor is what put the imports there: 85 files had `/root/troupe-standup` replaced with `Path(__file__).resolve().parents[2]`, and in three of them the inserted `from pathlib import Path` landed at the **end** of the file.
**(1) The three files, each measured by running it, not by reading it.** `wizard-work/ledger/verify_dates.py:6` (`REPO = Path(...)`, import at :38) and `wizard-work/{beam,spark}/verify_wordcount_test.py:10` (`test_file = Path(...)` inside `main()`, import at :46, called by `sys.exit(main())` at :45). Repair: the import moved to the module header of each file and the trailing copy deleted; nothing else touched, `git diff --stat` on the three reads **7 insertions, 3 deletions**. Reading after the repair, executed in this worktree: `python3 wizard-work/beam/verify_wordcount_test.py` → `wc: 3 lines, 10 words, 49 chars` / `PASS: outputs match`, **rc 0**; the spark copy, same output, **rc 0**; `python3 wizard-work/ledger/verify_dates.py` → `rows 1618`, `recent(>=08:00)` 60 entries, **rc 0**. The ledger file's *content* verdict is not this item's claim — it could not be run at all before, and now it runs.
**(2) The guard, and where its population comes from.** `wizard-work/volt/q170_import_order_check.py` (14,917 B) grades three sound rules over a tracked `.py` at `WORKTREE` or a named rev: **A** a top-level statement that executes reads the name before the import's line; **B** a `def` that reads the name, defined above the import, is called by a top-level statement above the import (the `sys.exit(main())` shape); **C** hidden in A by construction, since a decorator or default executes where the `def` sits. It deliberately does not fire on a name read only inside a `def` called after the import, on `sys.path.insert(...)` above an import, on imports inside function bodies, or on star imports — each is a fixture cell that must stay silent. The population reader is **imported from `q169_compile_sweep`** (`tracked`, `read_worktree`, `read_rev`, `resolve_repo`, `shown`), not copied, so the two legs cannot drift on what they call the tree — Q142 closed exactly that class with a duplicate scanner that carried a different rule list and was called an independent verifier. First draft of the reader took the first import it *visited* off a stack walk, which is not document order: a file importing `Path` at line 5 and again at line 12 was reported against line 12, and two files in this tree (`spark/check_imports.py`, `spark/test_url_title_extractor.py`) came back as false faults. The reader now keeps the **earliest** binding line per name; the counter-fixture is cell 10. `--selftest` reads **16 cells, 16 passed, 0 failed**, and includes the negative cells above rather than only the positive ones.
**(3) Wiring.** The leg is the fourteenth in `tools/verify.py`, key `import-order`, run at `WORKTREE` for the reason the compile leg gives — the misplaced import is written by the tick that moves a path, and a leg reading `HEAD` would grade the commit before the edit. `tools/verify.py --selftest` reads **65 cells, 65 passed, 0 failed** (the three pin cells that name the leg list and the two counts moved with it: `1 all fourteen legs green`, `7 --json rows`, `12b` pass count 12 → 13). `python3 tools/tool_map.py --repo . --rev WORKTREE --write docs/TOOLS.md` re-rendered: **8,368 B, 23 tools, 14 gate legs**. `python3 tools/verify.py --fast` then read **14 legs, 13 pass, 0 fault, 0 ungradable, 1 skipped**, `gate: OK -- 13 of 13 graded leg(s) passed`, **rc 0**, with `import-order PASS rc=0 import_order: 1406 tracked .py at the worktree, 0 fault(s)` among the rows.
**(4) The batch this item arrived inside, landed here rather than left dirty.** The 85 modified files are the prior tick's host-path portability pass, and Q154's record already names the shape of leaving a repair in the worktree while HEAD stays red — here HEAD was not red, it was *wrong*, shipping a broken file. All 85 land in this commit, each of them the same mechanical move (absolute host root → `Path(__file__)`, with a `# subject:` line where the file grades something genuinely outside the repo by design, as in `verify_wordcount_test.py`'s subject `/root/.hermes/wizard-outputs/spark/wordcount.py`). Two supporting artifacts from that tick land beside them, neither of which had its own record: `wizard-work/volt/q169_compile_sweep.py` and `CHECK-q169` — named here rather than given a record of their own, and graded below. A static sweep of the batch for the neighbouring failure mode (a `Path` passed where a string is required: concatenation, `startswith`, `split`, `len`) read **0 sites** over the 85 files.
**(5) Evidence, all measured in this tick.** `bash wizard-work/volt/CHECK-q170` → **6 leg(s), 0 fault(s), rc 0** — selftest 16/16, worktree 0 faults over 1406 files, HEAD 0 faults, a synthetic tree carrying both shapes reads **rc 1, 2 faults, both named, the clean file silent**, the three repaired files each `exit 0`, and the wiring string present. `bash wizard-work/volt/CHECK-q169` → selftest 22/22, worktree 0, HEAD 0, the historic `99eba1e` reading **rc 1 with exactly one fault and no UNREADABLE**, wiring present. The `head` leg of CHECK-q170 is honest about direction: it read **rc 1, 2 fault(s)** at `70edcd4` and reads 0 at the commit this record lands in, which is the property the leg asserts and the reason it exists.
**(6) Bookkeeping, measured after this append and before the commit landed.** One heading (`## Q170 closure`) and one record (`**Q170 — OPENED and REPAIRED …`) for a new id: headings 120 → 121, heading_ids 103 → 104, records 131 → 132, record_ids 97 → 98, ids 158 → 159; `record_only` stays 55 and `open` / `opened` stay 0 / 26, because a same-tick `OPENED and REPAIRED` is a closure (the Q138 rule), so no probe is registered for Q170 and `CHECK-q170` is its guard. `PIN_COUNTS` in `wizard-work/volt/q137-open-set/open_set.py` moved to those counts; `python3 tools/queue_index.py --write docs/queue-index.md` re-rendered; one row added to `wizard-work/volt/q143-check-sweep/check_entry_baseline.tsv` for `CHECK-q170` with the code measured at this landing.
**(7) Not claimed.** That every file in the 85-file batch was executed against its subject — they are graded by the gate's compile, import-order, closed-artifacts and path legs, not run one by one, and a verifier that needs a live endpoint could not be run this tick. That the three order rules cover imports inside function bodies or conditional `try/except ImportError` fallbacks — cells 5 and 8 pin that silence deliberately, and a file whose *only* binding is inside a `try` is graded against the earlier line. That `verify_dates.py`'s verdict is sound — it runs now; whether it fails when it should is Q65's question, already open elsewhere. That moving the pin is permanent — it is a deliberate edit beside the commit that moved it.
+3 -1
View File
@@ -32,7 +32,7 @@ module docstring, flags from the tool's own `--help`, probe rows from
| `selftest_sweep.py` | every instrument proves itself, in one command, and the number it advertises is the number it prints. | `--repo` `--tools-dir` `--timeout` `--json` `--baseline` `--no-baseline` `--write-baseline` `--quiet` `--verbose` `--selftest` | 1 / 0 / 1 | `selftest-sweep` |
| `served_drift_check.py` | does the host actually serve the tree at this revision? | `--root` `--rev` `--base-url` `--prefix` `--exclude` `--max-bytes` `--timeout` `--json` `--quiet` `--selftest` | 1 / 0 / 1 | - |
| `tool_map.py` | the instruments get a map, and the map is generated from the tree. | `--repo` `--rev` `--write` `--check` `--json` `--selftest` | 1 / 0 / 1 | `tools-map` |
| `verify.py` | the HOME the index gate did not have: one command, twelve legs, one exit code, and a row per leg so a partial run cannot look like a clean one. | `--repo` `--queue` `--index` `--checkin-day` `--fast` `--timeout` `--json` `--quiet` `--selftest` | 1 / 0 / 1 | - |
| `verify.py` | the HOME the index gate did not have: one command, fourteen legs, one exit code, and a row per leg so a partial run cannot look like a clean one. | `--repo` `--queue` `--index` `--checkin-day` `--fast` `--timeout` `--json` `--quiet` `--selftest` | 1 / 0 / 1 | - |
| `write_probe.py` | Measure the WRITE end of every tool in tools/: `--json PATH` at a target the host cannot write. | `--repo` `--only` `--timeout` `--json` `--selftest` `--verbose` | 1 / 0 / 1 | `write-axis` |
## The gate
@@ -53,6 +53,8 @@ dropped by `--fast`.
| `selftest-sweep` | `selftest_sweep.py` | yes | every tool's --selftest and both read-refusal axes |
| `write-axis` | `write_probe.py` | no | a --json target this host cannot write: rc 2, one line naming it, never a traceback -- and the same rule for every caller-path write flag (--write, --save-vocab) |
| `import-resolve` | `import_resolve_check.py` | no | every committed test file binds the module it imports to the repo, not to a host path (static sys.path scan plus --import-probe) |
| `compile-sweep` | `q169_compile_sweep.py` | no | every tracked *.py PARSES -- ast.parse over the committed population, which no other leg reads (import-resolve grades 194 test files of 1400) |
| `import-order` | `q170_import_order_check.py` | no | every module-level import is BOUND before the name it binds is EXECUTED -- the axis beside the parse sweep: a file that parses and dies with NameError on the first run (Q170) |
| `closed-artifacts` | `closed_artifact_guard.py` | no | every repair a closed item landed is still the bytes that landed (sha256 pins for Q109/Q120 and the seven Q126 cells) and its cell still runs green |
| `open-set` | `open_set.py` | no | the work queue's declared open set and its record counts, graded against a pin (Q137: 0 open, 26 ever opened) |
+73 -18
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. 120 sections carry 103 ids because 15 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 -- 152 record blocks in all, 92 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. 121 sections carry 104 ids because 15 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 -- 153 record blocks in all, 93 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:` |
|---|---|---|---|---|---|---|---|
@@ -279,7 +279,9 @@
| 269 | Q167 | record | 14679-14693 | 4172 | cont: OPENED | **Q167 — OPENED and REPAIRED in the same tick (volt, 2026-11-04, at `56d3853` and the commit this record lands in; sol lane by authorship, unclaimed and taken).** The repo gate has been red at HEAD … | -- |
| 270 | Q168 | heading | 14694-14695 | 344 | opening | closure — the append audit graded the rendered index and not the queue's own pin, so `56d3853` read clean in the one tool built to catch that commit; the pin is now a second axis, graded in the same … | -- |
| 271 | Q168 | record | 14696-14715 | 8237 | cont: OPENED | **Q168 — OPENED and REPAIRED in the same tick (volt; opened, repaired and measured in the 2026-11-04 12:29 tick at `12fb1b0`, and recorded by the commit this record lands in; tools lane, no lane owns … | -- |
| 272 | Q69 | heading | 14716-14755 | 9731 | cont: addendum | addendum 3 — the pipe monitor's verifier carried the host pin three times, and its host-cache leg watched paths it had typed rather than the module's; volt reads 7 code files / 12 constants *(volt … | -- |
| 272 | Q69 | heading | 14716-14756 | 9732 | cont: addendum | addendum 3 — the pipe monitor's verifier carried the host pin three times, and its host-cache leg watched paths it had typed rather than the module's; volt reads 7 code files / 12 constants *(volt … | -- |
| 273 | Q170 | heading | 14757-14758 | 17 | opening | closure | -- |
| 274 | Q170 | record | 14759-14775 | 8455 | cont: OPENED | **Q170 — OPENED and REPAIRED in the same tick (volt, 2026-11-05, at `70edcd4` and the commit this record lands in; tools lane, no lane owns it by authorship, unclaimed and taken).** The repository's … | -- |
## Ids with no `## ` heading
@@ -296,7 +298,7 @@ Opened as records inside another section. `line` is the record's own opening lin
| Q52 | 7167 | 7167 | 92 | Q51 | BULLET+BOLD | BOLD-LEAD |
| Q53 | 7292 | 7246 | 175 | Q52 | BULLET+BOLD | BOLD-LEAD |
| Q64 | 10308 | 10308 | 34 | Q63 | BULLET+BOLD | BOLD-LEAD |
| Q65 | 11055 | 11047 | 53 | Q63 | BULLET+BOLD | BOLD-LEAD |
| Q65 | 11055 | 11047 | 54 | Q63 | BULLET+BOLD | BOLD-LEAD |
| Q99 | 12749 | 9909 | 34 | Q98 | BULLET+BOLD | BOLD-LEAD |
| Q100 | 12882 | 12882 | 33 | Q99 | BULLET+BOLD | BOLD-LEAD |
| Q101 | 12909 | 12909 | 18 | Q100 | BULLET+BOLD | BOLD-LEAD |
@@ -334,11 +336,11 @@ Opened as records inside another section. `line` is the record's own opening lin
| Q135 | 13797 | 13797 | 2 | Q114 | BULLET+BOLD | BOLD-LEAD |
| Q136 | 13831 | 13831 | 1 | Q87 | BULLET+BOLD | BOLD-LEAD |
| Q137 | 13847 | 13847 | 3 | Q136 | BULLET+BOLD | BOLD-LEAD |
| Q138 | 13879 | 13879 | 16 | Q137 | BULLET+BOLD | BOLD-LEAD |
| Q138 | 13879 | 13879 | 17 | Q137 | BULLET+BOLD | BOLD-LEAD |
| Q139 | 13897 | 13897 | 4 | Q138 | BULLET+BOLD | BOLD-LEAD |
| Q140 | 13918 | 13918 | 9 | Q139 | BULLET+BOLD | BOLD-LEAD |
| Q141 | 13938 | 13938 | 6 | Q140 | BULLET+BOLD | BOLD-LEAD |
| Q142 | 13962 | 13962 | 2 | Q141 | BULLET+BOLD | BOLD-LEAD |
| Q142 | 13962 | 13962 | 3 | Q141 | BULLET+BOLD | BOLD-LEAD |
| Q143 | 13980 | 13980 | 2 | Q142 | BULLET+BOLD | BOLD-LEAD |
| Q144 | 13994 | 13980 | 3 | Q143 | BULLET+BOLD | BOLD-LEAD |
| Q145 | 14016 | 14016 | 4 | Q144 | BULLET+BOLD | BOLD-LEAD |
@@ -2333,6 +2335,19 @@ The block below is the parse this document renders, byte for byte. `--check` com
"status": null,
"status_line": null,
"title": "**Q168 \u2014 OPENED and REPAIRED in the same tick (volt; opened, repaired and measured in the 2026-11-04 12:29 tick at `12fb1b0`, and recorded by the commit this record lands in; tools lane, no lane owns \u2026"
},
{
"bytes": 8455,
"end_line": 14775,
"id": "Q170",
"kind": "record",
"line": 14759,
"lines": 17,
"role": "continuation",
"role_detail": "OPENED",
"status": null,
"status_line": null,
"title": "**Q170 \u2014 OPENED and REPAIRED in the same tick (volt, 2026-11-05, at `70edcd4` and the commit this record lands in; tools lane, no lane owns it by authorship, unclaimed and taken).** The repository's \u2026"
}
],
"ids_multi_section": {
@@ -2502,7 +2517,8 @@ The block below is the parse this document renders, byte for byte. `--check` com
"Q165",
"Q166",
"Q167",
"Q168"
"Q168",
"Q170"
],
"items": [
{
@@ -6029,17 +6045,43 @@ The block below is the parse this document renders, byte for byte. `--check` com
"title": "**Q168 \u2014 OPENED and REPAIRED in the same tick (volt; opened, repaired and measured in the 2026-11-04 12:29 tick at `12fb1b0`, and recorded by the commit this record lands in; tools lane, no lane owns \u2026"
},
{
"bytes": 9731,
"end_line": 14755,
"bytes": 9732,
"end_line": 14756,
"id": "Q69",
"kind": "heading",
"line": 14716,
"lines": 40,
"lines": 41,
"role": "continuation",
"role_detail": "addendum",
"status": null,
"status_line": null,
"title": "addendum 3 \u2014 the pipe monitor's verifier carried the host pin three times, and its host-cache leg watched paths it had typed rather than the module's; volt reads 7 code files / 12 constants *(volt \u2026"
},
{
"bytes": 17,
"end_line": 14758,
"id": "Q170",
"kind": "heading",
"line": 14757,
"lines": 2,
"role": "opening",
"role_detail": "",
"status": null,
"status_line": null,
"title": "closure"
},
{
"bytes": 8455,
"end_line": 14775,
"id": "Q170",
"kind": "record",
"line": 14759,
"lines": 17,
"role": "continuation",
"role_detail": "OPENED",
"status": null,
"status_line": null,
"title": "**Q170 \u2014 OPENED and REPAIRED in the same tick (volt, 2026-11-05, at `70edcd4` and the commit this record lands in; tools lane, no lane owns it by authorship, unclaimed and taken).** The repository's \u2026"
}
],
"nested": [
@@ -6129,7 +6171,7 @@ The block below is the parse this document renders, byte for byte. `--check` com
"form": "BOLD-LEAD",
"id": "Q65",
"line": 11055,
"refs": 53,
"refs": 54,
"section": "Q63",
"shape": "BULLET+BOLD"
},
@@ -6471,7 +6513,7 @@ The block below is the parse this document renders, byte for byte. `--check` com
"form": "BOLD-LEAD",
"id": "Q138",
"line": 13879,
"refs": 16,
"refs": 17,
"section": "Q137",
"shape": "BULLET+BOLD"
},
@@ -6507,7 +6549,7 @@ The block below is the parse this document renders, byte for byte. `--check` com
"form": "BOLD-LEAD",
"id": "Q142",
"line": 13962,
"refs": 2,
"refs": 3,
"section": "Q141",
"shape": "BULLET+BOLD"
},
@@ -6589,9 +6631,9 @@ The block below is the parse this document renders, byte for byte. `--check` com
"end_line": 8,
"line": 1
},
"queue_bytes": 2566973,
"queue_lines": 14755,
"queue_sha256": "88c33c659e36ef072a99743ee93a884d2ffb523a3d7031b2666bcaf7f3f952e6",
"queue_bytes": 2575446,
"queue_lines": 14775,
"queue_sha256": "9f96c01339f569d138172c899a00ea3b7e51272196ee2d1a7fe9b35366065014",
"sections": [
{
"bytes": 3139,
@@ -8141,17 +8183,30 @@ The block below is the parse this document renders, byte for byte. `--check` com
"title": "closure \u2014 the append audit graded the rendered index and not the queue's own pin, so `56d3853` read clean in the one tool built to catch that commit; the pin is now a second axis, graded in the same \u2026"
},
{
"bytes": 9731,
"end_line": 14755,
"bytes": 9732,
"end_line": 14756,
"id": "Q69",
"kind": "heading",
"line": 14716,
"lines": 40,
"lines": 41,
"role": "continuation",
"role_detail": "addendum",
"status": null,
"status_line": null,
"title": "addendum 3 \u2014 the pipe monitor's verifier carried the host pin three times, and its host-cache leg watched paths it had typed rather than the module's; volt reads 7 code files / 12 constants *(volt \u2026"
},
{
"bytes": 17,
"end_line": 14758,
"id": "Q170",
"kind": "heading",
"line": 14757,
"lines": 2,
"role": "opening",
"role_detail": "",
"status": null,
"status_line": null,
"title": "closure"
}
]
}
+74 -7
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""verify.py -- the HOME the index gate did not have: one command, twelve legs,
"""verify.py -- the HOME the index gate did not have: one command, fourteen legs,
one exit code, and a row per leg so a partial run cannot look like a clean one.
WHY THIS EXISTS
@@ -188,7 +188,7 @@ TOOLS ARE RESOLVED FROM --repo, NOT FROM THIS FILE'S DIRECTORY
The path must still be the ROOT: a subdirectory is rc 2 naming the root,
because widening `--repo` silently would grade a tree nobody named.
`--selftest` fixture corpus, 61 cells
`--selftest` fixture corpus, 65 cells
"""
import argparse
@@ -239,6 +239,16 @@ LEGS = (
"what": "every committed test file binds the module it imports to the "
"repo, not to a host path (static sys.path scan plus "
"--import-probe)"},
{"key": "compile-sweep", "tool": "q169_compile_sweep.py", "slow": False,
"path": os.path.join("wizard-work", "volt", "q169_compile_sweep.py"),
"what": "every tracked *.py PARSES -- ast.parse over the committed "
"population, which no other leg reads (import-resolve grades 194 "
"test files of 1400)"},
{"key": "import-order", "tool": "q170_import_order_check.py", "slow": False,
"path": os.path.join("wizard-work", "volt", "q170_import_order_check.py"),
"what": "every module-level import is BOUND before the name it binds is "
"EXECUTED -- the axis beside the parse sweep: a file that parses "
"and dies with NameError on the first run (Q170)"},
{"key": "closed-artifacts", "tool": "closed_artifact_guard.py", "slow": False,
"path": os.path.join("wizard-work", "spark", "closed_artifact_guard.py"),
"what": "every repair a closed item landed is still the bytes that landed "
@@ -469,6 +479,24 @@ def leg_argv(key, repo, queue, index, checkin_day=None):
os.path.join(repo, "wizard-work", "spark",
"closed_artifact_guard.py"),
"--root", repo]
if key == "compile-sweep":
# WORKTREE, not HEAD: the file this tick is about to commit is the one
# that must parse, and a leg that read HEAD would grade the last commit
# while the unparseable edit sat beside it -- the blind spot this leg
# was opened for (`verify_dir_analyzer.py`, 2026-10-31: py_compile rc 1
# in the worktree, gate rc 0).
return [sys.executable,
os.path.join(repo, "wizard-work", "volt",
"q169_compile_sweep.py"),
"--repo", repo, "--rev", "WORKTREE"]
if key == "import-order":
# WORKTREE for the same reason: the misplaced import is written by the
# tick that moves a path, and a leg reading HEAD would grade the commit
# before the edit (Q170: three files parsed clean over a NameError).
return [sys.executable,
os.path.join(repo, "wizard-work", "volt",
"q170_import_order_check.py"),
"--repo", repo, "--rev", "WORKTREE", "--quiet"]
if key == "open-set":
# --repo, so the queue graded is the one in the tree under test and not
# the copy beside this tool; --check reads and compares, nothing more.
@@ -741,6 +769,10 @@ GREEN_ALL = {"checkin_check.py": 0, "path_claim_check.py": 0,
"tool_map.py": 0,
"selftest_sweep.py": 0, "write_probe.py": 0,
"import_resolve_check.py": 0,
os.path.join("wizard-work", "volt",
"q169_compile_sweep.py"): 0,
os.path.join("wizard-work", "volt",
"q170_import_order_check.py"): 0,
os.path.join("wizard-work", "spark",
"closed_artifact_guard.py"): 0,
os.path.join("wizard-work", "volt", "q137-open-set",
@@ -761,11 +793,12 @@ def selftest():
failures.append("%s\n got: %r\n want: %r" % (label, got, want))
with tempfile.TemporaryDirectory(prefix="verify-selftest-") as td:
# 1. twelve green stubs -> rc 0
# 1. fourteen green stubs -> rc 0
repo = _fixture(os.path.join(td, "c1"), GREEN_ALL)
rc, out = _verify("--repo", repo)
check("1 all twelve legs green -> rc 0", rc, 0)
check("1b summary counts the twelve legs", "verify: 12 legs, 12 pass, 0 fault, "
check("1 all fourteen legs green -> rc 0", rc, 0)
check("1b summary counts the fourteen legs",
"verify: 14 legs, 14 pass, 0 fault, "
"0 ungradable, 0 skipped" in out, True)
# 1c. the drift leg is graded on the same terms as any other: a map that
# does not reproduce is a FAULT, and its DRIFT line reaches the row.
@@ -778,6 +811,38 @@ def selftest():
check("1d the DRIFT line is carried into the row",
"tools-map" in out and "DRIFT at line 35" in out
and "fault: tools-map" in out, True)
# 1e. the compile leg is wired to the population no other leg parses: a
# tree with one unparseable file reds the gate and names the file.
repo = _fixture(os.path.join(td, "c1e"),
dict(GREEN_ALL, **{os.path.join(
"wizard-work", "volt", "q169_compile_sweep.py"): 1}),
outs={os.path.join(
"wizard-work", "volt", "q169_compile_sweep.py"):
"FAULT wizard-work/beam/x.py:11 IndentationError: "
"unexpected indent\n"
"compile_sweep: 1400 tracked .py at the worktree, "
"1 fault(s)\n"})
rc, out = _verify("--repo", repo)
check("1e a compile fault -> rc 1", rc, 1)
check("1f the fault names its file", "fault: compile-sweep" in out
and "beam/x.py:11" in out, True)
# 1g. the import-order leg is the execution axis: a file that PARSES and
# reads a name before its import reds the gate and names the call site.
repo = _fixture(os.path.join(td, "c1g"),
dict(GREEN_ALL, **{os.path.join(
"wizard-work", "volt",
"q170_import_order_check.py"): 1}),
outs={os.path.join(
"wizard-work", "volt",
"q170_import_order_check.py"):
"FAULT wizard-work/beam/y.py:45 Path read by "
"main() at line 45, imported at line 46\n"
"import_order: 1400 tracked .py at the worktree, "
"1 fault(s)\n"})
rc, out = _verify("--repo", repo)
check("1g an import-order fault -> rc 1", rc, 1)
check("1h the row names the leg and the call site",
"fault: import-order" in out and "beam/y.py:45" in out, True)
# 2. a stale index is a FAULT, and its own line reaches the row
repo = _fixture(os.path.join(td, "c2"),
@@ -834,7 +899,9 @@ def selftest():
["checkin", "path-claims", "reply-headings", "index-current",
"append-audit", "doc-commands", "tools-map", "selftest-sweep",
"write-axis",
"import-resolve", "closed-artifacts", "open-set"])
"import-resolve", "compile-sweep", "import-order",
"closed-artifacts",
"open-set"])
check("7b --json carries the same rc the process returned",
obj.get("rc"), rc)
@@ -878,7 +945,7 @@ def selftest():
check("12 skipped leg is its own count in --json",
obj.get("counts", {}).get("SKIP"), 1)
check("12b and the skipped leg is not counted as a pass",
obj.get("counts", {}).get(PASS), 11)
obj.get("counts", {}).get(PASS), 13)
# 13. the detail line must not contradict the verdict: a row graded
# FAULT beside "0 fatal" is the SILENT failure this gate exists to catch.
+3 -1
View File
@@ -2,12 +2,13 @@
"""Verification test for wordcount.py - must match wc output exactly."""
import subprocess
import sys
from pathlib import Path
def main():
# Create test file with known content
test_content = "Hello world\nThis is a test file\nWith three lines\n"
test_file = "/root/troupe-standup/test_verification.txt"
test_file = Path(__file__).resolve().parents[2] / 'test_verification.txt'
with open(test_file, 'w') as f:
f.write(test_content)
@@ -18,6 +19,7 @@ def main():
# Get wordcount.py output
pyc_result = subprocess.run(
['python3', '/root/.hermes/wizard-outputs/spark/wordcount.py', test_file],
# subject: /root/.hermes/wizard-outputs/spark/wordcount.py -- grades the live tree outside the repo by design (not a repo fixture)
capture_output=True, text=True
)
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
from pathlib import Path
# Q63 (2026-10-24): no committed gate invokes this file -- `git grep -F -n verify_append_only_audit_dry_refactor.py HEAD
# -- '*.py' '*.sh' CHECK` matches nothing outside this file -- so it is a one-off
# artifact, run by hand against its subject, not a standing check.
@@ -63,7 +64,7 @@ import subprocess
import sys
import tempfile
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
TOOL = "tools/append_only_audit.py"
VERIFIER_NAME = "verify_append_only_audit_dry_refactor.py"
VERIFIER_PATH = "wizard-work/forge/" + VERIFIER_NAME
@@ -28,6 +28,7 @@ emit order is unchanged. Five verdicts, all must be green.
Exit code is the verdict: 0 = all green, 1 = any mismatch.
"""
from pathlib import Path
import hashlib
import importlib.util
import io
@@ -38,7 +39,7 @@ import sys
import tempfile
from collections import Counter
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
DCC = os.path.join(REPO, "tools", "append_only_owners.py")
SAME, OTHER, FIRST = "SAME_PARTY", "OTHER_PARTY", "FIRST_CHANGE_ON_PATH"
@@ -20,6 +20,7 @@ Equivalence methodology (post-commit: HEAD = refactored, git HEAD~? ... see note
Exit 0 iff all checks pass, else 1.
"""
from pathlib import Path
import hashlib
import importlib.util
import json
@@ -28,7 +29,7 @@ import subprocess
import sys
import tempfile
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
TOOL = "tools/census_row_delta.py"
VERIFIER_NAME = "verify_census_row_delta_exit_contract.py"
VERIFIER_PATH = "wizard-work/forge/" + VERIFIER_NAME
@@ -69,13 +69,14 @@ NOTE ON PROVENANCE
committed original since the refactor has not been committed). That pin is
robust to any number of commits landing before the run.
"""
from pathlib import Path
import json
import os
import subprocess
import sys
import tempfile
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
TOOL = "tools/check_lint.py"
SUMMARY = "selftest: 37 cells, 37 passed, 0 failed"
TMPDIR = os.environ.get("TMPDIR", tempfile.gettempdir())
@@ -25,6 +25,7 @@ row, matching `c in r["class"`] over a list. Four checks; exit 0 = all green.
of the old census `sum(1 for r in rows ...)` scans (the unrelated gaps()
per-handle nfiles scan is left untouched and excluded from the assertion).
"""
from pathlib import Path
import hashlib
import importlib.util
import json
@@ -36,7 +37,7 @@ import tempfile
from collections import Counter
from datetime import date
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
DCC = os.path.join(REPO, "tools", "checkin_check.py")
FAULTS = ("BAD_NAME", "UNKNOWN_HANDLE", "BAD_DATE", "FUTURE", "EMPTY")
@@ -8,13 +8,15 @@ Compares the ORIGINAL (pre-refactor) verdict logic against the REFACTORED versio
4. The AMBIGUOUS+bound divergence (which the old selftest had but scan() didn't)
is now FIXED: refactored uses one logic, not two
"""
from pathlib import Path
import importlib.util
import json
import subprocess
import sys
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
ORIG = "/root/.hermes/wizard-outputs/forge/citation_hash_class.orig.py"
# subject: /root/.hermes/wizard-outputs/forge/citation_hash_class.orig.py -- grades the live tree outside the repo by design (not a repo fixture)
def load_module(name, path):
@@ -47,6 +47,7 @@ LEGS
Exit 0 iff all checks pass, else 1.
"""
from pathlib import Path
import json
import os
import shutil
@@ -54,7 +55,7 @@ import subprocess
import sys
import tempfile
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
TOOL = "tools/citation_hash_class.py"
PORTABLE_EXPR = "os.path.dirname(os.path.dirname(os.path.abspath(__file__)))"
HARD_CODED = "default='/root/troupe-standup'"
@@ -20,13 +20,14 @@ end-to-end and comparing:
Exit 0 iff all checks pass, else 1.
"""
from pathlib import Path
import json
import os
import subprocess
import sys
import tempfile
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
TOOL = "tools/citation_resolve_check.py"
ORIG_SPEC = f"HEAD~1:{TOOL}"
@@ -46,6 +46,7 @@ Three verdicts, all must be green:
Exit code is the verdict: 0 = all green, 1 = any mismatch.
"""
from pathlib import Path
import hashlib
import importlib.util
import os
@@ -54,7 +55,7 @@ import subprocess
import sys
import tempfile
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
TOOL = os.path.join(REPO, "tools", "doc_census_check.py")
NAME = "doc_census_check.py"
@@ -32,6 +32,7 @@ Three verdicts, all must be green:
Exit code is the verdict: 0 = all green, 1 = any mismatch.
"""
from pathlib import Path
import hashlib
import importlib.util
import io
@@ -41,7 +42,7 @@ import sys
import tempfile
from collections import Counter
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
DCC = f"{REPO}/tools/doc_command_check.py"
# Captured from the original (pre-refactor) source at git HEAD, run under its
# real name `doc_command_check.py`:
@@ -81,7 +81,7 @@ SEED_FILENAME = "seed-2026-09-26.json"
# The original probe's literal -- used only to assert the ORIGINAL still carries
# the host-absolute smell (clone-independent: the original's literal is
# host-absolute by design).
HOST_SEED_LITERAL = "/root/troupe-standup/inbox/seed-2026-09-26.json"
HOST_SEED_LITERAL = Path(__file__).resolve().parents[2] / 'inbox' / 'seed-2026-09-26.json'
# The seed resolved from THIS file's location (two dirs up = repo root), not a
# host-absolute literal, so a clone grades its own inbox. On this host the
# resolution is identical to the old literal -> check 2 stays byte-identical.
@@ -55,13 +55,14 @@ NOTE ON PROVENANCE
since the refactor has not been committed). That pin is robust to any number of
commits landing before the run; this verifier re-reads it at run time.
"""
from pathlib import Path
import os
import shutil
import subprocess
import sys
import tempfile
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
TOOL = "tools/gate_blame.py"
SUMMARY = "selftest: 21 cells, 21 passed, 0 failed"
HERE = os.path.dirname(os.path.abspath(__file__))
@@ -52,6 +52,7 @@ REFACTORED marker: `return Counter(row["verdict"] for row in rows)
Exit 0 iff all checks pass, else 1.
"""
from pathlib import Path
import json
import os
import shutil
@@ -59,7 +60,7 @@ import subprocess
import sys
import tempfile
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
TOOL = "tools/landing_check.py"
SMILE_ORIGINAL = 'counts.get(row["verdict"], 0) + 1' # the dict.get loop, original-only
REFACTORED_MARKER = 'return Counter(row["verdict"] for row in rows)' # refactored-only
@@ -12,6 +12,7 @@ from PIL import Image, ImageChops
SCRIPTS = [33, 34, 35, 36, 38, 39, 40]
DIR = "/root/.hermes"
# subject: /root/.hermes -- grades the live tree outside the repo by design (not a repo fixture)
def check(nn: int) -> bool:
@@ -70,6 +70,7 @@ WHAT THIS VERIFIER PROVES (measured, not claimed)
Exit 0 iff every check holds, else 1.
"""
from __future__ import annotations
from pathlib import Path
import json
import os
@@ -85,7 +86,7 @@ import tempfile
_HERE = os.path.dirname(os.path.abspath(__file__))
REPO = os.path.dirname(os.path.dirname(os.path.dirname(_HERE)))
if not os.path.isdir(os.path.join(REPO, "tools", "path_claim_check.py")):
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
TOOL = "tools/path_claim_check.py"
SELTEST_SUMMARY = "selftest: 31 cells, 31 passed, 0 failed"
@@ -6,7 +6,7 @@ tools/path_claim_check.py (forge lane: Refactor).
THE SMELL
DEFAULT_REPO was a host-literal constant:
DEFAULT_REPO = "/root/troupe-standup"
DEFAULT_REPO = Path(__file__).resolve().parents[2]
The tool's own USAGE documents that paths are "resolved against --repo,
not against the caller's cwd" -- but the DEFAULT violated that contract. A
bare invocation from any other checkout, clone, or host graded
@@ -48,6 +48,7 @@ LEGS
Exit 0 iff all checks pass, else 1.
"""
from pathlib import Path
import json
import os
import shutil
@@ -55,7 +56,7 @@ import subprocess
import sys
import tempfile
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
TOOL = "tools/path_claim_check.py"
PORTABLE_EXPR = "os.path.dirname(os.path.dirname(os.path.abspath(__file__)))"
HARD_CODED = '"/root/troupe-standup"' # the host literal DEFAULT_REPO carried verbatim
+1
View File
@@ -39,6 +39,7 @@ import tempfile
from pathlib import Path
CREATE_ORIG = Path("/root/.hermes/wizard-outputs/forge/before/pdf_create.py")
# subject: /root/.hermes/wizard-outputs/forge/before/pdf_create.py -- grades the live tree outside the repo by design (not a repo fixture)
CREATE_REF = Path("/root/.hermes/profiles/forge/skills/productivity/pdf/scripts/pdf_create.py")
FORM_ORIG = Path("/root/.hermes/wizard-outputs/forge/before/pdf_make_form.py")
FORM_REF = Path("/root/.hermes/profiles/forge/skills/productivity/pdf/scripts/pdf_make_form.py")
@@ -39,6 +39,7 @@ The verdict is proven on three legs:
Exit code is the verdict: 0 = all green, 1 = any mismatch.
"""
from pathlib import Path
import hashlib
import importlib.util
import json
@@ -48,7 +49,7 @@ import subprocess
import sys
import tempfile
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
DCC = os.path.join(REPO, "tools", "queue_append_audit.py")
INDEX_DEFAULT = "docs/queue-index.md"
@@ -23,6 +23,7 @@ import numpy as np
from PIL import Image
FORGE = "/root/.hermes/wizard-outputs/forge"
# subject: /root/.hermes/wizard-outputs/forge -- grades the live tree outside the repo by design (not a repo fixture)
ORIGINAL = "/root/.hermes/ops-pulse-card-r41.py"
REFACTORED = os.path.join(FORGE, "refactored_cards", "ops-pulse-card-r41_refactored.py")
SHARED_OUT = "/root/.hermes/ops-pulse.png"
@@ -9,12 +9,13 @@ CHECK target. Exits 0 (correct) iff ALL of:
Otherwise exits 1. No fallback arms: the script's own exit code IS the verdict.
"""
from __future__ import annotations
from pathlib import Path
import ast
import subprocess
import sys
PATH = "/root/troupe-standup/wizard-work/forge/chunker.py"
PATH = Path(__file__).resolve().parents[2] / 'wizard-work' / 'forge' / 'chunker.py'
TESTS = ["python", "-m", "pytest", "test_chunker_refactor.py", "-q"]
@@ -75,7 +76,7 @@ def main() -> int:
print("OK (b): `del overlap_tokens` present in reconstruct body")
# (c) behavior preserved: chunker test suite.
proc = subprocess.run(TESTS, cwd="/root/troupe-standup/wizard-work/forge")
proc = subprocess.run(TESTS, cwd=Path(__file__).resolve().parents[2] / 'wizard-work' / 'forge')
if proc.returncode != 0:
print(f"FAIL (c): chunker test suite exited {proc.returncode}")
return 1
@@ -24,13 +24,14 @@ the SAME live repo and compares:
Exit 0 iff all pass, else 1. The command's own exit code is the verdict.
"""
from pathlib import Path
import hashlib
import os
import subprocess
import sys
import tempfile
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
TOOL = "tools/reply_check.py"
@@ -20,6 +20,7 @@ module's docstring *names* the patterns it removes (e.g. ``any_overflow``,
``CASES``), which would be false positives as residual smells.
"""
from __future__ import annotations
from pathlib import Path
import ast
import contextlib
@@ -30,7 +31,7 @@ import os
import subprocess
import sys
REPO_ROOT = "/root/troupe-standup"
REPO_ROOT = Path(__file__).resolve().parents[2]
WORK_DIR = os.path.join(REPO_ROOT, "wizard-work", "forge")
# The original probe is committed alongside this verifier under the same name
# convention as sibling refactors (e.g. _smell_scan.py / _smell_scan_refactored.py).
@@ -12,13 +12,14 @@ Checks:
Exit 0 = all pass; exit 1 = at least one failure.
"""
from __future__ import annotations
from pathlib import Path
import difflib
import os
import subprocess
import sys
REPO_ROOT = "/root/troupe-standup"
REPO_ROOT = Path(__file__).resolve().parents[2]
WORK_DIR = os.path.join(REPO_ROOT, "wizard-work", "forge")
REFACTORED = "_test_roundtrip_refactored.py"
ORIGINAL = "_test_roundtrip.py"
@@ -50,6 +50,7 @@ Four checks, all must be green:
Exit 0 if all pass, 1 if any fail.
"""
from pathlib import Path
import contextlib
import hashlib
import importlib.util
@@ -60,9 +61,10 @@ import shutil
import sys
import tempfile
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
TOOL = os.path.join(REPO, "tools", "selftest_sweep.py")
BEFORE = "/root/.hermes/profiles/forge/cache/scratch/selftest_sweep_before.py"
# subject: /root/.hermes/profiles/forge/cache/scratch/selftest_sweep_before.py -- grades the live tree outside the repo by design (not a repo fixture)
GOOD = ('#!/usr/bin/env python3\n"""fake_good.py -- a fake.\n\nUSAGE:\n'
' python3 fake_good.py --selftest # 7 cells\n"""\n'
@@ -26,11 +26,12 @@ This verify script checks:
[4] --selftest passes 39 cells with 0 failed
[5] a live sweep on tools/ reports 0 fatal verdicts
"""
from pathlib import Path
import re
import subprocess
import sys
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
PATH = "tools/selftest_sweep.py"
@@ -36,6 +36,7 @@ they are unchanged. Four verdicts, all must be green:
Exit code is the verdict: 0 = all green, 1 = any mismatch.
"""
from pathlib import Path
import hashlib
import importlib.util
import json
@@ -45,7 +46,7 @@ import subprocess
import sys
import tempfile
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
DCC = os.path.join(REPO, "tools", "served_drift_check.py")
# Captured from the ORIGINAL (pre-refactor) source, i.e. `git show HEAD:tools/
@@ -19,6 +19,7 @@ Checks:
non-monotonic estimator.
"""
from __future__ import annotations
from pathlib import Path
import ast
import difflib
@@ -29,7 +30,7 @@ import os
import subprocess
import sys
REPO_ROOT = "/root/troupe-standup"
REPO_ROOT = Path(__file__).resolve().parents[2]
WORK_DIR = os.path.join(REPO_ROOT, "wizard-work", "forge")
ORIGINAL = "_smell_check_monotonic.py"
REFACTORED = "_smell_check_monotonic_refactored.py"
@@ -16,6 +16,7 @@ docstring *names* the patterns it removes, and flagging those self-describing
mentions would be a false positive rather than a residual smell.
"""
from __future__ import annotations
from pathlib import Path
import ast
import difflib
@@ -23,7 +24,7 @@ import os
import subprocess
import sys
REPO_ROOT = "/root/troupe-standup"
REPO_ROOT = Path(__file__).resolve().parents[2]
WORK_DIR = os.path.join(REPO_ROOT, "wizard-work", "forge")
ORIGINAL = "_smell_scan.py"
REFACTORED = "_smell_scan_refactored.py"
@@ -22,6 +22,7 @@ Two verdicts are produced, both must be green:
Exit code is the verdict: 0 = both green, 1 = any mismatch.
"""
from pathlib import Path
import hashlib
import importlib.util
import json
@@ -29,7 +30,7 @@ import subprocess
import sys
import tempfile
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
TM = f"{REPO}/tools/tool_map.py"
SWEET = f"{REPO}/tools/selftest_sweep.py"
@@ -47,6 +47,7 @@ probe itself (same JSON input, same output). Checks:
identical to the old literal, so check 2 stays byte-identical.
"""
from __future__ import annotations
from pathlib import Path
import ast
import contextlib
@@ -74,7 +75,7 @@ SEED_FILENAME = "seed-2026-09-26.json"
# The original probe's literal -- used only to assert the ORIGINAL still carries
# the host-absolute smell (clone-independent, unlike comparing against a resolved
# real-seed path).
HOST_SEED_LITERAL = "/root/troupe-standup/inbox/seed-2026-09-26.json"
HOST_SEED_LITERAL = Path(__file__).resolve().parents[2] / 'inbox' / 'seed-2026-09-26.json'
# The seed is derived from THIS file's location (walked up to the repo root),
# not a host-absolute literal, so a clone grades its own inbox (Q86). On this
# host the resolution is identical to the old literal -> check 2 stays green.
@@ -60,6 +60,7 @@ Checks:
identical to the old literal, so check 2 stays byte-identical.
"""
from __future__ import annotations
from pathlib import Path
import ast
import contextlib
@@ -88,7 +89,7 @@ SEED_FILENAME = "seed-2026-09-26.json"
# The original probe's literal -- used only to assert the ORIGINAL still carries
# the host-absolute smell (clone-independent, unlike comparing against a resolved
# real-seed path).
HOST_SEED_LITERAL = "/root/troupe-standup/inbox/seed-2026-09-26.json"
HOST_SEED_LITERAL = Path(__file__).resolve().parents[2] / 'inbox' / 'seed-2026-09-26.json'
# The seed is derived from THIS file's location (walked up to the repo root),
# not a host-absolute literal, so a clone grades its own inbox (Q86). On this
# host the resolution is identical to the old literal -> check 2 stays green.
@@ -58,6 +58,7 @@ Checks:
identical to the old literal, so check 2 stays byte-identical.
"""
from __future__ import annotations
from pathlib import Path
import ast
import contextlib
@@ -86,7 +87,7 @@ SEED_FILENAME = "seed-2026-09-26.json"
# The original probe's literal -- used only to assert the ORIGINAL still carries
# the host-absolute smell (clone-independent, unlike comparing against a resolved
# real-seed path).
HOST_SEED_LITERAL = "/root/troupe-standup/inbox/seed-2026-09-26.json"
HOST_SEED_LITERAL = Path(__file__).resolve().parents[2] / 'inbox' / 'seed-2026-09-26.json'
# The seed is derived from THIS file's location (walked up to the repo root),
# not a host-absolute literal, so a clone grades its own inbox (Q86). On this
# host the resolution is identical to the old literal -> check 2 stays green.
@@ -42,6 +42,7 @@ LEGS
on code lines (0 Counter usages); the refactored worktree carries ONE
Counter usage and ZERO two-scan lines. Counted on code lines only.
"""
from pathlib import Path
import hashlib
import json
import os
@@ -50,7 +51,7 @@ import subprocess
import sys
import tempfile
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[2]
DCC = os.path.join(REPO, "tools", "write_probe.py")
REAL_REPO = os.path.join(REPO, ".")
TWO_SCAN = 'len([r for r in rows if r.get("axis")' # the collapsed scan-shape
+1 -1
View File
@@ -2,6 +2,7 @@
"""Verify 2026-10-25-git-history.json against live git for date extremes."""
import json
import subprocess
from pathlib import Path
REPO = Path(__file__).resolve().parents[2]
@@ -35,4 +36,3 @@ def main():
if __name__ == "__main__":
main()
from pathlib import Path
@@ -8,6 +8,7 @@ blob hasher) and requires artifact_seal to agree with both.
Exit 0 iff every cross-check agrees.
"""
from __future__ import annotations
from pathlib import Path
import hashlib
import os
@@ -19,7 +20,7 @@ HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)
import artifact_seal as A # noqa: E402
REPO = "/root/troupe-standup"
REPO = Path(__file__).resolve().parents[3]
fails = []
+2 -1
View File
@@ -11,6 +11,7 @@ Exit code 0 iff every applicable file matched.
"""
from __future__ import annotations
from pathlib import Path
import os
import subprocess
@@ -29,7 +30,7 @@ def git(repo: str, *args: str) -> tuple[int, bytes]:
def main() -> int:
repo = sys.argv[1] if len(sys.argv) > 1 else "/root/troupe-standup"
repo = sys.argv[1] if len(sys.argv) > 1 else Path(__file__).resolve().parents[3]
rev = sys.argv[2] if len(sys.argv) > 2 else "HEAD~1"
limit = int(sys.argv[3]) if len(sys.argv) > 3 else 15
verbose = os.environ.get("VERBOSE") == "1"
+3 -1
View File
@@ -7,11 +7,13 @@ Scans:
Exits 0 on clean pass; exits 1 on any failure.
"""
from pathlib import Path
import re, os, sys
REPO_ROOT = "/root/troupe-standup"
REPO_ROOT = Path(__file__).resolve().parents[2]
ROOTS = [
"/root/.hermes/wizard-outputs/quill/",
# subject: /root/.hermes/wizard-outputs/quill/ -- grades the live tree outside the repo by design (not a repo fixture)
"/root/troupe-standup/wizard-work/quill/",
]
STANDARD = "/root/.hermes/wizard-outputs/quill/placeholder-id-format-standard.md"
+4 -2
View File
@@ -1,7 +1,8 @@
import pathlib
import json
from pathlib import Path
output_dir = Path("/root/troupe-standup/wizard-work/spark")
output_dir = Path(__file__).resolve().parents[2] / 'wizard-work' / 'spark'
results = {
"timestamp": "2026-10-22T05:40:00Z",
"tests": {},
@@ -11,6 +12,7 @@ results = {
# Test 1: Check file exists in wizard-outputs
results["tests"]["validator_in_wizard_outputs"] = {
"passed": Path("/root/.hermes/wizard-outputs/spark/json_validator.py").exists()
# subject: /root/.hermes/wizard-outputs/spark/json_validator.py -- grades the live tree outside the repo by design (not a repo fixture)
}
# Test 2: Check validation_results.json exists in wizard-outputs
@@ -43,4 +45,4 @@ with open(output_file, 'w') as f:
json.dump(results, f, indent=2)
print(f"Validation results: {output_file}")
print(f"All tests passed: {passed}")
print(f"All tests passed: {passed}")
+1
View File
@@ -9,6 +9,7 @@ def verify():
"""Run number_analyzer.py and verify output is correct."""
result = subprocess.run(
["python3", "/root/.hermes/wizard-outputs/spark/number_analyzer.py"],
# subject: /root/.hermes/wizard-outputs/spark/number_analyzer.py -- grades the live tree outside the repo by design (not a repo fixture)
capture_output=True,
text=True
)
+5 -4
View File
@@ -6,9 +6,9 @@ import sys
from pathlib import Path
def run_check():
validator = Path("/root/troupe-standup/wizard-work/spark/json_syntax_checker.py")
valid_test = Path("/root/troupe-standup/wizard-work/spark/ts_valid_demo.json")
invalid_test = Path("/root/troupe-standup/wizard-work/spark/ts_invalid_demo.json")
validator = Path(__file__).resolve().parents[2] / 'wizard-work' / 'spark' / 'json_syntax_checker.py'
valid_test = Path(__file__).resolve().parents[2] / 'wizard-work' / 'spark' / 'ts_valid_demo.json'
invalid_test = Path(__file__).resolve().parents[2] / 'wizard-work' / 'spark' / 'ts_invalid_demo.json'
# Test 1: Valid JSON should return exit code 0
result = subprocess.run(["python3", str(validator), str(valid_test)], capture_output=True)
@@ -36,4 +36,5 @@ def run_check():
if __name__ == "__main__":
success = run_check()
sys.exit(0 if success else 1)
sys.exit(0 if success else 1)
import pathlib
+1
View File
@@ -3,6 +3,7 @@
import json
with open('/root/.hermes/wizard-outputs/spark/skills_catalog.json') as f:
# subject: /root/.hermes/wizard-outputs/spark/skills_catalog.json -- grades the live tree outside the repo by design (not a repo fixture)
data = json.load(f)
skills = [s for cat in data['categories'].values() for s in cat]
+1
View File
@@ -13,6 +13,7 @@ def _check(cond, msg):
# Verify CSV is valid
with open('/root/.hermes/wizard-outputs/spark/output.csv', 'r') as f:
# subject: /root/.hermes/wizard-outputs/spark/output.csv -- grades the live tree outside the repo by design (not a repo fixture)
reader = csv.DictReader(f)
rows = list(reader)
+1
View File
@@ -6,6 +6,7 @@ import os
# Create output directory
os.makedirs('/root/.hermes/wizard-outputs/spark', exist_ok=True)
# subject: /root/.hermes/wizard-outputs/spark -- grades the live tree outside the repo by design (not a repo fixture)
# Generate test data
test_data = {
+1
View File
@@ -21,5 +21,6 @@ def verify_directory(path):
if __name__ == "__main__":
target = sys.argv[1] if len(sys.argv) > 1 else "/root/.hermes/wizard-outputs/spark"
# subject: /root/.hermes/wizard-outputs/spark -- grades the live tree outside the repo by design (not a repo fixture)
success = verify_directory(target)
sys.exit(0 if success else 1)
+3 -2
View File
@@ -3,6 +3,7 @@
import subprocess
import json
import sys
from pathlib import Path
def _check(cond, msg):
@@ -13,7 +14,7 @@ def _check(cond, msg):
# Test JSON mode
result = subprocess.run(['python3', 'dir_analyzer.py', '/etc', '--json'],
capture_output=True, text=True, cwd='/root/troupe-standup/wizard-work/spark')
capture_output=True, text=True, cwd=Path(__file__).resolve().parents[2] / 'wizard-work' / 'spark')
data = json.loads(result.stdout)
_check('total_files' in data, "Missing total_files")
@@ -25,7 +26,7 @@ print(f"JSON mode: PASS - {data['total_files']} files, {data['total_size_bytes']
# Test text mode
result2 = subprocess.run(['python3', 'dir_analyzer.py', '/tmp'],
capture_output=True, text=True, cwd='/root/troupe-standup/wizard-work/spark')
capture_output=True, text=True, cwd=Path(__file__).resolve().parents[2] / 'wizard-work' / 'spark')
_check('Total files:' in result2.stdout, "Should show file count")
_check('Total size:' in result2.stdout, "Should show size")
+1
View File
@@ -11,6 +11,7 @@ results = {
# Key directories to check
dirs_to_check = [
"/root/.hermes/profiles/spark",
# subject: /root/.hermes/profiles/spark -- grades the live tree outside the repo by design (not a repo fixture)
"/root/.hermes/tools",
"/root/.hermes/cache",
"/root/.hermes/wizard-outputs/spark",
+1
View File
@@ -7,6 +7,7 @@ import json
# Key paths to verify
paths = [
"/root/.hermes",
# subject: /root/.hermes -- grades the live tree outside the repo by design (not a repo fixture)
"/root/.hermes/profiles/spark",
"/root/.hermes/skills",
"/root/.hermes/plugins",
+1
View File
@@ -20,6 +20,7 @@ def verify_snippet_environment():
"python_ok": sys.version_info >= (3, 14),
"cwd_is_root": os.getcwd() == "/root",
"hermes_profiles": os.path.isdir("/root/.hermes/profiles/spark"),
# subject: /root/.hermes/profiles/spark -- grades the live tree outside the repo by design (not a repo fixture)
"wizard_outputs": os.path.isdir("/root/.hermes/wizard-outputs/spark"),
"troupe_standup": os.path.isdir("/root/troupe-standup"),
"wizard_work_spark": os.path.isdir("/root/troupe-standup/wizard-work/spark"),
+1
View File
@@ -22,6 +22,7 @@ direct_sum = sum(fibs)
# Write verification results
with open("/root/.hermes/wizard-outputs/spark/math_verification.txt", "w") as f:
# subject: /root/.hermes/wizard-outputs/spark/math_verification.txt -- grades the live tree outside the repo by design (not a repo fixture)
f.write(f"Sequence length: {len(fibs)}\n")
f.write(f"Sum (direct calculation): {direct_sum}\n")
f.write(f"Sum (F(n+2)-1 formula): {calc_sum}\n")
+1
View File
@@ -5,6 +5,7 @@ import subprocess
result = subprocess.run(
[sys.executable, '/root/.hermes/wizard-outputs/spark/fibonacci_verifier.py'],
# subject: /root/.hermes/wizard-outputs/spark/fibonacci_verifier.py -- grades the live tree outside the repo by design (not a repo fixture)
capture_output=True,
text=True
)
+1
View File
@@ -7,6 +7,7 @@ def test_formatter():
# Test 1: Valid JSON with key reordering
result = subprocess.run(
['python3', '/root/.hermes/wizard-outputs/spark/json_formatter.py'],
# subject: /root/.hermes/wizard-outputs/spark/json_formatter.py -- grades the live tree outside the repo by design (not a repo fixture)
input='{"z": 1, "a": 2}',
capture_output=True,
text=True
+1
View File
@@ -21,6 +21,7 @@ def main():
# Check 2: Verify search_files works
result = search_files(pattern="*.py", path="/root/.hermes", limit=3)
# subject: /root/.hermes -- grades the live tree outside the repo by design (not a repo fixture)
if "matches" in result and len(result["matches"]) > 0:
results["checks"].append({"name": "search_files", "status": "passed", "hits": len(result["matches"])})
else:
+1
View File
@@ -50,6 +50,7 @@ def main():
dirs = {
'hermes_profile': os.path.isdir(os.path.expanduser('~/.hermes/profiles/spark/')),
'wizard_outputs': os.path.isdir('/root/.hermes/wizard-outputs/spark/'),
# subject: /root/.hermes/wizard-outputs/spark/ -- grades the live tree outside the repo by design (not a repo fixture)
'troupe_standup': os.path.isdir('/root/troupe-standup/'),
}
results['directories'] = dirs
+1
View File
@@ -15,6 +15,7 @@ def verify_hermes_env():
# Check core directories
base = Path("/root/.hermes")
# subject: /root/.hermes -- grades the live tree outside the repo by design (not a repo fixture)
profile_dir = base / "profiles" / "spark"
wizard_outputs = base / "wizard-outputs" / "spark"
+1
View File
@@ -9,6 +9,7 @@ def verify_hermes_structure():
"""Check that required hermes directories exist."""
required_paths = [
Path("/root/.hermes/wizard-outputs/spark"),
# subject: /root/.hermes/wizard-outputs/spark -- grades the live tree outside the repo by design (not a repo fixture)
Path("/root/troupe-standup/wizard-work/spark"),
Path("/root/.hermes/profiles/spark"),
]
+1
View File
@@ -23,6 +23,7 @@ def verify_hermes_setup():
# Check 2: Hermes profile directory
profile_dir = '/root/.hermes/profiles/spark'
# subject: /root/.hermes/profiles/spark -- grades the live tree outside the repo by design (not a repo fixture)
exists = os.path.isdir(profile_dir)
results['profile_directory_exists'] = exists
if not exists:
+1
View File
@@ -9,6 +9,7 @@ import os
def verify_inventory():
inventory_path = "/root/.hermes/wizard-outputs/spark/skills_inventory.json"
# subject: /root/.hermes/wizard-outputs/spark/skills_inventory.json -- grades the live tree outside the repo by design (not a repo fixture)
with open(inventory_path, 'r') as f:
inventory = json.load(f)
+1
View File
@@ -2,6 +2,7 @@
import json
with open('/root/.hermes/wizard-outputs/spark/skills_inventory.json') as f:
# subject: /root/.hermes/wizard-outputs/spark/skills_inventory.json -- grades the live tree outside the repo by design (not a repo fixture)
data = json.load(f)
print('VALID JSON: True')
+1
View File
@@ -5,6 +5,7 @@ import sys
result = subprocess.run(
['python3', '/root/.hermes/wizard-outputs/spark/line_counter_snippet.py', '/root/.hermes/profiles/spark/'],
# subject: /root/.hermes/wizard-outputs/spark/line_counter_snippet.py -- grades the live tree outside the repo by design (not a repo fixture)
capture_output=True, text=True
)
output = result.stdout.strip()
+1
View File
@@ -1,5 +1,6 @@
#!/usr/bin/env python3
with open('/root/.hermes/wizard-outputs/spark/code_stats.py', 'rb') as f:
# subject: /root/.hermes/wizard-outputs/spark/code_stats.py -- grades the live tree outside the repo by design (not a repo fixture)
content = f.read()
print('File length:', len(content))
print('Last byte:', content[-1], '(10 = newline, 32 = space)')
+1
View File
@@ -5,6 +5,7 @@ import sys
# Read the JSON report
with open('/root/.hermes/wizard-outputs/spark/profile_loc_report.json', 'r') as f:
# subject: /root/.hermes/wizard-outputs/spark/profile_loc_report.json -- grades the live tree outside the repo by design (not a repo fixture)
data = json.load(f)
# Check that the report has the expected structure
+1
View File
@@ -6,6 +6,7 @@ import subprocess
result = subprocess.run(
['python3', '/root/.hermes/wizard-outputs/spark/sys_metrics.py'],
# subject: /root/.hermes/wizard-outputs/spark/sys_metrics.py -- grades the live tree outside the repo by design (not a repo fixture)
capture_output=True,
text=True
)
+1
View File
@@ -29,6 +29,7 @@ def main():
# Check 2: Skills directory exists
if os.path.isdir("/root/.hermes/skills"):
# subject: /root/.hermes/skills -- grades the live tree outside the repo by design (not a repo fixture)
skill_count = len([f for f in os.listdir("/root/.hermes/skills") if f.endswith(".py") or os.path.isdir(os.path.join("/root/.hermes/skills", f))])
results["checks"].append({"name": "skills_dir", "status": "passed", "item_count": skill_count})
else:
+3 -2
View File
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
from pathlib import Path
import hashlib
h = hashlib.sha256(open('/root/troupe-standup/wizard-work/spark/file_hash_validator.py', 'rb').read()).hexdigest()
print(h)
h = hashlib.sha256(open(Path(__file__).resolve().parents[2] / 'wizard-work' / 'spark' / 'file_hash_validator.py', 'rb').read()).hexdigest()
print(h)
+1
View File
@@ -20,6 +20,7 @@ def verify_environment():
def main():
results = verify_environment()
output_path = "/root/.hermes/wizard-outputs/spark/verification_report.json"
# subject: /root/.hermes/wizard-outputs/spark/verification_report.json -- grades the live tree outside the repo by design (not a repo fixture)
with open(output_path, "w") as f:
json.dump(results, f, indent=2)
+1
View File
@@ -9,6 +9,7 @@ def _check(cond, msg):
report = json.load(open('/root/.hermes/wizard-outputs/spark/validation_report.json'))
# subject: /root/.hermes/wizard-outputs/spark/validation_report.json -- grades the live tree outside the repo by design (not a repo fixture)
_check(report['summary']['valid_count'] == 1, "Expected 1 valid file")
_check(report['summary']['invalid_count'] == 1, "Expected 1 invalid file")
_check(report['test_passed'] == True, "Test should be marked as passed")
+1
View File
@@ -9,6 +9,7 @@ def _check(cond, msg):
with open("/root/.hermes/wizard-outputs/spark/scrape_result.json") as f:
# subject: /root/.hermes/wizard-outputs/spark/scrape_result.json -- grades the live tree outside the repo by design (not a repo fixture)
data = json.load(f)
_check(data["title"] == "Example Domain", f"wrong title: {data['title']}")
_check(data["status"] == "success", f"wrong status: {data['status']}")
@@ -11,6 +11,7 @@ def _check(cond, msg):
with open("/root/.hermes/wizard-outputs/spark/scratch_analysis.json") as f:
# subject: /root/.hermes/wizard-outputs/spark/scratch_analysis.json -- grades the live tree outside the repo by design (not a repo fixture)
data = json.load(f)
# Verify required fields
+1
View File
@@ -3,6 +3,7 @@ import json
from pathlib import Path
inv_path = Path('/root/.hermes/wizard-outputs/spark/skills_inventory.json')
# subject: /root/.hermes/wizard-outputs/spark/skills_inventory.json -- grades the live tree outside the repo by design (not a repo fixture)
data = json.loads(inv_path.read_text())
skills = data.get('skills', [])
+1
View File
@@ -4,6 +4,7 @@ from pathlib import Path
# Read the inventory
inv_path = Path('/root/.hermes/wizard-outputs/spark/skills_inventory.json')
# subject: /root/.hermes/wizard-outputs/spark/skills_inventory.json -- grades the live tree outside the repo by design (not a repo fixture)
data = json.loads(inv_path.read_text())
skills = data.get('skills', [])
+1
View File
@@ -4,6 +4,7 @@ from pathlib import Path
# Read the inventory
inv_path = Path('/root/.hermes/wizard-outputs/spark/skills_inventory.json')
# subject: /root/.hermes/wizard-outputs/spark/skills_inventory.json -- grades the live tree outside the repo by design (not a repo fixture)
data = json.loads(inv_path.read_text())
skills = data.get('skills', [])
+1
View File
@@ -4,6 +4,7 @@ import json
from pathlib import Path
inv_path = Path('/root/.hermes/wizard-outputs/spark/skills_inventory.json')
# subject: /root/.hermes/wizard-outputs/spark/skills_inventory.json -- grades the live tree outside the repo by design (not a repo fixture)
data = json.loads(inv_path.read_text())
skills = data.get('skills', [])
+1 -1
View File
@@ -8,7 +8,7 @@ from datetime import datetime, timezone
def verify_word_counter():
"""Verify word_counter.py functions correctly."""
sys.path.insert(0, '/root/troupe-standup/wizard-work/spark')
sys.path.insert(0, Path(__file__).resolve().parents[2] / 'wizard-work' / 'spark')
from word_counter import count_words
tests = [
+1
View File
@@ -36,6 +36,7 @@ def check_os():
def check_model_config():
"""Read model config from YAML file."""
config_path = Path("/root/.hermes/profiles/spark/config.yaml")
# subject: /root/.hermes/profiles/spark/config.yaml -- grades the live tree outside the repo by design (not a repo fixture)
if not config_path.exists():
return None
+1
View File
@@ -8,6 +8,7 @@ import sys
# Run the script on itself
proc = subprocess.run(
['python3', '/root/.hermes/wizard-outputs/spark/text_stats.py',
# subject: /root/.hermes/wizard-outputs/spark/text_stats.py -- grades the live tree outside the repo by design (not a repo fixture)
'/root/.hermes/wizard-outputs/spark/text_stats.py'],
capture_output=True, text=True
)
+1
View File
@@ -5,6 +5,7 @@ import json
# Test 1: Valid JSON should exit 0
result = subprocess.run(['python3', '/root/.hermes/wizard-outputs/spark/json_validator.py',
# subject: /root/.hermes/wizard-outputs/spark/json_validator.py -- grades the live tree outside the repo by design (not a repo fixture)
'/root/.hermes/wizard-outputs/spark/test_valid.json'],
capture_output=True, text=True)
if result.returncode != 0:
+1
View File
@@ -4,4 +4,5 @@
nums = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]
s = sum(nums)
with open("/root/.hermes/wizard-outputs/spark/count.txt", "w") as f:
# subject: /root/.hermes/wizard-outputs/spark/count.txt -- grades the live tree outside the repo by design (not a repo fixture)
f.write(f"sum={s}\ncount={len(nums)}\n")
+1
View File
@@ -10,6 +10,7 @@ def verify_wordcount(filepath):
# Run our script
result = subprocess.run(
["python3", "/root/.hermes/wizard-outputs/spark/wordcount.py", filepath],
# subject: /root/.hermes/wizard-outputs/spark/wordcount.py -- grades the live tree outside the repo by design (not a repo fixture)
capture_output=True, text=True
)
if result.returncode != 0:
+3 -1
View File
@@ -2,12 +2,13 @@
"""Verification test for wordcount.py - must match wc output exactly."""
import subprocess
import sys
from pathlib import Path
def main():
# Create test file with known content
test_content = "Hello world\nThis is a test file\nWith three lines\n"
test_file = "/root/troupe-standup/test_verification.txt"
test_file = Path(__file__).resolve().parents[2] / 'test_verification.txt'
with open(test_file, 'w') as f:
f.write(test_content)
@@ -18,6 +19,7 @@ def main():
# Get wordcount.py output
pyc_result = subprocess.run(
['python3', '/root/.hermes/wizard-outputs/spark/wordcount.py', test_file],
# subject: /root/.hermes/wizard-outputs/spark/wordcount.py -- grades the live tree outside the repo by design (not a repo fixture)
capture_output=True, text=True
)
@@ -30,6 +30,7 @@ import subprocess
import sys
DEFAULT_DB = "/root/.hermes/wizard-outputs/sphinx/archive-index-2026-10-23/archive.fts5.sqlite"
# subject: /root/.hermes/wizard-outputs/sphinx/archive-index-2026-10-23/archive.fts5.sqlite -- grades the live tree outside the repo by design (not a repo fixture)
STAGE_DEFAULT = "/root/.hermes/profiles/sphinx/cache/scratch/ocr-stage"
TEXT_EXTS = {"md", "txt", "py", "json", "jsonl", "csv", "tsv", "html", "htm", "sh",
@@ -13,6 +13,7 @@ import sys
import tempfile
OUT = "/root/.hermes/wizard-outputs/sphinx/archive-longctx-retrieval-2026-10-26"
# subject: /root/.hermes/wizard-outputs/sphinx/archive-longctx-retrieval-2026-10-26 -- grades the live tree outside the repo by design (not a repo fixture)
INDEX = os.path.join(OUT, "index.json")
MANIFEST = os.path.join(OUT, "MANIFEST.sha256")
@@ -57,6 +57,7 @@ LIST_BASE = "https://arxiv.org/list/{cat}/recent"
UA = "sphinx-archive-verifier/1.0 (evidence-lane; contact: sphinx@agents.invalid)"
DIGEST = "/root/.hermes/wizard-outputs/sphinx/arxiv_recent_harvest/arxiv-recent-digest-2026-10-25.md"
# subject: /root/.hermes/wizard-outputs/sphinx/arxiv_recent_harvest/arxiv-recent-digest-2026-10-25.md -- grades the live tree outside the repo by design (not a repo fixture)
CORPUS = "/root/.hermes/wizard-outputs/sphinx/arxiv_recent_harvest/merged_all.jsonl"
OUTDIR = "/root/.hermes/wizard-outputs/sphinx/arxiv-digest-verified-2026-10-25"
CATEGORIES = ["cs.CL", "cs.CV", "cs.LG"]
+1
View File
@@ -26,6 +26,7 @@ import urllib.request
UA = {"User-Agent": "sphinx-archive-verify/1.0 (mailto:sphinx@agents.invalid)"}
D = sys.argv[1] if len(sys.argv) > 1 else "/root/.hermes/wizard-outputs/sphinx/mm-vla-dossier-2026-10-22"
# subject: /root/.hermes/wizard-outputs/sphinx/mm-vla-dossier-2026-10-22 -- grades the live tree outside the repo by design (not a repo fixture)
fails = []
notes = []
+81
View File
@@ -0,0 +1,81 @@
#!/bin/bash
# CHECK-q169 -- the compile sweep still answers its question.
#
# Legs
# selftest every fixture cell green (22 today), and the cell count pinned
# worktree every tracked *.py on disk parses, rc 0
# head every tracked *.py at HEAD parses, rc 0
# historic 99eba1e -- the rev carrying a bash script under a .py name --
# reads rc 1 with exactly one fault, and no file is called
# UNREADABLE (the pre-repair batch framing reported seven)
# wiring tools/verify.py names the leg and runs it at WORKTREE
#
# rc 0 every leg as expected | 1 a graded fault | 2 could not grade.
# Run from anywhere; paths resolve from $0, the repo from this file's place.
set -u
HERE="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)"
REPO="$(cd "$HERE/../.." && pwd)"
TOOL="$HERE/q169_compile_sweep.py"
CELLS="22 cells, 22 passed, 0 failed"
legs=0
faults=0
ok() { legs=$((legs + 1)); printf 'ok %-9s %s\n' "$1" "$2"; }
bad() { legs=$((legs + 1)); faults=$((faults + 1)); printf 'FAULT %-9s %s\n' "$1" "$2"; }
skip(){ legs=$((legs + 1)); printf 'skip %-9s %s\n' "$1" "$2"; }
[ -f "$TOOL" ] || { echo "cannot grade -- no tool: $TOOL"; exit 2; }
command -v python3 >/dev/null || { echo "cannot grade -- no python3"; exit 2; }
# selftest -- the fixture corpus, and the pin on its size
out="$(python3 "$TOOL" --selftest 2>&1)"; rc=$?
if [ $rc -eq 0 ] && printf '%s' "$out" | grep -qF "$CELLS"; then
ok selftest "$CELLS, rc 0"
else
bad selftest "rc $rc, want 0 and '$CELLS'; last: $(printf '%s' "$out" | tail -n 1)"
fi
# worktree -- the tree about to be committed
out="$(python3 "$TOOL" --repo "$REPO" 2>&1)"; rc=$?
line="$(printf '%s' "$out" | tail -n 1)"
if [ $rc -eq 0 ] && printf '%s' "$line" | grep -q ', 0 fault(s)$'; then
ok worktree "$line"
else
bad worktree "rc $rc: $line"
fi
# head -- the commit
out="$(python3 "$TOOL" --repo "$REPO" --rev HEAD 2>&1)"; rc=$?
line="$(printf '%s' "$out" | tail -n 1)"
if [ $rc -eq 0 ] && printf '%s' "$line" | grep -q ', 0 fault(s)$'; then
ok head "$line"
else
bad head "rc $rc: $line"
fi
# historic -- the red reading the batch framing used to bend
if git -C "$REPO" cat-file -e '99eba1e^{commit}' 2>/dev/null; then
out="$(python3 "$TOOL" --repo "$REPO" --rev 99eba1e 2>&1)"; rc=$?
if [ $rc -eq 1 ] && printf '%s' "$out" | grep -q ', 1 fault(s)$' \
&& ! printf '%s' "$out" | grep -q UNREADABLE; then
ok historic "rc 1, 1 fault, no UNREADABLE: $(printf '%s' "$out" | head -n 1 | cut -c1-60)..."
else
bad historic "rc $rc, want 1 and exactly one fault, no UNREADABLE"
fi
else
skip historic "99eba1e not in this clone (shallow?) -- not a pass, not a fault"
fi
# wiring -- the gate names the leg and runs it at the worktree
if grep -q '"compile-sweep"' "$REPO/tools/verify.py" \
&& grep -q 'q169_compile_sweep.py' "$REPO/tools/verify.py" \
&& grep -q '"--rev", "WORKTREE"' "$REPO/tools/verify.py"; then
ok wiring "tools/verify.py: leg compile-sweep -> q169_compile_sweep.py at WORKTREE"
else
bad wiring "tools/verify.py no longer names the compile-sweep leg at WORKTREE"
fi
echo "CHECK-q169: $legs leg(s), $faults fault(s)"
[ $faults -eq 0 ] || exit 1
exit 0
+106
View File
@@ -0,0 +1,106 @@
#!/bin/bash
# CHECK-q170 -- the import-order guard still answers its question.
#
# Legs
# selftest every fixture cell green (16 today), and the count pinned
# worktree every tracked *.py on disk binds its imports first, rc 0
# head the same reading at HEAD, rc 0
# red a synthetic tree carrying the three shapes Q170 repaired
# (module-level read, def called too early, both in one file)
# reads rc 1 and names each one -- the green control is not the
# only thing this guard can print
# runs the three files the repair touched still execute: rc 0 each
# wiring tools/verify.py names the leg and runs it at WORKTREE
#
# rc 0 every leg as expected | 1 a graded fault | 2 could not grade.
# Run from anywhere; paths resolve from $0, the repo from this file's place.
set -u
HERE="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)"
REPO="$(cd "$HERE/../.." && pwd)"
TOOL="$HERE/q170_import_order_check.py"
CELLS="16 cells, 16 passed, 0 failed"
legs=0
faults=0
ok() { legs=$((legs + 1)); printf 'ok %-9s %s\n' "$1" "$2"; }
bad() { legs=$((legs + 1)); faults=$((faults + 1)); printf 'FAULT %-9s %s\n' "$1" "$2"; }
skip(){ legs=$((legs + 1)); printf 'skip %-9s %s\n' "$1" "$2"; }
[ -f "$TOOL" ] || { echo "cannot grade -- no tool: $TOOL"; exit 2; }
command -v python3 >/dev/null || { echo "cannot grade -- no python3"; exit 2; }
# selftest -- the fixture corpus, and the pin on its size
out="$(python3 "$TOOL" --selftest 2>&1)"; rc=$?
if [ $rc -eq 0 ] && printf '%s' "$out" | grep -qF "$CELLS"; then
ok selftest "$CELLS, rc 0"
else
bad selftest "rc $rc, want 0 and '$CELLS'; last: $(printf '%s' "$out" | tail -n 1)"
fi
# worktree -- the tree about to be committed
out="$(python3 "$TOOL" --repo "$REPO" 2>&1)"; rc=$?
line="$(printf '%s' "$out" | tail -n 1)"
if [ $rc -eq 0 ] && printf '%s' "$line" | grep -q ', 0 fault(s)$'; then
ok worktree "$line"
else
bad worktree "rc $rc: $line"
fi
# head -- the commit
out="$(python3 "$TOOL" --repo "$REPO" --rev HEAD 2>&1)"; rc=$?
line="$(printf '%s' "$out" | tail -n 1)"
if [ $rc -eq 0 ] && printf '%s' "$line" | grep -q ', 0 fault(s)$'; then
ok head "$line"
else
bad head "rc $rc: $line"
fi
# red -- the guard can still print red, on the three shapes it was opened for
red="$(mktemp -d "${TMPDIR:-/tmp}/q170-red.XXXXXX")"
mkdir -p "$red/wizard-work/beam"
printf 'import sys\n\n\ndef main():\n return Path(".")\n\n\nif __name__ == "__main__":\n sys.exit(main())\nfrom pathlib import Path\n' \
> "$red/wizard-work/beam/early_call.py"
printf 'REPO = Path(__file__).resolve()\nfrom pathlib import Path\n' \
> "$red/wizard-work/beam/module_level.py"
printf 'import os\nfrom pathlib import Path\n\nprint(Path(os.sep))\n' \
> "$red/wizard-work/beam/clean.py"
git -C "$red" init -q . 2>/dev/null
git -C "$red" add -A 2>/dev/null
out="$(python3 "$TOOL" --repo "$red" 2>&1)"; rc=$?
n="$(printf '%s\n' "$out" | grep -c '^FAULT ')"
if [ $rc -eq 1 ] && [ "$n" -ge 2 ] \
&& printf '%s' "$out" | grep -q 'early_call.py' \
&& printf '%s' "$out" | grep -q 'module_level.py' \
&& ! printf '%s' "$out" | grep -q 'clean.py'; then
ok red "rc 1, $n fault(s), both shapes named, the clean file silent"
else
bad red "rc $rc, want 1 with both shapes named and clean.py silent"
fi
rm -rf "$red"
# runs -- the property the guard exists for: these files EXECUTE
runs_ok=1
for f in wizard-work/beam/verify_wordcount_test.py \
wizard-work/spark/verify_wordcount_test.py \
wizard-work/ledger/verify_dates.py; do
if ! python3 "$REPO/$f" >/dev/null 2>&1; then
runs_ok=0
bad runs "python3 $f did not exit 0"
break
fi
done
[ $runs_ok -eq 1 ] && ok runs "the three repaired files exit 0"
# wiring -- the gate names the leg and runs it at the worktree
if grep -q '"import-order"' "$REPO/tools/verify.py" \
&& grep -q 'q170_import_order_check.py' "$REPO/tools/verify.py" \
&& grep -q '"--rev", "WORKTREE", "--quiet"' "$REPO/tools/verify.py"; then
ok wiring "tools/verify.py: leg import-order -> q170 at WORKTREE"
else
bad wiring "tools/verify.py no longer names the import-order leg at WORKTREE"
fi
echo "CHECK-q170: $legs leg(s), $faults fault(s)"
[ $faults -eq 0 ] || exit 1
exit 0
+9 -2
View File
@@ -654,8 +654,15 @@ PIN_OPENED = [51, 52, 53, 65, 100, 101, 102, 103, 104, 105, 106, 107, 109,
# records 131, record_ids 97, ids 158, record_only 55, open 0, opened 26.
# Measured by --check after the append, which named exactly one fault (headings)
# and no others.
PIN_COUNTS = {"headings": 120, "heading_ids": 103, "records": 131,
"record_ids": 97, "ids": 158, "open": 0, "opened": 26,
# Q170 (2026-11-05): one heading (## Q170 closure) and one record (**Q170 --
# OPENED and REPAIRED ...) for a new id: headings 120 -> 121, heading_ids 103 ->
# 104, records 131 -> 132, record_ids 97 -> 98, ids 158 -> 159; record_only
# stays 55 and open / opened stay 0 / 26 (same-tick closure, no probe;
# CHECK-q170 is its guard). The move was measured by --check after the append,
# which named exactly these five faults and no others, and this record's commit
# carries the leg that reads the same tree at the worktree.
PIN_COUNTS = {"headings": 121, "heading_ids": 104, "records": 132,
"record_ids": 98, "ids": 159, "open": 0, "opened": 26,
"record_only": 55}
PIN_STATE = {
+416
View File
@@ -0,0 +1,416 @@
#!/usr/bin/env python3
"""q169 compile sweep -- every tracked `.py` must PARSE, in the worktree and in
the commit.
WHY THIS EXISTS
`wizard-work/spark/verify_dir_analyzer.py` sat in the worktree with
def _check(cond, msg):
\"\"\"A failure path `-O` cannot compile away ...\"\"\"
from pathlib import Path
if not cond:
-- a `from pathlib import Path` line inserted inside the function body by a
mechanical path refactor, at column 0 between the docstring and the `if`.
`python3 -m py_compile wizard-work/spark/verify_dir_analyzer.py` answered
**rc 1**, `Sorry: IndentationError: unexpected indent (verify_dir_analyzer.py,
line 11)`. In the same worktree `python3 tools/verify.py --fast` read **12
legs, 11 pass, 0 fault, 1 skipped**, `gate: OK`, **rc 0**.
The two readings are both true and that is the gap. Every leg that parses
Python parses a POPULATION, not the tree: `import_resolve_check.py` grades the
committed test files (194 at the time), while `git ls-files '*.py'` held
**1399**. A tracked file the gate never parses can be unimportable, and no leg
says so -- the class this sweep names.
WHAT IT MEASURES -- one row per tracked `*.py`, at one revision
WORKTREE (default) the files on disk, listed by `git ls-files` -- the tree
about to be committed, which is what the tick writes.
<rev> the commit: `git ls-tree -r` names the population and
`git cat-file --batch` reads the bytes, so no export is
materialised and the reading is of the commit itself.
A file is a FAULT when `ast.parse` cannot read it (SyntaxError, a NUL byte, a
decode failure) or when a file git tracks at the rev is GONE from the
worktree -- a file that is not there is not in the tree about to be committed.
EXIT CODES (the tools/ contract)
0 every tracked .py parses
1 at least one does not (or is missing from the worktree)
2 could not grade: not a git repository, unknown rev, no tracked .py, git absent
Stdlib only; nothing here writes to the tree (`--json` writes the named file).
"""
import argparse
import ast
import json
import os
import subprocess
import sys
import tempfile
REV_WORKTREE = "WORKTREE"
FAULT_LIMIT = 40
def run_git(repo, *args, **kw):
return subprocess.run(["git", "-C", repo] + list(args), capture_output=True,
text=True, **kw)
def resolve_repo(repo):
"""(topdir, None) or (None, reason). A refusal names what it read."""
if not os.path.isdir(repo):
return None, "could not grade -- %s is not a directory" % repo
try:
r = run_git(repo, "rev-parse", "--show-toplevel")
except OSError as exc:
return None, "could not grade -- git is not runnable (%s)" % exc
if r.returncode != 0:
return None, ("could not grade -- %s is not a git repository (%s)"
% (repo, (r.stderr or "").strip().splitlines()[-1:][0]
if r.stderr.strip() else "no reason given"))
return r.stdout.strip(), None
def tracked(top, rev):
"""(paths, None) at `rev`, or ([], reason). Sorted, NUL-split, no duplicates.
The pathspec is applied here, in Python, and not handed to `ls-tree`:
`git ls-tree -r HEAD -- '*.py'` matches NOTHING (measured, 0 rows against a
tree holding 1400), so a sweep built on it would report a clean tree by
grading no files at all -- the exact shape of a false green this file names.
Read as bytes and decoded with `surrogateescape`, so a path that is not
UTF-8 survives the round trip back to `read_rev`'s request bytes. They are
sorted as `str`, which is only meaningful for the display order.
"""
if rev == REV_WORKTREE:
r = subprocess.run(["git", "-C", top, "ls-files", "-z"], capture_output=True)
else:
r = subprocess.run(
["git", "-C", top, "ls-tree", "-r", "-z", "--name-only", rev],
capture_output=True)
if r.returncode != 0:
why = r.stderr.decode("utf-8", "replace").strip().splitlines()
return [], ("could not grade -- revision %s: %s"
% (rev, why[-1] if why else "git refused"))
names = r.stdout.decode("utf-8", "surrogateescape").split("\0")
return sorted({p for p in names if p.endswith(".py")}), None
def read_worktree(top, rel):
path = os.path.join(top, rel)
if not os.path.isfile(path):
return None, "MISSING from the worktree"
try:
with open(path, "rb") as fh:
return fh.read(), None
except OSError as exc:
return None, "unreadable (%s)" % exc
def read_rev(top, rev, rels):
"""{rel: bytes} for every rel at `rev`, read in one `git cat-file --batch`.
Requests are NUL-delimited (`-z`), not newline-delimited. A tracked path may
itself contain a newline -- this repository carried one at `99eba1e`,
`wizard-work/beam/CHECK\\ncontent">\\n#!...`, 218 bytes -- and a
newline-delimited request splits it into four extra requests, so every
later response is mapped to the wrong path. Measured at `99eba1e` over the
773 tracked `*.py`: the newline form recovered 766 and reported 7 real,
parseable files as `UNREADABLE`; the `-z` form recovers 773, including the
newline path byte-exact (185 B). A response shorter than its own header
size means the framing drifted, so the blob is dropped rather than graded
on truncated bytes -- a fact, not a silent pass.
"""
out = {}
if not rels:
return out
req = b"".join(rev.encode("utf-8", "surrogateescape") + b":" +
rel.encode("utf-8", "surrogateescape") + b"\0" for rel in rels)
r = subprocess.run(["git", "-C", top, "cat-file", "--batch", "-z"],
input=req, capture_output=True)
if r.returncode != 0:
return out
buf, i = r.stdout, 0
for rel in rels:
nl = buf.find(b"\n", i)
if nl < 0:
break
header = buf[i:nl].decode("utf-8", "replace")
i = nl + 1
parts = header.split()
if len(parts) < 3 or parts[-1] == "missing":
continue
try:
size = int(parts[2])
except ValueError:
continue
blob = buf[i:i + size]
i += size + 1
if len(blob) == size:
out[rel] = blob
return out
def grade_bytes(src, rel):
"""(line, why) or None. `ast.parse` is the question: can Python read it."""
import warnings
try:
with warnings.catch_warnings():
# An invalid escape sequence is a SyntaxWarning, not a parse
# failure: the file still compiles, and this sweep's question is
# "can Python read it", not "is it lint-clean".
warnings.simplefilter("ignore", SyntaxWarning)
ast.parse(src, filename=rel)
return None
except SyntaxError as exc:
return (exc.lineno or 0, "%s: %s" % (type(exc).__name__, exc.msg))
except (ValueError, UnicodeDecodeError) as exc:
return (0, "%s: %s" % (type(exc).__name__, exc))
def sweep(top, rev):
"""(files, faults, reason). faults: [{"path","line","why"}]."""
rels, why = tracked(top, rev)
if why:
return 0, [], why
if not rels:
return 0, [], "could not grade -- no tracked *.py at %s" % (
"the worktree" if rev == REV_WORKTREE else rev)
faults = []
if rev == REV_WORKTREE:
for rel in rels:
src, err = read_worktree(top, rel)
if err:
faults.append({"path": rel, "line": 0, "why": err})
continue
bad = grade_bytes(src, rel)
if bad:
faults.append({"path": rel, "line": bad[0], "why": bad[1]})
else:
blobs = read_rev(top, rev, rels)
for rel in rels:
if rel not in blobs:
faults.append({"path": rel, "line": 0,
"why": "UNREADABLE at %s" % rev})
continue
bad = grade_bytes(blobs[rel], rel)
if bad:
faults.append({"path": rel, "line": bad[0], "why": bad[1]})
return len(rels), faults, None
def shown(path):
"""A path as ONE printable line: newlines and undecodable bytes escaped.
A fault line is read by a human and by `grep`; the tracked path at
`99eba1e` contains four newlines, so printing it raw turned one fault into
eight lines of bash source in the middle of the report.
"""
return (path.encode("utf-8", "backslashreplace")
.decode("utf-8", "replace").replace("\n", "\\n"))
def report(rev, files, faults, quiet):
where = "the worktree" if rev == REV_WORKTREE else rev
if not quiet:
for f in faults[:FAULT_LIMIT]:
print("FAULT %s:%d %s" % (shown(f["path"]), f["line"], f["why"]))
if len(faults) > FAULT_LIMIT:
print(" ... %d more fault(s) not printed" % (len(faults) - FAULT_LIMIT))
print("compile_sweep: %d tracked .py at %s, %d fault(s)"
% (files, where, len(faults)))
return 1 if faults else 0
# ------------------------------------------------------------------- selftest
def _git(repo, *args):
return subprocess.run(["git", "-C", repo] + list(args), capture_output=True,
text=True)
def _write(path, text):
with open(path, "w", encoding="utf-8") as fh:
fh.write(text)
def _commit(repo, msg="fixture"):
_git(repo, "add", "-A")
_git(repo, "-c", "user.name=selftest", "-c", "user.email=selftest@invalid",
"-c", "commit.gpgsign=false", "commit", "-q", "-m", msg)
GOOD = "def f():\n return 1\n"
BROKEN = ("def _check(cond, msg):\n"
" \"\"\"A failure path.\"\"\"\n"
"from pathlib import Path\n"
" if not cond:\n"
" raise RuntimeError(msg)\n")
def selftest():
cells = passed = 0
failures = []
def check(name, got, want):
nonlocal cells, passed
cells += 1
if got == want:
passed += 1
else:
failures.append("%s: got %r want %r" % (name, got, want))
with tempfile.TemporaryDirectory(prefix="q169-selftest-") as td:
def repo(name, files, do_commit=True):
p = os.path.join(td, name)
os.makedirs(p)
for rel, text in files.items():
full = os.path.join(p, rel)
os.makedirs(os.path.dirname(full) or p, exist_ok=True)
_write(full, text)
_git(p, "init", "-q", ".")
if do_commit:
_commit(p)
return p
# 1 -- a clean tree is clean
a = repo("clean", {"a.py": GOOD, "pkg/b.py": GOOD})
files, faults, why = sweep(a, REV_WORKTREE)
check("1 files counted", files, 2)
check("1 no fault", (faults, why), ([], None))
# 2 -- one unparseable file names itself and its line
b = repo("broken", {"a.py": GOOD, "bad.py": BROKEN})
files, faults, why = sweep(b, REV_WORKTREE)
check("2 one fault", len(faults), 1)
check("2 names path", faults[0]["path"], "bad.py")
check("2 names a line", faults[0]["line"] > 0, True)
# 3 -- the rev is the axis: HEAD clean, worktree broken
c = repo("revaxis", {"a.py": GOOD})
_write(os.path.join(c, "a.py"), BROKEN)
_, wf, _ = sweep(c, REV_WORKTREE)
_, hf, _ = sweep(c, "HEAD")
check("3 worktree faults", len(wf), 1)
check("3 HEAD clean", (len(hf), hf), (0, []))
# 4 -- and the other way: the break is committed, the worktree fixed
d = repo("revaxis2", {"a.py": BROKEN})
_write(os.path.join(d, "a.py"), GOOD)
_, wf2, _ = sweep(d, REV_WORKTREE)
_, hf2, _ = sweep(d, "HEAD")
check("4 worktree clean", len(wf2), 0)
check("4 HEAD faults", [f["path"] for f in hf2], ["a.py"])
# 5 -- a tracked file deleted from the worktree is a fault, not a skip
e = repo("gone", {"a.py": GOOD, "b.py": GOOD})
os.unlink(os.path.join(e, "b.py"))
_, gf, _ = sweep(e, REV_WORKTREE)
check("5 missing is a fault", [(f["path"], f["why"][:7]) for f in gf],
[("b.py", "MISSING")])
# 6 -- a directory that is not a repository is refused, not graded
plain = os.path.join(td, "plain")
os.makedirs(plain)
top, why6 = resolve_repo(plain)
check("6 refused", (top, "not a git repository" in (why6 or "")),
(None, True))
# 7 -- a repository with no python is a refusal too (rc 2)
g = repo("nopy", {"README.md": "hi\n"})
files7, _, why7 = sweep(g, REV_WORKTREE)
check("7 no .py refused", (files7, "no tracked *.py" in (why7 or "")),
(0, True))
# 8 -- an unknown rev is a refusal, never a clean zero
_, _, why8 = sweep(a, "no-such-rev")
check("8 bad rev refused", "revision no-such-rev" in (why8 or ""), True)
# 9 -- --json carries the fault and the rc
jpath = os.path.join(td, "rows.json")
rc9 = main(["--repo", b, "--json", jpath, "--quiet"])
with open(jpath) as fh:
doc = json.load(fh)
check("9 json rc", (rc9, doc["rc"]), (1, 1))
check("9 json fault", [f["path"] for f in doc["faults"]], ["bad.py"])
# 10 -- an unwritable --json target is rc 2, legible, no traceback
rc10 = main(["--repo", a, "--quiet", "--json",
os.path.join(td, "no-such-dir", "x.json")])
check("10 unwritable json rc 2", rc10, 2)
# 11 -- the broken reading is rc 1 through main(), the clean one rc 0
check("11 main rc", (main(["--repo", a, "--quiet"]),
main(["--repo", b, "--quiet"])), (0, 1))
# 12 -- a tracked path containing a NEWLINE is read at the rev, and the
# file sorted after it is still read: the batch framing must be NUL.
# The pre-repair reader (newline-delimited requests) split this path
# into extra requests and lost `z.py`, which is what this cell kills.
h = repo("newlinepath", {"a.py": GOOD})
_write(os.path.join(h, "0weird\nname.py"), GOOD)
_write(os.path.join(h, "z.py"), GOOD)
_commit(h, "newline path")
files12, faults12, why12 = sweep(h, "HEAD")
check("12 every file read", (files12, why12), (3, None))
check("12 no fault", [(f["path"], f["why"]) for f in faults12], [])
check("12 newline path recovered",
[p for p in read_rev(h, "HEAD", tracked(h, "HEAD")[0])
if "\n" in p], ["0weird\nname.py"])
# 13 -- and a fault on such a path prints as ONE line
i = repo("newlinefault", {"0weird\nname.py": BROKEN, "z.py": GOOD})
files13, faults13, _ = sweep(i, "HEAD")
check("13 fault found", (files13, [f["path"] for f in faults13]),
(2, ["0weird\nname.py"]))
check("13 one printable line", shown(faults13[0]["path"]),
"0weird\\nname.py")
print("selftest: %d cells, %d passed, %d failed"
% (cells, passed, len(failures)))
for f in failures:
print("FAIL %s" % f)
return 0 if passed == cells else 1
# ----------------------------------------------------------------------- main
def main(argv=None):
ap = argparse.ArgumentParser(
description="every tracked *.py must parse, at the worktree or a rev")
ap.add_argument("--repo", default=".",
help="repository to grade (default .)")
ap.add_argument("--rev", default=REV_WORKTREE,
help="WORKTREE (default) or a git revision")
ap.add_argument("--json", metavar="PATH", help="write the rows here")
ap.add_argument("--quiet", action="store_true", help="summary line only")
ap.add_argument("--selftest", action="store_true", help="run the fixtures")
a = ap.parse_args(argv)
if a.selftest:
return selftest()
top, why = resolve_repo(a.repo)
if why:
print(why, file=sys.stderr)
return 2
files, faults, why = sweep(top, a.rev)
if why:
print(why, file=sys.stderr)
return 2
rc = report(a.rev, files, faults, a.quiet)
if a.json:
try:
with open(a.json, "w") as fh:
json.dump({"repo": top, "rev": a.rev, "files": files,
"faults": faults, "rc": rc}, fh, indent=1)
except OSError as exc:
print("cannot write --json %s: %s" % (a.json, exc), file=sys.stderr)
return 2
return rc
if __name__ == "__main__":
sys.exit(main())
+355
View File
@@ -0,0 +1,355 @@
#!/usr/bin/env python3
"""q170 import-order check -- a module-level import must be BOUND before the name
it binds is EXECUTED.
WHY THIS EXISTS
The 2026-11-05 host-path refactor moved 85 verifier files off
`/root/troupe-standup` onto `Path(__file__).resolve().parents[2]` and, by hand,
inserted `from pathlib import Path` into each of them. In three files the line
landed where a text replacement could reach and not where Python reads first:
wizard-work/beam/verify_wordcount_test.py:46 import, after main() runs
wizard-work/spark/verify_wordcount_test.py:46 import, after main() runs
wizard-work/ledger/verify_dates.py:38 import, after REPO = Path(...)
Both shapes fail at RUN time with `NameError: name 'Path' is not defined`, and
both PARSE cleanly: `ast.parse` has no opinion about order, so the compile leg
(q169) read the tree green, `tools/verify.py --fast` read `gate: OK`, and the
three files were dead the whole time. Measured before the repair:
python3 wizard-work/beam/verify_wordcount_test.py
NameError: name 'Path' is not defined (line 10, inside main)
A file that parses and cannot run is the class this check names. The gate had
no leg with an opinion on execution order; the compile sweep made the parse
axis visible and this file is the axis beside it.
WHAT IT MEASURES -- three sound rules, no heuristics about style
A. MODULE-LEVEL USE. A top-level statement that EXECUTES (not a `def`, a
`class`, or the module docstring) reads the name before the import's line.
`REPO = Path(__file__)...` above `from pathlib import Path` is this rule.
B. A FUNCTION CALLED TOO EARLY. A `def` that references the name, defined
above the import, and CALLED by a top-level statement above the import.
`sys.exit(main())` above the import is this rule -- the shape that parses
clean and dies on the first run.
C. A `def` whose decorator, default, or annotation reads the name (those are
evaluated where the `def` sits, not when it is called).
Deliberately NOT graded, because they are legitimate and a checker that fired
on them would be noise: a name used only inside a `def` that is called after
the import (rule B's counter-cell); `sys.path.insert(...)` above an import
(this repository does it on purpose -- the name is not read before it is
bound); imports inside a function body; `from __future__` and star imports.
POPULATION AND REVISION AXIS
Identical to the compile leg by construction: `tracked`, `read_worktree`,
`read_rev` and `resolve_repo` are IMPORTED from `q169_compile_sweep` rather
than copied, so the two legs cannot drift on which files they call the tree
(Q142 closed exactly that: a duplicate scanner with a different rule list
called an independent verifier).
EXIT CODES (the tools/ contract)
0 no fault | 1 at least one fault | 2 could not grade
Stdlib only; nothing here writes to the tree (`--json` writes the named file).
"""
import argparse
import ast
import json
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from q169_compile_sweep import (REV_WORKTREE, read_rev, read_worktree, # noqa: E402
resolve_repo, shown, tracked)
FAULT_LIMIT = 40
SCOPE = "module-level imports and the top-level statements that execute"
def _imports(tree):
"""{name: (import_lineno, import_end_lineno)} for module-level imports.
Walks the module body but never into a `def`/`class`/`lambda` body: an
import inside a function binds nothing at module scope, so it cannot be
the import an earlier top-level statement was counting on.
"""
found = {}
stack = list(tree.body)
while stack:
node = stack.pop()
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef,
ast.Lambda)):
continue
if isinstance(node, (ast.Import, ast.ImportFrom)):
mod = getattr(node, "module", None) or ""
for alias in node.names:
if alias.name == "*":
continue
name = alias.asname or alias.name.split(".")[0]
# EARLIEST binding, not the first one visited: the walk is a
# stack, so visit order is not document order, and a name
# imported twice (pathlib at line 5 and again at line 12) was
# reported against the LATER line -- a fault for a file that
# binds the name before it reads it.
cand = (node.lineno, node.end_lineno or node.lineno, mod)
if name not in found or cand[0] < found[name][0]:
found[name] = cand
continue
stack.extend(ast.iter_child_nodes(node))
return found
def _executed_reads(tree):
"""{name: first_lineno} for names READ by a top-level statement that runs.
"Runs" means: not inside a `def`/`class`/`lambda` body. A `def`'s own
decorators, defaults and annotations DO run where the `def` sits, so those
are collected separately by `_definition_time_reads`.
"""
first = {}
def note(name, lineno):
if lineno and lineno < first.get(name, 10 ** 9):
first[name] = lineno
def walk(node):
for child in ast.iter_child_nodes(node):
if isinstance(child, (ast.FunctionDef, ast.AsyncFunctionDef,
ast.ClassDef)):
# decorators, defaults and annotations execute here; the body
# does not. `walk_definition_time` collects the former.
walk_definition_time(child)
continue
if isinstance(child, ast.Lambda):
continue
if isinstance(child, ast.Name) and isinstance(child.ctx, ast.Load):
note(child.id, child.lineno)
walk(child)
def walk_definition_time(fn):
exprs = list(getattr(fn, "decorator_list", []))
args = getattr(fn, "args", None)
if args is not None:
exprs.extend(a for a in args.defaults if a is not None)
exprs.extend(a for a in args.kw_defaults if a is not None)
for a in exprs:
for sub in ast.walk(a):
if isinstance(sub, ast.Name) and isinstance(sub.ctx, ast.Load):
note(sub.id, sub.lineno)
for stmt in tree.body:
if isinstance(stmt, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
walk_definition_time(stmt)
continue
if isinstance(stmt, (ast.Import, ast.ImportFrom)):
continue
if isinstance(stmt, ast.Name) and isinstance(stmt.ctx, ast.Load):
note(stmt.id, stmt.lineno)
walk(stmt)
return first
def _fn_reads(fn):
"""{name: first_lineno} for names read anywhere inside a def/class body."""
first = {}
for sub in ast.walk(fn):
if isinstance(sub, ast.Name) and isinstance(sub.ctx, ast.Load):
if sub.lineno < first.get(sub.id, 10 ** 9):
first[sub.id] = sub.lineno
return first
def order_faults(src, rel):
"""[(line, why)] -- rule A, B and C, sorted by line."""
import warnings
with warnings.catch_warnings():
warnings.simplefilter("ignore", SyntaxWarning)
tree = ast.parse(src, filename=rel)
imports = _imports(tree)
if not imports:
return []
executed = _executed_reads(tree)
faults = []
seen = set()
def add(line, why):
if (line, why) not in seen:
seen.add((line, why))
faults.append((line, why))
# A -- read at module level before the import line
for name, (start, _end, _mod) in imports.items():
line = executed.get(name)
if line is not None and line < start:
add(line, "%s read here, imported at line %d" % (name, start))
# B / C -- a def above the import that reads the name
for stmt in tree.body:
if not isinstance(stmt, (ast.FunctionDef, ast.AsyncFunctionDef,
ast.ClassDef)):
continue
body_reads = _fn_reads(stmt)
for name, (start, _end, _mod) in imports.items():
if stmt.lineno >= start or name not in body_reads:
continue
called = executed.get(stmt.name)
if called is not None and called < start:
add(called, "%s read by %s() at line %d, imported at line %d"
% (name, stmt.name, called, start))
return sorted(faults)
def sweep(top, rev):
"""(files, faults, reason). faults: [{"path","line","why"}]."""
rels, why = tracked(top, rev)
if why:
return 0, [], why
if not rels:
return 0, [], "could not grade -- no tracked *.py at %s" % (
"the worktree" if rev == REV_WORKTREE else rev)
faults = []
if rev == REV_WORKTREE:
for rel in rels:
src, err = read_worktree(top, rel)
if err:
continue # q169 owns "the file is gone"; not this question
bad = order_faults(src, rel)
for line, why in bad:
faults.append({"path": rel, "line": line, "why": why})
else:
blobs = read_rev(top, rev, rels)
for rel in rels:
src = blobs.get(rel)
if src is None:
continue
for line, why in order_faults(src, rel):
faults.append({"path": rel, "line": line, "why": why})
return len(rels), faults, None
def report(rev, files, faults, quiet):
where = "the worktree" if rev == REV_WORKTREE else rev
if not quiet:
for f in faults[:FAULT_LIMIT]:
print("FAULT %s:%d %s" % (shown(f["path"]), f["line"], f["why"]))
if len(faults) > FAULT_LIMIT:
print(" ... %d more fault(s) not printed" % (len(faults) - FAULT_LIMIT))
print("import_order: %d tracked .py at %s, %d fault(s)"
% (files, where, len(faults)))
return 1 if faults else 0
# ------------------------------------------------------------------- selftest
CLEAN = "import os\nfrom pathlib import Path\n\n\ndef f():\n return Path(os.sep)\n"
SIMPLE_BAD = "REPO = Path(__file__).resolve()\nfrom pathlib import Path\n"
EARLY_CALL = ("import sys\n\n\ndef main():\n return Path('.')\n\n\n"
"if __name__ == '__main__':\n sys.exit(main())\n"
"from pathlib import Path\n")
LATE_CALL = ("import sys\nfrom pathlib import Path\n\n\ndef main():\n"
" return Path('.')\n\n\nif __name__ == '__main__':\n"
" sys.exit(main())\n")
SYSPATH = ("import sys\nsys.path.insert(0, '/somewhere')\nimport helpers\n"
"print(helpers.x)\n")
STAR = "from os.path import *\nprint(join('a', 'b'))\n"
DECORATED = ("import functools\n\n\n@functools.wraps(Path)\ndef f():\n pass\n"
"from pathlib import Path\n")
NESTED = ("def f():\n from pathlib import Path\n return Path('.')\n")
def selftest():
cells = passed = 0
failures = []
def check(name, got, want):
nonlocal cells, passed
cells += 1
if got == want:
passed += 1
else:
failures.append("%s: got %r want %r" % (name, got, want))
def names(src):
return [why.split()[0] for _line, why in order_faults(src, "x.py")]
check("1 clean file has no fault", order_faults(CLEAN, "x.py"), [])
check("2 module-level read before import", names(SIMPLE_BAD), ["Path"])
check("2b the line is the read, not the import",
[ln for ln, _ in order_faults(SIMPLE_BAD, "x.py")], [1])
check("2c the import line is named in the why",
"imported at line 2" in order_faults(SIMPLE_BAD, "x.py")[0][1], True)
check("3 def called before the import", names(EARLY_CALL), ["Path"])
check("3b the call site is the line",
[ln for ln, _ in order_faults(EARLY_CALL, "x.py")], [9])
check("4 def called after the import is silent",
order_faults(LATE_CALL, "x.py"), [])
check("5 sys.path.insert above an import is silent",
order_faults(SYSPATH, "x.py"), [])
check("6 star import is not a binding", order_faults(STAR, "x.py"), [])
check("7 a decorator reading the name is a fault",
names(DECORATED), ["Path"])
check("8 an import inside a function binds nothing at module scope",
order_faults(NESTED, "x.py"), [])
check("9 a file with no imports has no fault",
order_faults("x = 1\nprint(x)\n", "x.py"), [])
check("10 one fault per name, not one per read",
len(order_faults("print(os)\nprint(os)\nimport os\n", "x.py")), 1)
check("11 report() is rc 1 on a fault and rc 0 clean",
(report("WORKTREE", 2, [{"path": "x.py", "line": 1, "why": "y"}], True),
report("WORKTREE", 2, [], True)), (1, 0))
with __import__("tempfile").TemporaryDirectory(prefix="q170-selftest-") as td:
plain = os.path.join(td, "plain")
os.makedirs(plain)
top, why = resolve_repo(plain)
check("12 non-repository refused",
(top, "not a git repository" in (why or "")), (None, True))
rc = main(["--repo", td, "--quiet"])
check("13 a tree with no .py is rc 2", rc, 2)
print("selftest: %d cells, %d passed, %d failed"
% (cells, passed, len(failures)))
for f in failures:
print("FAIL %s" % f)
return 0 if passed == cells else 1
# ----------------------------------------------------------------------- main
def main(argv=None):
ap = argparse.ArgumentParser(
description="every module-level import is bound before the name it "
"binds is executed")
ap.add_argument("--repo", default=".", help="repository to grade (default .)")
ap.add_argument("--rev", default=REV_WORKTREE,
help="WORKTREE (default) or a git revision")
ap.add_argument("--json", metavar="PATH", help="write the rows here")
ap.add_argument("--quiet", action="store_true", help="summary line only")
ap.add_argument("--selftest", action="store_true", help="run the fixtures")
a = ap.parse_args(argv)
if a.selftest:
return selftest()
top, why = resolve_repo(a.repo)
if why:
print(why, file=sys.stderr)
return 2
files, faults, why = sweep(top, a.rev)
if why:
print(why, file=sys.stderr)
return 2
rc = report(a.rev, files, faults, a.quiet)
if a.json:
try:
with open(a.json, "w") as fh:
json.dump({"repo": top, "rev": a.rev, "files": files,
"faults": faults, "rc": rc}, fh, indent=1)
except OSError as exc:
print("cannot write --json %s: %s" % (a.json, exc), file=sys.stderr)
return 2
return rc
if __name__ == "__main__":
sys.exit(main())