volt: root CHECK-* sweep 2026-11-02 -- 32 entries, 20 OK / 12 FAULT at e44d49a

sweep.py runs every root CHECK-* under bash and records rc, class and the
process's last line, pinning rev + sha256 of each entry in manifest.json.
report.md is the table; TRIAGE.md groups the 12 reds into four causes.
check-root-sweep.sh grades the record (pin / universe / class contract /
report parity / rows integrity), 5 legs, with sensitivity_probe.py proving
three mutations redden the leg that owns them and the restore is green.
This commit is contained in:
ledger committed 2026-11-02 22:58:39 +00:00
1 parent e44d49aeec
commit 6b1e24fec4
8 files changed
+956

No files matched your search

+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
# check-root-sweep.sh -- grade the root CHECK-* sweep artifact.
#
# The sweep (wizard-work/volt/root-check-sweep/sweep.py) runs every root
# CHECK-* entry point and records each exit code with the bytes it measured.
# Its verifier grades that record: the pin (rev, timestamp, timeout), the
# universe (entry list + sha256), the rc -> class contract, the report's
# parity with the rows, and the rows file's own integrity.
#
# Deliberately named in lower case: upper-case CHECK* at the repository root
# is the population the q143 census enumerates, and a verifier of that census
# must not silently join it.
set -u
exec python3 "$(dirname "${BASH_SOURCE[0]}")/wizard-work/volt/root-check-sweep/verify_sweep.py"
@@ -0,0 +1,98 @@
# Root CHECK sweep -- 2026-11-02, handover
Measured at `e44d49aeeca2b61c5a03ab33d0b8cef66f423d73` -- see `manifest.json` for the full
40-hex rev, the UTC stamp and the sha256 of every entry point that was run. The sweep ran **32**
root `CHECK-*` entry points under `bash <path>`: **20 OK, 12 FAULT, 0 UNEXPECTED,
0 TIMEOUT, 0 could-not-grade** (531.3 s). Rows: `results.tsv`. Table: `report.md`.
The 12 reds are not 12 defects. They are **four causes**, measured below, each with the
fault line the entry point itself printed in this run.
## A. The Q159 landing is in the worktree, not in the tree (q143, q148, q159)
CHECK-q143 rc=1 FAIL: MISSING CHECK-q159 -- baseline names it, the tree does not have it
CHECK-q148 rc=1 FAIL: MISSING CHECK-q159 -- baseline names it, the tree does not have it
CHECK-q159 rc=1 census FAULT rc=1 :: paths: 141 entry point(s), 140 baseline path(s), 3 fault(s)
`wizard-work/volt/q143-check-sweep/check_entry_baseline.tsv` carries the Q159 guard row and
`CHECK-q159` exists on disk, but `check_sweep.py` discovers **tracked** entry points and
`CHECK-q159` is untracked -- so the baseline names a path the tree does not hold. The same
two commands also report the next cause.
Fix: commit `CHECK-q159` with the baseline row that names it (and the Q159 witnesses), or drop
the row until it is committed. Nothing else in this cluster is a code fault.
## B. Two tracked entry points have no baseline row (q143, q159)
FAIL: NEW wizard-work/ledger/CHECK-2026-11-02-jobs-table -- in the tree, not in the baseline
FAIL: NEW wizard-work/sol/CHECK-untracked-file-classify-2026-11-02 -- in the tree, not in the baseline
Both are committed and therefore discoverable, but neither has a row a human signed. Fix:
run each once, record its rc and first fault line in `check_entry_baseline.tsv` through the
row-level re-take path (the file's own convention), or the census is red for every reader.
## C. `CHECK-q-checkparen` pins a tally the rubric outgrew (q-checkparen)
FAULT selftest rc=0 selftest: 51 cells, 51 passed, 0 failed
FAULT pin ['check_lint.py\t51\tcells']
FAULT falsifier rc=1 selftest: 51 cells, 49 passed, 2 failed
The subject is green (51/51) and the falsifier leg proves the rubric can red (49/51 on the
mutated copy), so what is stale is the verifier's expected literal, not `check_lint.py`. This
is the Q158 shape a second time: a verifier that asserts a cell tally goes red when the
rubric grows, on a tree where the refactor it grades is untouched.
## D. Beam lane: coverage and bindings (q149, q153, q85)
CHECK-q149 rc=1 FAIL beam-gate red (rc=1)
CHECK-q153 rc=1 FAIL lane-check bindings: 185 file(s) graded repo-wide at WORKTREE, 109 test file(s) in wizard-work/beam/
CHECK-q85 rc=1 coverage: 118 module(s): ... 2 run by CHECK, 6 exempt, 1 fault(s) (all three live passes)
`CHECK-q153`'s `verify` leg is green (6/6) and `import_resolve_check` grades 185 files with 0
faults; the red is the `lane-check` binding leg (185 graded vs 109 test files in the lane).
`CHECK-q85`'s coverage authority reports 1 fault over 118 modules in every one of its three
live runs, so it is not a flake. These three are one subject: the beam lane's module set is
larger than the set its collected tests and its binding census can account for.
## E. `CHECK-q150`: q65's ledger and rc probe (q150)
FAIL runner-ledger q65: 8 fault(s)
FAIL rc-probe q65_rc_probe: 5 fault(s)
PASS no-verdict q65_no_verdict: 0 fault(s)
Two of three legs red, and the two `.tsv` files they read
(`wizard-work/volt/q65_runner_baseline.tsv`, `q65_rc_probe.tsv`) are **modified in this
worktree** (uncommitted), so the first question is whether this red is the modification or
the tree. Not settled here.
## F. Frozen untracked snapshots (sol-untracked-classify, untracked-triad, untracked-triage)
CHECK-sol-untracked-classify rc=1 frozen path missing on disk: 'verify_wordcount_test.py'
CHECK-sol-untracked-classify rc=1 frozen path not present under repo: 'wizard-work/null/.hermes-tmp.RqZp3z'
CHECK-untracked-triad-2026-11-01 rc=1 id=1 path=CHECK-q146 is not currently untracked
CHECK-untracked-triage-2026-11-01 rc=1 frozen path missing on disk: ['wizard-work/null/.hermes-tmp.RqZp3z']
Three snapshots of "the untracked set at rev X" graded against the live set. Two of the paths
they froze no longer exist (`wizard-work/null/.hermes-tmp.RqZp3z` is a temp directory;
`verify_wordcount_test.py` left the root) and `CHECK-q146` was committed, so it stopped being
untracked. The classification was never wrong; the universe moved. This is Q157's shape
exactly, in three more files.
## G. `CHECK-sol-profile-triage-2026-11-02`: artifact vs live profile (sol-profile)
CHECK FAIL categories mismatch:
artifact state_db 11 / config_data 1
live state_db 10 / config_data 2
One live profile path moved between the two categories after the artifact was taken. The
baseline already signs this row `KNOWN RED: artifact categories != live disk (sol profile
changed after the artifact was taken)`, so this sweep confirms the signed reading rather than
finding a new one.
## What this sweep does not claim
- It grades the **worktree**, not the commit: 106 paths differ from `e44d49a` (modified +
untracked). A green row is green for those bytes, which `manifest.json` pins by sha256.
- It does not re-run the checks that were green; it records the process and its last line.
- It does not say a red row is a defect. A, C, F and G are stale instruments on a moved
universe; B is unregistered work; D and E are not attributed here.
@@ -0,0 +1,209 @@
{
"counts": {
"FAULT": 12,
"OK": 20
},
"entries": [
{
"bytes": 761,
"name": "CHECK",
"sha256": "5d039e42302a6d7a2618cf271e6f4a03450ed6df6ee9a0144c2295b7a6fa6975",
"tracked_at_rev": true
},
{
"bytes": 365,
"name": "CHECK-2026-11-01-ledger-dir-census",
"sha256": "0a524960e582563431bba85d15f3955ef1f9c501c1e921068c070060d1edf62d",
"tracked_at_rev": true
},
{
"bytes": 428,
"name": "CHECK-2026-11-02-openmeteo-summary",
"sha256": "c50bfff355a56d5fa427fef8ac8c270e71519d84261eb438598f6631fa6cf884",
"tracked_at_rev": false
},
{
"bytes": 1276,
"name": "CHECK-2026-11-02-untracked-classify",
"sha256": "fdce9d0887932498611e6fd72c1fb9f97516fb9647738c6bf74dd79c0f8083e4",
"tracked_at_rev": true
},
{
"bytes": 524,
"name": "CHECK-ledger-dir-census",
"sha256": "0db9b52e919cc17e7b5a2b063137edd04b1e3767d284912ce665a2fbb9e1f47d",
"tracked_at_rev": true
},
{
"bytes": 466,
"name": "CHECK-q-checkparen",
"sha256": "63035f0c2df959ad5b54021fa4d86abb3fb79868510a7abeb8c6a09f3b9f4b54",
"tracked_at_rev": true
},
{
"bytes": 3743,
"name": "CHECK-q143",
"sha256": "5d8b3f6a5647959c1d04fefedac35f6fd5fe325168ff9dd578a4486c2571c43e",
"tracked_at_rev": true
},
{
"bytes": 3556,
"name": "CHECK-q146",
"sha256": "b64ff06524745e8fd6d2845ab69303d7472f579b1b18605efb272d42c5594d7c",
"tracked_at_rev": true
},
{
"bytes": 2947,
"name": "CHECK-q147",
"sha256": "5aa35a79a4da211a6beb758598375b9c7fbcc653ea197d68dac58dafe0389ab0",
"tracked_at_rev": true
},
{
"bytes": 5783,
"name": "CHECK-q148",
"sha256": "231d04cff956786092b4ea3fd4972d186e6b382463a9c10051ec2603b4f97b24",
"tracked_at_rev": true
},
{
"bytes": 6178,
"name": "CHECK-q149",
"sha256": "2cf788980c1626e6e34fe7e9d99e729b3030653cd515f314270f95addef37785",
"tracked_at_rev": true
},
{
"bytes": 4626,
"name": "CHECK-q150",
"sha256": "0a7975b85e8130f35a3c0d1e90d12a867effc4420b59d4f6806f8f7b6b134ff7",
"tracked_at_rev": true
},
{
"bytes": 2873,
"name": "CHECK-q151",
"sha256": "59ef476b23d885b3caa93e3e843eff6a97210814f7a6f587bbe20b2caebf1cfe",
"tracked_at_rev": true
},
{
"bytes": 3315,
"name": "CHECK-q152",
"sha256": "b9de094511787b806115581041523b6188ea0be6ad8fefdc75328caa6f8560ef",
"tracked_at_rev": true
},
{
"bytes": 2600,
"name": "CHECK-q153",
"sha256": "062dced3a83f657e65c5f9fe224e4e8904c3905b707c685620a2348b1ef8f20e",
"tracked_at_rev": true
},
{
"bytes": 5909,
"name": "CHECK-q154",
"sha256": "0bbf23fb865312b8648b22b5a77a88131beddae23f9fd80d0b18a13a86b828cf",
"tracked_at_rev": false
},
{
"bytes": 2575,
"name": "CHECK-q155",
"sha256": "54617458249263e3f10b22d2833c285434f0f4a92345abb22768f9bc1aaab7b7",
"tracked_at_rev": true
},
{
"bytes": 3447,
"name": "CHECK-q156",
"sha256": "383ee3d94361ce01297e1079e6ea8ca0755f20376d29404bf45a21f52a63cf79",
"tracked_at_rev": true
},
{
"bytes": 3312,
"name": "CHECK-q157",
"sha256": "4744b5b5327abbab7a6be5662ea87473b306a3fef01196f8583da497023f9047",
"tracked_at_rev": true
},
{
"bytes": 6925,
"name": "CHECK-q158",
"sha256": "f80552e1f098208bab404743142c19b2ab058b23e3ac5c358de4c7a6b7451a08",
"tracked_at_rev": true
},
{
"bytes": 4956,
"name": "CHECK-q159",
"sha256": "acb287d3fe74dd8ec8f555dfb9b952fad8fe4fc0e43d8720f5811dbc318e45d0",
"tracked_at_rev": false
},
{
"bytes": 5528,
"name": "CHECK-q85",
"sha256": "4980bbd76f171ccf7af4584d84175f1f144872f28a58b73cb33e5892be0916c7",
"tracked_at_rev": true
},
{
"bytes": 6438,
"name": "CHECK-quill-draft-compliance",
"sha256": "a1beb354a32e70f759f4e1375a2444b055fa437a085fa288456d2a50b76bad21",
"tracked_at_rev": true
},
{
"bytes": 689,
"name": "CHECK-sol-lane-triage-2026-10-29",
"sha256": "24800b074f4be5471e1d75e94ca8200dd96228b71fc862deb9027994883f66a0",
"tracked_at_rev": true
},
{
"bytes": 673,
"name": "CHECK-sol-lane-triage-2026-11-01",
"sha256": "198a8ca344c37a4883abc584f409bc4dce54f57b4d273b8ee30fa874e4852007",
"tracked_at_rev": true
},
{
"bytes": 602,
"name": "CHECK-sol-lane-triage-2026-11-02",
"sha256": "1031f3c20fb31b5b46f36e63f9b9e240901090fb75c07f0cc2dca9122f1a3bc5",
"tracked_at_rev": true
},
{
"bytes": 527,
"name": "CHECK-sol-profile-triage-2026-11-02",
"sha256": "e6bb09c6a98708c84abafe4c4cf7de2fbe457c3c0a54ff8ac886e31aeecb6c5e",
"tracked_at_rev": true
},
{
"bytes": 457,
"name": "CHECK-sol-untracked-classify",
"sha256": "4e383e4b40f99115830cfaab37267786a8b8639a22590a308368f25e31e156ba",
"tracked_at_rev": false
},
{
"bytes": 358,
"name": "CHECK-triage-2026-10-29",
"sha256": "aa3e442abdf491038888fa3e1319c13b218ae1013ec60fb4b62c0c300cd83c15",
"tracked_at_rev": false
},
{
"bytes": 386,
"name": "CHECK-triage-2026-11-01",
"sha256": "f6dba366ba5c5a1de2be1efb7e3d413acaca73e0f98aec7a1fbcc7e4bedd0384",
"tracked_at_rev": true
},
{
"bytes": 503,
"name": "CHECK-untracked-triad-2026-11-01",
"sha256": "001cb873fe11c58ece2a0785e51a30b1ba7d7f6a6595fca59af94e9ec84f8ad2",
"tracked_at_rev": true
},
{
"bytes": 533,
"name": "CHECK-untracked-triage-2026-11-01",
"sha256": "f1a013f31a3a5aa05302eefe977b5865424c942b78eeff01824fbd563503214c",
"tracked_at_rev": true
}
],
"entry_count": 32,
"generated_utc": "2026-11-02T22:38:46Z",
"repo": "troupe-standup",
"results_sha256": "540fea8d1bea8bcfd3f5b7572c11804c11cd36ceabecc61eedce23dcc2658331",
"rev": "e44d49aeeca2b61c5a03ab33d0b8cef66f423d73",
"rev_subject": "beam: content-based duplicate file detector with tests",
"timeout_s": 300,
"tool": "wizard-work/volt/root-check-sweep/sweep.py",
"worktree_dirty_paths": 106
}
@@ -0,0 +1,59 @@
# Root CHECK-* entry-point sweep
- measured at: `2026-11-02T22:38:46Z`
- rev: `e44d49aeeca2b61c5a03ab33d0b8cef66f423d73` -- beam: content-based duplicate file detector with tests
- worktree: 106 path(s) differ from that rev (modified + untracked); the worktree is what was graded
- entry points run: **32**
- FAULT: **12**
- OK: **20**
- total wall time: **531.3 s**
| entry | rc | s | class | last line |
|---|---|---|---|---|
| `CHECK` | 0 | 2.3 | OK | verify_selftest_sweep_q93_refactor: ALL GREEN (0 failed, all checks) |
| `CHECK-2026-11-01-ledger-dir-census` | 0 | 1.67 | OK | VERDICT: rc 0 -- the committed CSV is the derivation at the pinned rev |
| `CHECK-2026-11-02-openmeteo-summary` | 0 | 0.19 | OK | PASS: 6 rows match source-derived table; header exact |
| `CHECK-2026-11-02-untracked-classify` | 0 | 1.24 | OK | CHECK OK: 306 pinned paths; manifest==snapshot in order; categories re-derive by rule; rule agrees with the generator; no pinned path was tracked at 4a640e1 |
| `CHECK-ledger-dir-census` | 0 | 2.28 | OK | VERDICT: rc 0 -- the committed CSV is the derivation at the pinned rev |
| `CHECK-q-checkparen` | 1 | 2.0 | FAULT | verify_fix: 3 leg(s) faulted |
| `CHECK-q143` | 1 | 31.17 | FAULT | q143: 2 leg(s), 1 fault(s) |
| `CHECK-q146` | 0 | 2.79 | OK | q146: 4 leg(s), no fault |
| `CHECK-q147` | 0 | 5.33 | OK | q147: 4 of 4 leg(s) passed |
| `CHECK-q148` | 1 | 24.26 | FAULT | q148: 4 of 5 leg(s) passed |
| `CHECK-q149` | 1 | 107.43 | FAULT | q149: 5 of 6 leg(s) passed |
| `CHECK-q150` | 1 | 47.26 | FAULT | q150: 6 leg(s), 2 fault(s) |
| `CHECK-q151` | 0 | 12.33 | OK | q151: 3 leg(s), all passed |
| `CHECK-q152` | 0 | 31.81 | OK | q152: 4 leg(s), all passed |
| `CHECK-q153` | 1 | 68.72 | FAULT | q153: 2 leg(s), 1 fault(s) |
| `CHECK-q154` | 0 | 14.47 | OK | CHECK-q154: 5 leg(s) passed, 0 fault(s), 0 ungradable |
| `CHECK-q155` | 0 | 7.16 | OK | q155: 3 leg(s), all passed |
| `CHECK-q156` | 0 | 63.19 | OK | q156: 6 leg(s), all passed |
| `CHECK-q157` | 0 | 2.74 | OK | q157: 6 leg(s), all passed |
| `CHECK-q158` | 0 | 4.17 | OK | CHECK-q158: 6 leg(s) passed, 0 fault(s), 0 ungradable |
| `CHECK-q159` | 1 | 4.05 | FAULT | q159: 2 passed, 3 fault(s) |
| `CHECK-q85` | 1 | 69.59 | FAULT | q85: 3 leg(s) passed, 2 fault(s), 0 ungradable |
| `CHECK-quill-draft-compliance` | 0 | 2.83 | OK | CHECK-quill-draft-compliance: 5 leg(s) passed, 0 fault(s), 0 ungradable |
| `CHECK-sol-lane-triage-2026-10-29` | 0 | 2.84 | OK | VERIFY OK (216 files, categories re-derived, all paths present) |
| `CHECK-sol-lane-triage-2026-11-01` | 0 | 4.62 | OK | VERIFY OK (339 files, categories re-derived, all paths present) |
| `CHECK-sol-lane-triage-2026-11-02` | 0 | 6.67 | OK | VERIFY OK (382 files, categories re-derived, all paths present) |
| `CHECK-sol-profile-triage-2026-11-02` | 1 | 0.4 | FAULT | - categories mismatch: artifact={'identity': 2, 'config': 3, 'state_db': 11, 'soul': 1, 'script': 20, 'cache': 3, 'backups': 1, 'extension_dir': 18, 'config_dat |
| `CHECK-sol-untracked-classify` | 1 | 0.2 | FAULT | - frozen path not present under repo: 'wizard-work/null/.hermes-tmp.RqZp3z' |
| `CHECK-triage-2026-10-29` | 0 | 0.17 | OK | PASS: Triage-2026-10-29.json re-derives 8/8 items from evidence; decision_counts={'approve': 6, 'table': 2, 'reject': 0}, categories={'archive_fix': 5, 'app_pr' |
| `CHECK-triage-2026-11-01` | 0 | 0.24 | OK | PASS: Triage-2026-11-01.json re-derives 8/8 items from seed evidence; decision_counts={'approve': 6, 'table': 2}, categories={'archive_fix': 5, 'app_pr': 1, 'ge |
| `CHECK-untracked-triad-2026-11-01` | 1 | 7.0 | FAULT | - id=20 path=wizard-work/null/.hermes-tmp.RqZp3z is not currently untracked |
| `CHECK-untracked-triage-2026-11-01` | 1 | 0.18 | FAULT | - frozen path missing on disk: ['wizard-work/null/.hermes-tmp.RqZp3z'] |
## Not OK
- `CHECK-q-checkparen` rc=1 (FAULT): verify_fix: 3 leg(s) faulted
- `CHECK-q143` rc=1 (FAULT): q143: 2 leg(s), 1 fault(s)
- `CHECK-q148` rc=1 (FAULT): q148: 4 of 5 leg(s) passed
- `CHECK-q149` rc=1 (FAULT): q149: 5 of 6 leg(s) passed
- `CHECK-q150` rc=1 (FAULT): q150: 6 leg(s), 2 fault(s)
- `CHECK-q153` rc=1 (FAULT): q153: 2 leg(s), 1 fault(s)
- `CHECK-q159` rc=1 (FAULT): q159: 2 passed, 3 fault(s)
- `CHECK-q85` rc=1 (FAULT): q85: 3 leg(s) passed, 2 fault(s), 0 ungradable
- `CHECK-sol-profile-triage-2026-11-02` rc=1 (FAULT): - categories mismatch: artifact={'identity': 2, 'config': 3, 'state_db': 11, 'soul': 1, 'script': 20, 'cache': 3, 'backups': 1, 'extension_dir': 18, 'config_dat
- `CHECK-sol-untracked-classify` rc=1 (FAULT): - frozen path not present under repo: 'wizard-work/null/.hermes-tmp.RqZp3z'
- `CHECK-untracked-triad-2026-11-01` rc=1 (FAULT): - id=20 path=wizard-work/null/.hermes-tmp.RqZp3z is not currently untracked
- `CHECK-untracked-triage-2026-11-01` rc=1 (FAULT): - frozen path missing on disk: ['wizard-work/null/.hermes-tmp.RqZp3z']
@@ -0,0 +1,33 @@
entry rc secs class traceback last_stdout last_stderr
CHECK 0 2.3 OK 0 verify_selftest_sweep_q93_refactor: ALL GREEN (0 failed, all checks) -
CHECK-2026-11-01-ledger-dir-census 0 1.67 OK 0 VERDICT: rc 0 -- the committed CSV is the derivation at the pinned rev -
CHECK-2026-11-02-openmeteo-summary 0 0.19 OK 0 PASS: 6 rows match source-derived table; header exact -
CHECK-2026-11-02-untracked-classify 0 1.24 OK 0 CHECK OK: 306 pinned paths; manifest==snapshot in order; categories re-derive by rule; rule agrees with the generator; no pinned path was tracked at 4a640e1 -
CHECK-ledger-dir-census 0 2.28 OK 0 VERDICT: rc 0 -- the committed CSV is the derivation at the pinned rev -
CHECK-q-checkparen 1 2.0 FAULT 0 verify_fix: 3 leg(s) faulted -
CHECK-q143 1 31.17 FAULT 0 q143: 2 leg(s), 1 fault(s) -
CHECK-q146 0 2.79 OK 0 q146: 4 leg(s), no fault -
CHECK-q147 0 5.33 OK 0 q147: 4 of 4 leg(s) passed -
CHECK-q148 1 24.26 FAULT 0 q148: 4 of 5 leg(s) passed -
CHECK-q149 1 107.43 FAULT 0 q149: 5 of 6 leg(s) passed -
CHECK-q150 1 47.26 FAULT 0 q150: 6 leg(s), 2 fault(s) -
CHECK-q151 0 12.33 OK 0 q151: 3 leg(s), all passed -
CHECK-q152 0 31.81 OK 0 q152: 4 leg(s), all passed -
CHECK-q153 1 68.72 FAULT 0 q153: 2 leg(s), 1 fault(s) -
CHECK-q154 0 14.47 OK 0 CHECK-q154: 5 leg(s) passed, 0 fault(s), 0 ungradable -
CHECK-q155 0 7.16 OK 0 q155: 3 leg(s), all passed -
CHECK-q156 0 63.19 OK 0 q156: 6 leg(s), all passed -
CHECK-q157 0 2.74 OK 0 q157: 6 leg(s), all passed -
CHECK-q158 0 4.17 OK 0 CHECK-q158: 6 leg(s) passed, 0 fault(s), 0 ungradable -
CHECK-q159 1 4.05 FAULT 0 q159: 2 passed, 3 fault(s) -
CHECK-q85 1 69.59 FAULT 0 q85: 3 leg(s) passed, 2 fault(s), 0 ungradable -
CHECK-quill-draft-compliance 0 2.83 OK 0 CHECK-quill-draft-compliance: 5 leg(s) passed, 0 fault(s), 0 ungradable -
CHECK-sol-lane-triage-2026-10-29 0 2.84 OK 0 VERIFY OK (216 files, categories re-derived, all paths present) -
CHECK-sol-lane-triage-2026-11-01 0 4.62 OK 0 VERIFY OK (339 files, categories re-derived, all paths present) -
CHECK-sol-lane-triage-2026-11-02 0 6.67 OK 0 VERIFY OK (382 files, categories re-derived, all paths present) -
CHECK-sol-profile-triage-2026-11-02 1 0.4 FAULT 0 - categories mismatch: artifact={'identity': 2, 'config': 3, 'state_db': 11, 'soul': 1, 'script': 20, 'cache': 3, 'backups': 1, 'extension_dir': 18, 'config_dat -
CHECK-sol-untracked-classify 1 0.2 FAULT 0 - frozen path not present under repo: 'wizard-work/null/.hermes-tmp.RqZp3z' -
CHECK-triage-2026-10-29 0 0.17 OK 0 PASS: Triage-2026-10-29.json re-derives 8/8 items from evidence; decision_counts={'approve': 6, 'table': 2, 'reject': 0}, categories={'archive_fix': 5, 'app_pr' -
CHECK-triage-2026-11-01 0 0.24 OK 0 PASS: Triage-2026-11-01.json re-derives 8/8 items from seed evidence; decision_counts={'approve': 6, 'table': 2}, categories={'archive_fix': 5, 'app_pr': 1, 'ge -
CHECK-untracked-triad-2026-11-01 1 7.0 FAULT 0 - id=20 path=wizard-work/null/.hermes-tmp.RqZp3z is not currently untracked -
CHECK-untracked-triage-2026-11-01 1 0.18 FAULT 0 - frozen path missing on disk: ['wizard-work/null/.hermes-tmp.RqZp3z'] -
1 entry rc secs class traceback last_stdout last_stderr
2 CHECK 0 2.3 OK 0 verify_selftest_sweep_q93_refactor: ALL GREEN (0 failed, all checks) -
3 CHECK-2026-11-01-ledger-dir-census 0 1.67 OK 0 VERDICT: rc 0 -- the committed CSV is the derivation at the pinned rev -
4 CHECK-2026-11-02-openmeteo-summary 0 0.19 OK 0 PASS: 6 rows match source-derived table; header exact -
5 CHECK-2026-11-02-untracked-classify 0 1.24 OK 0 CHECK OK: 306 pinned paths; manifest==snapshot in order; categories re-derive by rule; rule agrees with the generator; no pinned path was tracked at 4a640e1 -
6 CHECK-ledger-dir-census 0 2.28 OK 0 VERDICT: rc 0 -- the committed CSV is the derivation at the pinned rev -
7 CHECK-q-checkparen 1 2.0 FAULT 0 verify_fix: 3 leg(s) faulted -
8 CHECK-q143 1 31.17 FAULT 0 q143: 2 leg(s), 1 fault(s) -
9 CHECK-q146 0 2.79 OK 0 q146: 4 leg(s), no fault -
10 CHECK-q147 0 5.33 OK 0 q147: 4 of 4 leg(s) passed -
11 CHECK-q148 1 24.26 FAULT 0 q148: 4 of 5 leg(s) passed -
12 CHECK-q149 1 107.43 FAULT 0 q149: 5 of 6 leg(s) passed -
13 CHECK-q150 1 47.26 FAULT 0 q150: 6 leg(s), 2 fault(s) -
14 CHECK-q151 0 12.33 OK 0 q151: 3 leg(s), all passed -
15 CHECK-q152 0 31.81 OK 0 q152: 4 leg(s), all passed -
16 CHECK-q153 1 68.72 FAULT 0 q153: 2 leg(s), 1 fault(s) -
17 CHECK-q154 0 14.47 OK 0 CHECK-q154: 5 leg(s) passed, 0 fault(s), 0 ungradable -
18 CHECK-q155 0 7.16 OK 0 q155: 3 leg(s), all passed -
19 CHECK-q156 0 63.19 OK 0 q156: 6 leg(s), all passed -
20 CHECK-q157 0 2.74 OK 0 q157: 6 leg(s), all passed -
21 CHECK-q158 0 4.17 OK 0 CHECK-q158: 6 leg(s) passed, 0 fault(s), 0 ungradable -
22 CHECK-q159 1 4.05 FAULT 0 q159: 2 passed, 3 fault(s) -
23 CHECK-q85 1 69.59 FAULT 0 q85: 3 leg(s) passed, 2 fault(s), 0 ungradable -
24 CHECK-quill-draft-compliance 0 2.83 OK 0 CHECK-quill-draft-compliance: 5 leg(s) passed, 0 fault(s), 0 ungradable -
25 CHECK-sol-lane-triage-2026-10-29 0 2.84 OK 0 VERIFY OK (216 files, categories re-derived, all paths present) -
26 CHECK-sol-lane-triage-2026-11-01 0 4.62 OK 0 VERIFY OK (339 files, categories re-derived, all paths present) -
27 CHECK-sol-lane-triage-2026-11-02 0 6.67 OK 0 VERIFY OK (382 files, categories re-derived, all paths present) -
28 CHECK-sol-profile-triage-2026-11-02 1 0.4 FAULT 0 - categories mismatch: artifact={'identity': 2, 'config': 3, 'state_db': 11, 'soul': 1, 'script': 20, 'cache': 3, 'backups': 1, 'extension_dir': 18, 'config_dat -
29 CHECK-sol-untracked-classify 1 0.2 FAULT 0 - frozen path not present under repo: 'wizard-work/null/.hermes-tmp.RqZp3z' -
30 CHECK-triage-2026-10-29 0 0.17 OK 0 PASS: Triage-2026-10-29.json re-derives 8/8 items from evidence; decision_counts={'approve': 6, 'table': 2, 'reject': 0}, categories={'archive_fix': 5, 'app_pr' -
31 CHECK-triage-2026-11-01 0 0.24 OK 0 PASS: Triage-2026-11-01.json re-derives 8/8 items from seed evidence; decision_counts={'approve': 6, 'table': 2}, categories={'archive_fix': 5, 'app_pr': 1, 'ge -
32 CHECK-untracked-triad-2026-11-01 1 7.0 FAULT 0 - id=20 path=wizard-work/null/.hermes-tmp.RqZp3z is not currently untracked -
33 CHECK-untracked-triage-2026-11-01 1 0.18 FAULT 0 - frozen path missing on disk: ['wizard-work/null/.hermes-tmp.RqZp3z'] -
@@ -0,0 +1,107 @@
#!/usr/bin/env python3
"""sensitivity_probe.py -- prove the sweep verifier can print a red.
A verifier that has only ever printed PASS is not evidence: it may be a print
statement with a five-leg shape. This probe mutates a copy of the artifact in
three independent places -- a class label, a pinned sha256, a stated count --
and requires `check-root-sweep.sh` to exit 1 and name the leg that owns the
mutated field. Every mutation is restored from a pristine copy, and the last
assertion is that the restored artifact is green again.
Run: python3 sensitivity_probe.py (exit 0 = all three mutations reddened the
leg that owns them and the restore is green)
"""
from __future__ import annotations
import json
import os
import shutil
import subprocess
import sys
import tempfile
ART = os.path.dirname(os.path.abspath(__file__))
ROOT = subprocess.run(["git", "-C", ART, "rev-parse", "--show-toplevel"],
capture_output=True, text=True).stdout.strip()
CHECK = os.path.join(ROOT, "check-root-sweep.sh")
FILES = ["results.tsv", "manifest.json", "report.md"]
def run_check() -> tuple[int, str]:
p = subprocess.run(["bash", CHECK], capture_output=True, text=True,
errors="replace")
return p.returncode, p.stdout + p.stderr
def leg_line(out: str, leg: str) -> str:
for line in out.splitlines():
if line.strip().startswith(leg + " "):
return line.strip()
return ""
def mutate(name: str, path: str, old: str, new: str) -> None:
text = open(path, encoding="utf-8").read()
if text.count(old) != 1:
raise SystemExit(f"{name}: mutation site occurs {text.count(old)}x, want 1")
open(path, "w", encoding="utf-8").write(text.replace(old, new))
def main() -> int:
pristine = tempfile.mkdtemp(prefix="sweep-pristine-")
for f in FILES:
shutil.copy2(os.path.join(ART, f), os.path.join(pristine, f))
rows = []
try:
# 1 -- a class label that contradicts its rc.
name = "class-label"
path = os.path.join(ART, "results.tsv")
first_ok = open(path, encoding="utf-8").read().splitlines()[1]
cols = first_ok.split("\t")
mutate(name, path, "\t".join(cols), "\t".join(
cols[:3] + ["FAULT"] + cols[4:]))
rc, out = run_check()
rows.append((name, "classes", rc, leg_line(out, "classes")))
shutil.copy2(os.path.join(pristine, "results.tsv"), path)
# 2 -- a pinned sha256 that no longer describes the file.
name = "pinned-sha"
mpath = os.path.join(ART, "manifest.json")
manifest = json.load(open(mpath, encoding="utf-8"))
good = manifest["entries"][0]["sha256"]
mutate(name, mpath, good, "0" * 64)
rc, out = run_check()
rows.append((name, "universe", rc, leg_line(out, "universe")))
shutil.copy2(os.path.join(pristine, "manifest.json"), mpath)
# 3 -- a stated count that disagrees with the rows file.
name = "report-count"
rpath = os.path.join(ART, "report.md")
mutate(name, rpath, f"- entry points run: **{len(manifest['entries'])}**",
f"- entry points run: **{len(manifest['entries']) - 1}**")
rc, out = run_check()
rows.append((name, "report", rc, leg_line(out, "report")))
shutil.copy2(os.path.join(pristine, "report.md"), rpath)
# 4 -- the restore: the artifact as shipped must be green again.
rc, out = run_check()
rows.append(("restored", "-", rc, out.strip().splitlines()[-1]))
finally:
shutil.rmtree(pristine, ignore_errors=True)
ok = True
for name, leg, rc, line in rows:
if name == "restored":
good = rc == 0
else:
good = rc == 1 and leg in line and "FAULT" in line
ok = ok and good
print(f" {name:<13} {'PASS' if good else 'FAULT'} rc={rc} {line}")
print(f"\nsensitivity: {sum(1 for r in rows if (r[0] == 'restored' and r[2] == 0) or (r[0] != 'restored' and r[2] == 1))}/4 cell(s) as expected")
return 0 if ok else 1
if __name__ == "__main__":
sys.exit(main())
+232
View File
@@ -0,0 +1,232 @@
#!/usr/bin/env python3
"""sweep.py -- run every root CHECK-* entry point and classify its exit code.
WHY
The repo gate (`tools/verify.py --fast`) runs a fixed set of legs; none of
them runs the committed `CHECK-*` entry points sitting at the repository
root. Each of those was written as a deliverable's own verification command,
so the question "does the tree still satisfy the checks it shipped with?"
has no answer from the gate. This sweep answers it by running each one under
the interpreter every caller in this tree uses (`bash <path>`) and
classifying the exit code against this repo's published contract:
rc 0 OK the check graded clean
rc 1 FAULT the check graded a fault (a real, reportable red)
rc 2 COULD_NOT_GRADE the check could not grade its subject
other UNEXPECTED a shell/driver error (126, 127, signal, ...)
timeout TIMEOUT killed after --timeout seconds
Nothing here is a stub: every row is a real process with a real exit code,
and stdout/stderr tails are the process's own bytes.
WHAT IS PINNED
A verdict is only worth the tree it was measured on, so every run writes
`manifest.json` beside its rows: the full HEAD sha and subject, the UTC
timestamp, the timeout, and the sha256 of every swept entry-point file, plus
a flag for whether that path exists at HEAD. The report prints the same rev.
The bytes that were run are therefore recoverable, not implied.
An interrupted run is partial evidence, not no evidence: rows are flushed as
they finish, so a sweep killed at the wall clock leaves every completed row.
USAGE
python3 sweep.py --out <dir> [--repo <path>] [--timeout 300] [--json]
Writes <dir>/results.tsv, <dir>/manifest.json and <dir>/report.md, and
prints one summary line. Exit code of the sweep itself: 0 if every row
graded 0, 1 if any row graded 1 or worse, 2 if the sweep could not run (no
entry points found, or a manifest could not be captured).
"""
from __future__ import annotations
import argparse
import datetime as _dt
import glob
import hashlib
import json
import os
import subprocess
import sys
import time
CLASS = {0: "OK", 1: "FAULT", 2: "COULD_NOT_GRADE"}
def discover(repo: str) -> list[str]:
rows = []
for path in sorted(glob.glob(os.path.join(repo, "CHECK*"))):
if os.path.isfile(path):
rows.append(os.path.basename(path))
return rows
def tail(text: str, limit: int = 160) -> str:
text = (text or "").strip().replace("\t", " ").replace("\r", " ")
lines = [ln for ln in text.splitlines() if ln.strip()]
if not lines:
return "-"
return lines[-1].strip()[:limit]
def run_one(repo: str, name: str, timeout: int) -> dict:
started = time.time()
try:
proc = subprocess.run(
["bash", name],
cwd=repo,
capture_output=True,
text=True,
timeout=timeout,
errors="replace",
)
rc, out, err = proc.returncode, proc.stdout, proc.stderr
except subprocess.TimeoutExpired as exc:
rc = "timeout"
out = (exc.stdout or "") if isinstance(exc.stdout, str) else ""
err = (exc.stderr or "") if isinstance(exc.stderr, str) else ""
secs = round(time.time() - started, 2)
klass = "TIMEOUT" if rc == "timeout" else CLASS.get(rc, "UNEXPECTED")
return {
"name": name,
"rc": rc,
"secs": secs,
"class": klass,
"last_out": tail(out),
"last_err": tail(err),
"traceback": "Traceback (most recent call last)" in (err or ""),
}
def git_out(repo: str, *args: str) -> str:
try:
p = subprocess.run(["git", "-C", repo, *args], capture_output=True,
text=True, timeout=30, errors="replace")
except (OSError, subprocess.SubprocessError):
return ""
return p.stdout.strip() if p.returncode == 0 else ""
def sha256_file(path: str) -> str:
h = hashlib.sha256()
with open(path, "rb") as fh:
for chunk in iter(lambda: fh.read(1 << 20), b""):
h.update(chunk)
return h.hexdigest()
def capture_manifest(repo: str, names: list[str], timeout: int) -> dict:
rev = git_out(repo, "rev-parse", "HEAD")
if len(rev) != 40:
raise RuntimeError(f"cannot resolve HEAD in {repo!r}")
subject = git_out(repo, "log", "-1", "--format=%s", "HEAD")
tracked = set(git_out(repo, "ls-tree", "-r", "--name-only", "HEAD")
.splitlines())
entries = []
for name in names:
path = os.path.join(repo, name)
entries.append({
"name": name,
"sha256": sha256_file(path),
"bytes": os.path.getsize(path),
"tracked_at_rev": name in tracked,
})
dirty = [ln for ln in git_out(repo, "status", "--porcelain").splitlines()
if ln.strip()]
return {
"tool": "wizard-work/volt/root-check-sweep/sweep.py",
"generated_utc": _dt.datetime.now(_dt.timezone.utc)
.strftime("%Y-%m-%dT%H:%M:%SZ"),
"repo": os.path.basename(repo.rstrip("/")),
"rev": rev,
"rev_subject": subject,
"worktree_dirty_paths": len(dirty),
"timeout_s": timeout,
"entry_count": len(entries),
"entries": entries,
}
def main(argv: list[str] | None = None) -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--repo", default=os.path.dirname(os.path.abspath(__file__)))
ap.add_argument("--out", required=True)
ap.add_argument("--timeout", type=int, default=300)
ap.add_argument("--json", action="store_true")
args = ap.parse_args(argv)
repo = os.path.abspath(args.repo)
names = discover(repo)
if not names:
print(f"sweep: no CHECK* entry points under {repo}")
return 2
try:
manifest = capture_manifest(repo, names, args.timeout)
except (OSError, RuntimeError) as exc:
print(f"sweep: cannot capture manifest: {exc}", file=sys.stderr)
return 2
rows: list[dict] = []
os.makedirs(args.out, exist_ok=True)
tsv = os.path.join(args.out, "results.tsv")
with open(tsv, "w", encoding="utf-8") as fh:
fh.write("entry\trc\tsecs\tclass\ttraceback\tlast_stdout\tlast_stderr\n")
fh.flush()
for name in names:
r = run_one(repo, name, args.timeout)
rows.append(r)
fh.write(
f"{r['name']}\t{r['rc']}\t{r['secs']}\t{r['class']}\t"
f"{int(r['traceback'])}\t{r['last_out']}\t{r['last_err']}\n"
)
fh.flush()
print(f" {r['class']:<16} rc={r['rc']:<8} {r['secs']:>7.2f}s {r['name']}",
flush=True)
counts: dict[str, int] = {}
for r in rows:
counts[r["class"]] = counts.get(r["class"], 0) + 1
bad = [r for r in rows if r["class"] != "OK"]
manifest["results_sha256"] = sha256_file(tsv)
manifest["counts"] = dict(sorted(counts.items()))
with open(os.path.join(args.out, "manifest.json"), "w", encoding="utf-8") as fh:
json.dump(manifest, fh, indent=2, sort_keys=True)
fh.write("\n")
report = os.path.join(args.out, "report.md")
with open(report, "w", encoding="utf-8") as fh:
fh.write("# Root CHECK-* entry-point sweep\n\n")
fh.write(f"- measured at: `{manifest['generated_utc']}`\n")
fh.write(f"- rev: `{manifest['rev']}` -- {manifest['rev_subject']}\n")
fh.write(f"- worktree: {manifest['worktree_dirty_paths']} path(s) differ "
f"from that rev (modified + untracked); the worktree is what "
f"was graded\n")
fh.write(f"- entry points run: **{len(rows)}**\n")
for k in sorted(counts):
fh.write(f"- {k}: **{counts[k]}**\n")
fh.write(f"- total wall time: **{round(sum(r['secs'] for r in rows), 1)} s**\n\n")
fh.write("| entry | rc | s | class | last line |\n|---|---|---|---|---|\n")
for r in rows:
last = r["last_err"] if r["last_err"] != "-" else r["last_out"]
fh.write(
f"| `{r['name']}` | {r['rc']} | {r['secs']} | {r['class']} | "
f"{last.replace('|', '/')} |\n"
)
if bad:
fh.write("\n## Not OK\n\n")
for r in bad:
fh.write(f"- `{r['name']}` rc={r['rc']} ({r['class']}): "
f"{r['last_err'] if r['last_err'] != '-' else r['last_out']}\n")
if args.json:
print(json.dumps({"manifest": manifest, "rows": rows}, indent=2))
else:
detail = ", ".join(f"{k} {counts[k]}" for k in sorted(counts))
print(f"sweep: {len(rows)} entry point(s) -- {detail} "
f"({round(sum(r['secs'] for r in rows), 1)} s) at {manifest['rev'][:12]}")
return 0 if not bad else 1
if __name__ == "__main__":
sys.exit(main())
@@ -0,0 +1,204 @@
#!/usr/bin/env python3
"""verify_sweep.py -- grade the root CHECK-* sweep artifact against itself.
WHAT THIS IS
`sweep.py` runs every root `CHECK-*` entry point and classifies its exit
code. Its verdict is only worth the bytes it measured, so this verifier
grades the artifact, not the repository: the pin (rev, timestamp, timeout),
the universe (which entry points, and their sha256), the class mapping
(rc -> class, the repo's published contract), the report (one table row per
entry, counts and rev stated), and the integrity of the row file itself.
It does NOT re-run the entry points -- that is the sweep's job and it costs
minutes. It answers "is this artifact a faithful record of a run over the
universe it names", which is the question a reader of a table actually has.
EXIT
0 every leg passed; 1 a fault; 2 the artifact is not there to grade.
"""
from __future__ import annotations
import datetime as _dt
import hashlib
import json
import os
import re
import subprocess
import sys
ART = os.path.dirname(os.path.abspath(__file__))
MANIFEST = os.path.join(ART, "manifest.json")
RESULTS = os.path.join(ART, "results.tsv")
REPORT = os.path.join(ART, "report.md")
CLASS = {0: "OK", 1: "FAULT", 2: "COULD_NOT_GRADE"}
HEX40 = re.compile(r"^[0-9a-f]{40}$")
UTC = re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$")
passed = 0
faults: list[str] = []
def leg(name: str, problems: list[str], detail: str) -> None:
global passed
if problems:
print(f" {name:<10} FAULT {'; '.join(problems[:4])}")
faults.extend(problems)
else:
print(f" {name:<10} PASS {detail}")
passed += 1
def sha256_file(path: str) -> str:
h = hashlib.sha256()
with open(path, "rb") as fh:
for chunk in iter(lambda: fh.read(1 << 20), b""):
h.update(chunk)
return h.hexdigest()
def git(*args: str) -> str:
p = subprocess.run(["git", "-C", ART, *args], capture_output=True,
text=True, errors="replace")
return p.stdout.strip() if p.returncode == 0 else ""
def git_ok(*args: str) -> bool:
p = subprocess.run(["git", "-C", ART, *args], capture_output=True,
text=True, errors="replace")
return p.returncode == 0
def read_rows() -> list[dict]:
rows = []
with open(RESULTS, encoding="utf-8") as fh:
header = fh.readline().rstrip("\n").split("\t")
want = ["entry", "rc", "secs", "class", "traceback",
"last_stdout", "last_stderr"]
if header != want:
raise SystemExit(f"results.tsv header {header!r} != {want!r}")
for line in fh:
parts = line.rstrip("\n").split("\t")
if len(parts) != 7:
raise SystemExit(f"results.tsv row has {len(parts)} fields: {line!r}")
rows.append(dict(zip(want, parts)))
return rows
def main() -> int:
for path in (MANIFEST, RESULTS, REPORT):
if not os.path.isfile(path):
print(f"verify_sweep: no {path} -- cannot grade", file=sys.stderr)
return 2
manifest = json.load(open(MANIFEST, encoding="utf-8"))
rows = read_rows()
report = open(REPORT, encoding="utf-8").read()
# 1 -- the pin: a full rev that resolves, a real UTC stamp, a coherent count.
problems = []
rev = str(manifest.get("rev", ""))
if not HEX40.match(rev):
problems.append(f"rev is not a full 40-hex sha: {rev!r}")
elif not git_ok("cat-file", "-e", f"{rev}^{{commit}}"):
problems.append(f"rev {rev} does not resolve in this repo")
stamp = str(manifest.get("generated_utc", ""))
if not UTC.match(stamp):
problems.append(f"generated_utc is not YYYY-MM-DDTHH:MM:SSZ: {stamp!r}")
else:
try:
_dt.datetime.fromisoformat(stamp.replace("Z", "+00:00"))
except ValueError:
problems.append(f"generated_utc does not parse: {stamp!r}")
entries = manifest.get("entries") or []
if manifest.get("entry_count") != len(entries):
problems.append(f"entry_count {manifest.get('entry_count')} != "
f"{len(entries)} manifest entries")
if len(entries) != len(rows):
problems.append(f"manifest names {len(entries)} entries, results has {len(rows)} rows")
if not isinstance(manifest.get("timeout_s"), int) or manifest["timeout_s"] <= 0:
problems.append(f"timeout_s is not a positive int: {manifest.get('timeout_s')!r}")
leg("pin", problems, f"{len(rows)} rows at {rev[:12]} {stamp}")
# 2 -- the universe: same names, same order, same bytes, same trackedness.
problems = []
names = [r["entry"] for r in rows]
if names != [e.get("name") for e in entries]:
problems.append("results row order/names differ from manifest entries")
root = git("rev-parse", "--show-toplevel") or os.path.dirname(ART)
tracked = set(git("ls-tree", "-r", "--full-tree", "--name-only", rev).splitlines()) if HEX40.match(rev) else set()
for e in entries:
path = os.path.join(root, e.get("name", ""))
if not os.path.isfile(path):
problems.append(f"{e.get('name')}: file absent")
continue
if sha256_file(path) != e.get("sha256"):
problems.append(f"{e.get('name')}: sha256 moved since the sweep")
if bool(e.get("tracked_at_rev")) != (e.get("name") in tracked):
problems.append(f"{e.get('name')}: tracked_at_rev disagrees with ls-tree {rev[:8]}")
leg("universe", problems, f"{len(entries)} entry files byte-identical to the manifest pin")
# 3 -- the class mapping: rc -> class is the contract, not a label.
problems = []
for r in rows:
try:
rc = int(r["rc"])
except ValueError:
problems.append(f"{r['entry']}: rc {r['rc']!r} is not an int")
continue
want = CLASS.get(rc, "UNEXPECTED")
if r["class"] != want:
problems.append(f"{r['entry']}: rc {rc} labelled {r['class']}, contract says {want}")
if r["traceback"] not in ("0", "1"):
problems.append(f"{r['entry']}: traceback flag {r['traceback']!r}")
try:
if float(r["secs"]) < 0:
problems.append(f"{r['entry']}: negative seconds")
except ValueError:
problems.append(f"{r['entry']}: secs {r['secs']!r}")
leg("classes", problems, "every rc maps to its class under the published contract")
# 4 -- the report: one table row per entry, counts and rev as measured.
problems = []
counts: dict[str, int] = {}
for r in rows:
counts[r["class"]] = counts.get(r["class"], 0) + 1
table = re.findall(r"^\| `([^`]+)` \| ([^|]+?) \| ([^|]+?) \| ([A-Z_]+) \|", report, re.M)
if [t[0] for t in table] != names:
problems.append(f"report table names {len(table)} rows, results has {len(names)}")
if f"- entry points run: **{len(rows)}**" not in report:
problems.append("report does not state entry points run")
for klass, count in counts.items():
if f"- {klass}: **{count}**" not in report:
problems.append(f"report does not state {klass} count {count}")
if rev and rev not in report:
problems.append("report does not name the pinned rev")
leg("report", problems, f"{len(table)} table rows, counts and rev agree with the rows file")
# 5 -- substance: the rows file is the file the manifest hashed and no row
# is silent, so a green row is a process that said something.
problems = []
if sha256_file(RESULTS) != manifest.get("results_sha256"):
problems.append("results.tsv sha256 differs from the manifest")
for r in rows:
if r["class"] in ("OK", "FAULT") and r["last_stdout"].strip() in ("", "-") \
and r["last_stderr"].strip() in ("", "-"):
problems.append(f"{r['entry']}: {r['class']} row carries no output at all")
bad = sorted(r["entry"] for r in rows if r["class"] != "OK")
bullets = re.findall(r"^- `([^`]+)` rc=", report, re.M)
if sorted(bullets) != bad:
problems.append(f"Not-OK bullets {sorted(bullets)} != rows {bad}")
if not any(r["class"] == "OK" for r in rows):
problems.append("no OK row -- a sweep that cannot pass anything is not evidence")
leg("substance", problems, f"{len(bad)} non-OK row(s) enumerated, every row carries output")
print()
if faults:
print(f"sweep-check: {passed} passed, {len(faults)} fault(s)")
return 1
print(f"sweep-check: 5 leg(s), all passed")
return 0
if __name__ == "__main__":
sys.exit(main())