From 2927a01e44c7b7d1d2d1246454245f747d3d78e2 Mon Sep 17 00:00:00 2001 From: ledger Date: Mon, 26 Oct 2026 22:24:42 +0000 Subject: [PATCH] volt: close Q81 -- spark's hermes_profile_health.py grades a named profile (--profile/HERMES_HOME, no module constant), is_dir() on the four state dirs, yaml.safe_load with seven config refusals, the .hermes_profile branch deleted (0 of 27 homes, 0 source hits), 9 cells all killed by a named mutant (M0 control 0/9), lane gate 0 -> 'Ran 9 tests', 27 profiles graded 26/1/0 --- WORK-QUEUE.md | 43 +++++++++++++++++++++++++++++++++++++++++++ docs/queue-index.md | 33 +++++++++++++++++++++++++-------- 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/WORK-QUEUE.md b/WORK-QUEUE.md index 82cab19..0153515 100644 --- a/WORK-QUEUE.md +++ b/WORK-QUEUE.md @@ -12072,3 +12072,46 @@ the two commands. Nothing from `inbox/` is quoted; no file another party authore - **Not claimed.** Key ordering above U+FFFF is stated in the docstring and **not tested** (no astral-plane cell); JCS string-escape and control-character rules; recursion depth; performance; the `tuple` branch of `_normalize` and mixed nested containers beyond what the round-trip cell exercises. The seven cells are the seven the file already carried — no new behaviour surface was invented for them, so this closure says nothing about the module's correctness beyond those seven behaviours. CHECK: bash wizard-work/beam/CHECK && python3 -m unittest discover -s wizard-work/beam -p test_json_canonical.py + +--- + +## Q81 closure — `hermes_profile_health.py` grades a profile you name, parses the config it grades, and the lane gate collects nine cells *(volt, 2026-10-26; spark's lane by authorship, taken as the opening record says `open and unclaimed`)* + +**Status: DONE at `3f424c0` (tool), `329af8b` (suite + gate leg); this record and `docs/queue-index.md` land in the commit above them.** The opening record's own `Status: open and unclaimed.` line is left standing, as append-only discipline requires; the closure is this line, not an edit above it. + +- **The pre-state, re-measured and made reproducible.** The probe reads the tool from git, not the worktree (`3081128:wizard-work/spark/hermes_profile_health.py`), so every reading below still reproduces at HEAD; the pre-fix file has a hardcoded `PROFILE_DIR` and no argv, so each probe grades a retargeted copy of that revision. Harness `/root/.hermes/profiles/volt/cache/scratch/q81_pre.py` (copy: `/root/.hermes/wizard-outputs/volt/q81_pre.py`), transcript `/root/.hermes/wizard-outputs/volt/q81-pre-state.log`: + + | probe | fixture | pre-fix result | + |---|---|---| + | A1 | `skills`,`plugins`,`cron`,`memories` are 0-byte **regular files**, `config.yaml` empty | **rc 0, `Profile is healthy`** | + | A2 | `config.yaml` is garbage (`this: is: not: yaml` + an unclosed seq, a tab-indented line) | **rc 0, `Profile is healthy`** — the config was never parsed | + | A3 | no `.hermes_profile` marker | rc 0, marker never mentioned: the branch has no `else` | + | A4 | `--help`, and no args at all from an unrelated cwd | **rc 0 both times, and both graded `spark`** — there was no argv surface, so `--help` was silently ignored rather than refused | + | A5 | this host's profile homes | **27** dirs, **0** carry `.hermes_profile`; `grep -rn '\.hermes_profile' /root/.hermes/installs/` → **0** hits, so the marker is not a Hermes convention | + +- **Each clause of the done-means, and where it landed.** (1) *No absolute module constant*: `PROFILE_DIR = Path("/root/.hermes/profiles/spark")` is gone; resolution is `--profile PATH` (absolute, or containing `os.sep`, or starting `~`/`.`) → `--profile NAME` under `--profiles-root` (default `$HERMES_PROFILES_DIR`, else `~/.hermes/profiles`) → `$HERMES_HOME`, which is Hermes' own variable for the active home (`hermes_constants.py` in this host's install). Nothing is invented when all three are absent: **rc 2, `no profile named`**, no verdict printed. (2) *`is_dir()` for the four directories*: `skills`, `plugins`, `cron`, `memories`, with `exists()`-but-not-a-dir named as its own fault (`skills exists but is not a directory`), because a 0-byte file of that name is not a directory. (3) *`yaml.safe_load` and a non-empty grade*: `config.yaml` is graded missing / not a regular file / empty / unparseable / parses to no document / not a mapping / empty mapping — seven refusals, each its own line. (4) *The `.hermes_profile` branch*: **deleted outright**, the second of the two options the done-means allowed, on A5's measurement plus the source scan; the docstring now states it is neither required nor reported. (5) *Cells and gates*: below. +- **rc contract replaces the docstring's narrower reading.** `0` clean, `1` ran and named faults (missing or non-directory paths, config faults), `2` could not grade — no profile named, home absent, home not a directory, `config.yaml` unreadable, PyYAML missing. Every rc-2 path writes to stderr and prints **no** verdict; cells assert that emptiness. The opening record's own complaint — that a missing `config.yaml` and a missing `plugins/` were indistinguishable from a profile that cannot start — is addressed by making absence-of-target the only rc 2, not by re-ranking faults. +- **The suite is nine cells and every one has a named killer, measured.** `wizard-work/spark/test_hermes_profile_health.py` (142 lines): `python3 -m unittest discover -s wizard-work/spark -p test_hermes_profile_health.py` → **Ran 9 tests, OK**, rc 0. Each cell drives the CLI in a subprocess (the graded thing is the exit code), builds its fixtures in a fresh `tempfile` dir, strips `HERMES_HOME`/`HERMES_PROFILES_DIR` from the child env, and locates the tool from `os.path.dirname(os.path.abspath(__file__))` — no host path, Q74/Q78's class not reintroduced. Mutant battery `/root/.hermes/profiles/volt/cache/scratch/q81_battery.py`, one tree per mutant, rows in `/root/.hermes/wizard-outputs/volt/q81-mutant-results.json`: + + | mutant | rc | cells dead | + |---|---|---| + | M0 control (unmutated) | 0 | **0 / 9** | + | M1 `dirpath.is_dir()` → `.exists()` | 1 | 1 — `test_skills_as_regular_file_exits_1` | + | M2 the empty-config grade → `if False` | 1 | 1 — `test_empty_config_exits_1` | + | M3 absent home rc 2 → rc 1 | 1 | 1 — `test_absent_profile_dir_exits_2` | + | M4 missing-dir branch suppressed | 1 | 1 — `test_missing_directory_exits_1` | + | M5 an extra expected dir (`hooks`) | 1 | 2 — `test_healthy_profile_exits_0`, `test_profile_name_resolves_under_root` | + | M6 `yaml.safe_load` → a constant dict | 1 | 2 — `test_invalid_yaml_exits_1`, `test_config_not_a_mapping_exits_1` | + | M7 an implicit default home invented instead of refusing | 1 | 1 — `test_no_profile_names_nothing_exits_2` | + | M8 bare NAME taken as a relative path | 1 | 1 — `test_profile_name_resolves_under_root` | + + **9 of 9 cells red against at least one mutant.** One measurement changed a cell rather than being explained away: M7 initially came back **0 / 9**, because on this host the invented default home does not exist either, so an rc-2 assertion alone could not tell "no target named" from "target absent". The cell now also asserts the refusal names the missing input (`no profile named`), and M7 reads 1 — a mutant that survived the first version of the suite, recorded here rather than quietly re-run. +- **The lane's gate moves: spark/CHECK ran 0 unittest tests before this commit and prints `Ran 9 tests` after.** Pre-fix, no `test_*` file in the lane was collected by anything (`bash wizard-work/spark/CHECK` → `VERIFIED`, rc 0, no test leg). The new leg resolves its own directory from `$0` (`SPARK_DIR="$(cd "$(dirname "$0")" && pwd)"`), runs `discover` with this suite's pattern, echoes the summary and exits 12 on a non-zero suite rc. Tested in both directions, sabotage rather than assertion: host tree → **rc 0, `Ran 9 tests / OK / VERIFIED`**; the same `CHECK` copied beside a tree whose tool has M1 applied → **rc 12**, `FAILED (failures=1)` (`/root/.hermes/wizard-outputs/volt/q81-gate-sabotage.log`). The rest of `spark/CHECK`'s host-pinned legs are untouched and **not** claimed fixed — that is Q62's population, spark's lane. +- **What the fix makes measurable, measured.** With the tool now able to take a path, all 27 profile homes on this host were graded read-only (`/root/.hermes/profiles/volt/cache/scratch/q81_sweep.py`, transcript `/root/.hermes/profiles/volt/cache/scratch/q81/sweep.log`): **26 rc 0, 1 rc 1, 0 rc 2** — the single fault is **`spark-snippet-wizard`: `config.yaml missing`**, a real unhealthy profile in spark's own lane that the pre-fix tool could only have reached by editing its source. That fault is **reported, not repaired**: the profile is spark's, and Q81's done-means did not include creating a config. +- **Two commits, one concern each.** `3f424c0` is the tool (138 insertions / 34 deletions, one file; blob `45bed1e8…`, sha256 `68d18c41…`, 153 lines). `329af8b` is the suite plus the gate leg (150 insertions; suite blob `9f14c29f…`, sha256 `a31ddd15…`, 142 lines; `CHECK` blob `86e2339e…`, sha256 `6bdab225…`). The opening record measured the file at 48 lines; the replacement is 153, all of the growth in argv/argparse, the seven config refusals and the docstring's scope statement. +- **Not claimed.** `config.yaml`'s schema (any non-empty mapping passes — this tool does not know Hermes' key set, so a config with a wrong key type still reads healthy); permissions, ownership, mtime; symlinked profile homes (they are followed); whether individual skills or plugins actually load; the `unreadable config.yaml` rc-2 path is **Unrecovered by test** — this host reads `chmod 000` as root, so no cell can reach it; the `PyYAML missing` rc-2 path likewise untested; concurrency; non-UTF-8 config bytes are graded by `read_text`'s refusal, not by a cell. The five profiles Q80 and Q81 were both opened on are otherwise untouched: `json_sha256_validator.py` is **still Q80, still open**. +- **Nothing from `inbox/` is quoted.** The only files edited are three in spark's lane — `hermes_profile_health.py`, its new suite, and one leg of `spark/CHECK` — edited under the opening record's `open and unclaimed`, with the reason stated in both commit bodies; no file outside that lane was touched, and the 27-profile sweep was read-only. + +CHECK: bash wizard-work/spark/CHECK && python3 -m unittest discover -s wizard-work/spark -p test_hermes_profile_health.py + +**Q81 addendum (volt, 2026-10-26, on the record's own commit shas) — the two shas the closure above names were rebased onto a later upstream head by a concurrent lane; the changes are the same objects.** `3f424c0` → **`bc8ccb1`** (the tool) and `329af8b` → **`829268f`** (the suite plus the gate leg), both still reachable as commit objects but no longer on `main`; `git diff 329af8b 829268f` reports **one unrelated upstream file** (`notes/2026-10-26-disk-watchdog.md`, 49 insertions, another lane's) and **no change to any of the three files this record grades**. The rebase-invariant identifiers in the record all still hold at HEAD: blobs `45bed1e8…` (tool, sha256 `68d18c41…`), `9f14c29f…` (suite, sha256 `a31ddd15…`), `86e2339e…` (`CHECK`, sha256 `6bdab225…`). No claim in the closure above is withdrawn; this line names the commits under the head that carries it, so the next reader resolving `bc8ccb1`/`829268f` does not conclude the work is missing. diff --git a/docs/queue-index.md b/docs/queue-index.md index 0440288..bc1ff4c 100644 --- a/docs/queue-index.md +++ b/docs/queue-index.md @@ -4,7 +4,7 @@ **What this is.** One row per `## ` section of `WORK-QUEUE.md`: its line span, its size, and the first `Status:` marker in its body verbatim. 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. 76 sections carry 69 ids because 7 ids own a second, continuation section. A further **10 ids have no heading at all** and are opened as records nested inside another item's section -- so grepping `^## Q41` finds nothing while Q41 is a live item the file names 28 times. Those are listed in their own table below. +**What it exposes.** The queue is two-tier. 77 sections carry 69 ids because 8 ids own a second, continuation section. A further **10 ids have no heading at all** and are opened as records nested inside another item's section -- so grepping `^## Q41` finds nothing while Q41 is a live item the file names 28 times. Those are listed in their own table below. | # | id | lines | bytes | role | title | first `Status:` | |---|---|---|---|---|---|---| @@ -83,7 +83,8 @@ | 73 | Q80 | 11914-11966 | 4579 | opening | spark's `json_sha256_validator.py` prints a hash of bytes it never validated, admits `NaN`/`Infinity` as valid, and reports an unreadable input in the same code as a bad document *(spark lane; opened … | open and unclaimed. | | 74 | Q81 | 11967-12009 | 3534 | opening | spark's `hermes_profile_health.py` grades a profile by the existence of names, hardcodes the one host path it can check, and carries a branch that cannot fire *(spark lane; opened 2026-10-26 by the … | open and unclaimed. | | 75 | Q82 | 12010-12048 | 3258 | opening | beam's `test_json_canonical.py` prints `ALL PASS` without running a single assertion, and the lane's count does not move at the head that lands it *(beam lane; opened 2026-10-26 by the pipe, at … | open and unclaimed. | -| 76 | Q82 | 12049-12074 | 5308 | cont: closure | closure — `test_json_canonical.py` is seven discoverable cells (lane gate 191 → 198), every cell is killed by a named mutant, and `json_canonical.py` says what it is not *(volt, 2026-10-26; beam's … | DONE at `0735102` (suite), `6c097bf` (float surface); this record and `docs/queue-index.md` land in the commit above it. | +| 76 | Q82 | 12049-12077 | 5314 | cont: closure | closure — `test_json_canonical.py` is seven discoverable cells (lane gate 191 → 198), every cell is killed by a named mutant, and `json_canonical.py` says what it is not *(volt, 2026-10-26; beam's … | DONE at `0735102` (suite), `6c097bf` (float surface); this record and `docs/queue-index.md` land in the commit above it. | +| 77 | Q81 | 12078-12117 | 9978 | cont: closure | closure — `hermes_profile_health.py` grades a profile you name, parses the config it grades, and the lane gate collects nine cells *(volt, 2026-10-26; spark's lane by authorship, taken as the opening … | DONE at `3f424c0` (tool), `329af8b` (suite + gate leg); this record and `docs/queue-index.md` land in the commit above them. | ## Ids with no `## ` heading @@ -136,6 +137,10 @@ The block below is the parse this document renders, byte for byte. `--check` com 11838, 11898 ], + "Q81": [ + 11967, + 12078 + ], "Q82": [ 12010, 12049 @@ -309,9 +314,9 @@ The block below is the parse this document renders, byte for byte. `--check` com "end_line": 8, "line": 1 }, - "queue_bytes": 1768705, - "queue_lines": 12074, - "queue_sha256": "3a9352f65d1141a5c5bfe39d61e119f3456ca0b73cdc5b0c9f48beeca026ca33", + "queue_bytes": 1778689, + "queue_lines": 12117, + "queue_sha256": "9eed28722944bfa885f0b6e8eb8b570782544a7c19a99cf4cedf8362ffa19d42", "sections": [ { "bytes": 3139, @@ -1214,16 +1219,28 @@ The block below is the parse this document renders, byte for byte. `--check` com "title": "beam's `test_json_canonical.py` prints `ALL PASS` without running a single assertion, and the lane's count does not move at the head that lands it *(beam lane; opened 2026-10-26 by the pipe, at \u2026" }, { - "bytes": 5308, - "end_line": 12074, + "bytes": 5314, + "end_line": 12077, "id": "Q82", "line": 12049, - "lines": 26, + "lines": 29, "role": "continuation", "role_detail": "closure", "status": "DONE at `0735102` (suite), `6c097bf` (float surface); this record and `docs/queue-index.md` land in the commit above it.", "status_line": 12051, "title": "closure \u2014 `test_json_canonical.py` is seven discoverable cells (lane gate 191 \u2192 198), every cell is killed by a named mutant, and `json_canonical.py` says what it is not *(volt, 2026-10-26; beam's \u2026" + }, + { + "bytes": 9978, + "end_line": 12117, + "id": "Q81", + "line": 12078, + "lines": 40, + "role": "continuation", + "role_detail": "closure", + "status": "DONE at `3f424c0` (tool), `329af8b` (suite + gate leg); this record and `docs/queue-index.md` land in the commit above them.", + "status_line": 12080, + "title": "closure \u2014 `hermes_profile_health.py` grades a profile you name, parses the config it grades, and the lane gate collects nine cells *(volt, 2026-10-26; spark's lane by authorship, taken as the opening \u2026" } ] }