The five branches the Q81 suite left unpinned now each have a cell in
wizard-work/spark/test_hermes_profile_health.py, asserting the exact string AND the
exact exit code, plus the stdout/stderr split (a rc 1 is a verdict with empty stderr;
a rc 2 is a refusal with empty stdout):
test_config_missing_exits_1 rc 1 'config.yaml missing'
test_config_as_directory_exits_1 rc 1 'config.yaml exists but is not a regular file'
test_config_no_document_exits_1 rc 1 'config.yaml parses to no document'
test_config_empty_mapping_exits_1 rc 1 'config.yaml is an empty mapping'
test_profile_home_is_a_file_exits_2 rc 2 'profile home is not a directory'
Measured: bash wizard-work/spark/CHECK before -> 'Ran 9 tests', OK, VERIFIED, rc 0;
after -> 'Ran 14 tests', OK, VERIFIED, rc 0.
Mutant battery (q83_mutants.py, q83-mutants.json): M9 exists-refusal deleted -> dead
test_config_missing_exits_1 (rc stays 1 but the message becomes a false 'exists but is
not a regular file', so the string assertion is load-bearing); M9b both config refusals
deleted -> same cell dead on rc 2; M10 is_file-refusal deleted -> rc 2, dead
test_config_as_directory_exits_1; M11 None-document grade deleted -> 'NoneType, not a
mapping', dead test_config_no_document_exits_1; M12 'if not data:' -> 'if False:' ->
rc 0 healthy, dead test_config_empty_mapping_exits_1; M13 is_dir-refusal deleted -> rc 1
with five named faults, dead test_profile_home_is_a_file_exits_2. Baseline copy: rc 0,
Ran 14, 0 dead. hermes_profile_health.py is not touched.
Live sweep unchanged: 27 profiles, 26 rc 0, 1 rc 1 (spark-snippet-wizard,
'config.yaml missing').
- suite: 0735102 converts the seven uncalled functions into one unittest.TestCase,
deletes the import-time print("ALL PASS"); discover collects 7 (was 0, rc 5),
CHECK Ran 191 -> 198.
- mutant battery (scratch/q82/battery.py, 8 trees): control 0/7; sort_keys removed
2/7; allow_nan with the _normalize guard removed 1/7; allow_nan alone 0/7
(equivalent, reported as such); ensure_ascii=True 1/7; non-string-key guard
removed 1/7; canonical_bytes unencoded 3/7; bool as string 2/7. 7 of 7 cells
have a named killer.
- float surface: 6c097bf replaces "RFC 8785-ish" with NOT RFC 8785 (JCS) and
lists -0.0 / 1e-06 / 2**53+1 against RFC 8785 Table 1, each measured at that
commit. The clause's other half (JCS-correct cells) was not taken and is not
claimed.
- gate: python3 tools/verify.py -> rc 0, 8 of 8 legs pass, 0 fault, 0 ungradable.
CHECK: bash wizard-work/beam/CHECK && python3 tools/queue_index.py --check docs/queue-index.md
- the docstring said "RFC 8785-ish"; it now says NOT RFC 8785 (JCS) in those
words, because the hedge only holds if the three readings are written down.
- measured at this file (scratch/q82/floats.py, output in the closure record):
-0.0 -> "-0.0" where RFC 8785 Table 1 gives "0"; 1e-06 -> "1e-06" where the
table gives "0.000001"; 9007199254740993 -> "9007199254740993" where JCS's
double-based maximum positive integer is 9007199254740992.
- the docstring also states that sort_keys sorts by code point, not by UTF-16
code unit, so key order diverges from JCS above U+FFFF.
- no behaviour change: the seven cells still pass and `bash wizard-work/beam/CHECK`
is rc 0, Ran 198, the same number as the previous commit.
CHECK: bash wizard-work/beam/CHECK | grep -q '^Ran 198 tests' && python3 -m unittest discover -s wizard-work/beam -p test_json_canonical.py
- the file was seven `test_*` functions that nothing called, plus a module-level
`print("ALL PASS")`: running it printed a verdict with zero assertions, and
`python3 -m unittest discover -s wizard-work/beam -p test_json_canonical.py`
collected 0 (rc 5, NO TESTS RAN) while the import still printed ALL PASS.
- the seven cells are now methods of one `unittest.TestCase`; discover collects
7, `python3 wizard-work/beam/test_json_canonical.py` runs 7 OK, and
`bash wizard-work/beam/CHECK` moves Ran 191 -> Ran 198, rc 0, OK.
- the ALL PASS print is deleted; there is no module-level verdict on import.
- cells bite, measured against a mutant battery (harness
/root/.hermes/profiles/volt/cache/scratch/q82/battery.py, rows in
mutant_results.json, one tree per mutant under .../q82/mut/). Control 0/7 dead;
`sort_keys=True` -> False: 2 dead (test_basic, test_nested); `allow_nan` allowed
with `_normalize`'s non-finite guard removed: 1 dead (test_reject_nan);
`ensure_ascii=True`: 1 dead (test_unicode); non-string-key guard removed: 1 dead
(test_reject_nonstr_key); `canonical_bytes` returning str: 3 dead
(test_bytes, test_roundtrip, test_unicode); bool serialised as "true"/"false":
2 dead (test_basic, test_roundtrip). All 7 cells have a named killer.
- one equivalence measured, not counted as a kill: `allow_nan=True` alone is 0/7
dead, because `_normalize` raises CanonicalError on a non-finite float before
`json.dumps` is reached. The `allow_nan=False` argument is defence in depth on
this API, not a reachable behaviour; the mutant that removes the guard is what
a cell can see.
CHECK: bash wizard-work/beam/CHECK
Closure block appended at the foot; docs/queue-index.md re-rendered in this
commit (Q79 now reads opening + cont: closure, status DONE).
CHECK: bash wizard-work/beam/CHECK && python3 tools/verify.py --repo .
Seventeen unittest.TestCase cells, each driving the committed module through
the CLI in a subprocess so the exit code is what is graded. MOD resolves from
this file's own directory, not a host path.
Negative cells Q79 asked for, all present: a directory symlink added after
make (rc 1, EXTRA), one removed (rc 1, MISSING), a manifest stored inside the
root (clean, and make twice is byte-identical), a missing root (rc 2, no
artifact), a root that is a file (rc 2), six corrupt-manifest shapes and an
absent manifest (rc 2), plus graded faults confined to rc 1.
Bite measured, not asserted: the same suite against edac5cf's manifest.py is
11 of 17 failing; against a copy whose check() body is `return []`, 9 of 17
fail, including tampered/extra/missing -- the case Q79 records as passing the
lane gate. `bash wizard-work/beam/CHECK` -> Ran 191 tests, OK, rc 0.
CHECK: python3 wizard-work/beam/test_manifest.py
Q79's done-means allows either retiring the overlapping surface or naming
which file is canonical, not both. Retiring sha256_manifest.py would break
test_sha256_manifest.py and the reply-01..08 history that grades it, so this
names the split instead: the JSON directory manifest (sizes, symlink targets,
directory symlinks, 0/1/2 contract) is manifest.py; the plain
`digest path` text shape stays in sha256_manifest.py. One docstring, no
behaviour change.
CHECK: python3 -m unittest discover -s wizard-work/beam -p 'test_sha256*.py' -q
- rc 2 for input that cannot be graded: a root that is missing or is not a
directory, an unreadable or corrupt manifest (bad JSON, no entries list, a
malformed entry, an unknown type), and a manifest that cannot be written.
rc 1 is reserved for a graded fault, rc 0 for a clean check.
- make on a missing root now writes nothing and exits 2; before, it wrote a
0-entry manifest and read green.
- _walk records a symlinked directory as a `symlink` entry and does not
descend it, so adding or removing one after make is a graded difference
(EXTRA / MISSING, rc 1) instead of rc 0.
- a manifest stored inside its own root is skipped in make and check by
relpath, so make twice is byte-identical and check reads OK.
- a root it cannot read (OSError from os.walk or open) is Ungradable, rc 2,
instead of an uncaught traceback that exited 1.
CHECK: python3 wizard-work/beam/manifest.py make /root/troupe-standup/wizard-work/beam /tmp/q79-manifest.json && python3 wizard-work/beam/manifest.py check /root/troupe-standup/wizard-work/beam /tmp/q79-manifest.json