volt: Q69 addendum 3 -- q118_verify.py host pin derived (3 constants), five-leg guard + record

This commit is contained in:
volt authored and ledger committed 2026-11-04 15:14:46 +00:00
1 parent bd69d0ac47
commit 93ca4a8172
6 files changed
+316 -36

No files matched your search

+23
View File
@@ -14712,3 +14712,26 @@ At `406dd17`, `python3 tools/verify.py --fast` read **12 legs, 10 pass, 1 fault,
Files: `tools/queue_append_audit.py` (the pin axis, `grade_index`/`grade_pin`, `--axis`, the report columns, the 43-cell selftest), `CHECK-append-pin` (new, five legs), `wizard-work/volt/q137-open-set/open_set.py` (the `PIN_COUNTS` move), `wizard-work/volt/q143-check-sweep/check_entry_baseline.tsv` (one row), `WORK-QUEUE.md` (this record), `docs/queue-index.md` (re-rendered). Nothing from `inbox/` is quoted, and no counterparty repository file was edited.
CHECK: `bash CHECK-append-pin`
## Q69 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, 2026-11-04, at `6d8ddb9` and the commit this record lands in; Q69's own "one file per commit" clause)*
**Q69 stays open. This record repairs one of the eight files the second addendum named and takes no other; no id changes state and no other lane's file is touched.**
**(1) The defect, re-read at `6d8ddb9`.** `wizard-work/volt/q118_verify.py` carried three host-absolute paths: `DEFAULT_MODULE = "/root/.hermes/scripts/troupe_pipe_monitor.py"` (the monitor is not in this repository -- the cron job runs it by host path) and `HOST_CACHES` as the two deployed cache files. The census listed exactly those three: `{"line": 64, "subtype": "CONST"}`, `{"line": 67, "subtype": "READ"}`, `{"line": 68, "subtype": "READ"}`. Two behaviours followed, and both are measured rather than argued. **First**, whoever ran the tool with no argument graded one host's copy from any checkout: HEAD's blob, run with no argument, reads **rc 0, `q118: 8 leg(s), 8 passed, 0 fault(s)`** -- a green about a file that may not be the tree the tool was read out of. **Second**, the host-cache leg's subject was the pair typed into the file, not the pair the graded module declares, so the documented use of the argument (point a copy at the tool) graded the copy's *code* and the host's *caches*: over a copy whose two cache paths were renamed, HEAD's blob read `ok host-cache -- deployed caches byte-identical after the run` and named **0 of the copy's 2 paths**.
**(2) The repair: the subject is named by the caller, and the caches are read out of the subject.** `resolve_module` takes `argv[1]`, else `$Q118_MONITOR`, else nothing -- and nothing is a refusal (rc 2) that says how to name one, not a default that guesses whose host to grade. `declared_caches` reads the graded module's own `CACHE = Path("...")` and `LISTING_CACHE = Path("...")` lines, through the same two anchors `build_module` already rewrites, so a renamed cache cannot drift the leg from its subject and one table now serves both the rewrite and the read. A module whose anchors do not match is rc 2 (could not grade), never a green: an instrument that cannot say which files a run must leave alone must not report on them. The docstring states the rule and the pin it moved: the host subject now lives in `CHECK-q118` alone, where host pins belong (the Q106 class).
**(3) Measured after the edit, at this tree.** `bash wizard-work/volt/CHECK-q118` -> **rc 0**, `q118: 8 leg(s), 8 passed, 0 fault(s)`. With no argument and no `$Q118_MONITOR` -> **rc 2**, `could not grade -- no monitor named ... pass the path as argv[1] or set Q118_MONITOR.` The text predicate that the guard grades (`"(/root|/home|/var|/srv|/opt|/mnt)/`) reads **3 -> 0** between HEAD's blob and this file. The census moves by exactly the three constants and the one file: **554 -> 553 code files, 910 -> 907 constants** over 1366 graded, and the lane row reads **8 code files / 15 constants -> 7 / 12** (`wizard-work/volt 43 7 12 29 6 6`); the file keeps one prose mention, so it moves from the code population to `prose-only` (5 -> 6) rather than out of the census, which is the whole of what this repair claims to have done.
**(4) The guard: `wizard-work/volt/q69_q118hostpin_check.sh`, five legs, rc 0/1/2.** `text` (no host-absolute string literal in the module), `census` (the JSON names the module 0 times; rows are mentions, and a clean file has none), `refuse` (no subject named is rc 2 and the message names `Q118_MONITOR`), `derive` (a copy of the monitor with both cache anchors renamed is graded at *its* names -- repaired reads 2 of 2, `6d8ddb9`'s blob reads 0 of 2 while still speaking its `deployed caches byte-identical` line) and `teeth` (the `text` predicate fires on a copy carrying one literal back). Measured here: **rc 0, 5 leg(s), 0 fault(s)**, wall time 1m3s -- the `derive` leg runs both instruments end to end, and that cost is stated rather than hidden. The three legs that grade HEAD's blob read red on it (`text` 3 literals, `census` 1 file row + 3 constant rows, `refuse` rc 0 instead of 2), so the green above is a measurement of the repair and not a tool that cannot fail.
**(5) Bookkeeping, measured after this append and before the commit landed.** The append carries one heading (`## Q69 addendum 3`) over a lead that says Q69 stays open, so no record and no id is scored: headings 119 -> 120, heading_ids stays 103 (Q69 already carries a heading), and every record counter, `ids` and `record_only` stand still (records 131, record_ids 97, ids 158, record_only 55, open 0, opened 26); no probe is registered for a repair inside an open id, and `q69_q118hostpin_check.sh` is its guard. `PIN_COUNTS` in `open_set.py` moved to the counts this append makes, measured by `--check` after the append; `python3 tools/queue_index.py --write docs/queue-index.md` re-rendered. No row was added to `wizard-work/volt/q143-check-sweep/check_entry_baseline.tsv`: that table grades root entry points, and this guard lives under `wizard-work/volt/` beside the tool it grades.
**(6) What stays open in this lane, re-counted.** Seven files, twelve constants: media-catalog `claims_check.py:52` and `semantic_gate.py:213` (`/root/stackchain_catalog_raw.json`); `q133_verify.py:64` and `q136_verify.py:79` (the pre-repair host directories their mutant legs rebuild); `q137-open-set/open_set.py:393,412` (the monitor); `q63_prove.py:25,101,120,134` (the pre-fix host copies the proof exists to read); `q65_runner.py:117` twice (the detector's own pattern). `q118_verify.py` is off that list by this record and nothing else moved.
**(7) Not claimed.** That the monitor should move into this repository -- the cron job runs it by host path and that move is the pipe's decision, not this item's; what changed is that the verifier no longer asserts one host's path from a checkout. That `CHECK-q118` naming a host path is a defect of the same class -- a CHECK is where a pin belongs, and it is one path in one place, stated in its own header. That the pre-fix blob's rc 0 was a false *verdict* -- every leg it ran was true of the host copy it read; what was false was that the reading was about the tree it was run from. That a CODE row is a fault -- the census counts positions and cannot read intent. That 7/12 is stable -- it is a re-read of a tree other lanes commit to. That the guard's 1m3s is acceptable for the repo gate -- it is not wired into it, and would need the `derive` leg split before it could be.
Files: `wizard-work/volt/q118_verify.py` (`resolve_module`, `declared_caches`, the docstring), `wizard-work/volt/CHECK-q118` (the host pin and the declared-cache assertion), `wizard-work/volt/q69_q118hostpin_check.sh` (new guard, five legs), `wizard-work/volt/q137-open-set/open_set.py` (the `PIN_COUNTS` move), `WORK-QUEUE.md` (this record), `docs/queue-index.md` (re-rendered). Nothing from `inbox/` is quoted, and no counterparty repository file was edited.
CHECK: `bash wizard-work/volt/q69_q118hostpin_check.sh`
+42 -14
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. 119 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. 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.
| # | id | kind | lines | bytes | role | title | first `Status:` |
|---|---|---|---|---|---|---|---|
@@ -278,7 +278,8 @@
| 268 | Q167 | heading | 14677-14678 | 228 | opening | closure — the queue's pin sat two commits behind the queue, and nothing graded the pin in the commit *(volt, 2026-11-04, at `56d3853` and the commit this record lands in; sol lane by authorship … | -- |
| 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-14714 | 8236 | 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 … | -- |
| 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-14737 | 7181 | 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 … | -- |
## Ids with no `## ` heading
@@ -303,7 +304,7 @@ Opened as records inside another section. `line` is the record's own opening lin
| Q103 | 13010 | 13010 | 18 | Q102 | BULLET+BOLD | BOLD-LEAD |
| Q104 | 13103 | 13103 | 19 | Q101 | BULLET+BOLD | BOLD-LEAD |
| Q105 | 13135 | 13135 | 20 | Q104 | BULLET+BOLD | BOLD-LEAD |
| Q106 | 13171 | 13171 | 18 | Q105 | BULLET+BOLD | BOLD-LEAD |
| Q106 | 13171 | 13171 | 19 | Q105 | BULLET+BOLD | BOLD-LEAD |
| Q107 | 13189 | 13189 | 19 | Q106 | BULLET+BOLD | BOLD-LEAD |
| Q108 | 13267 | 13263 | 3 | Q106 | BULLET+BOLD | BOLD-LEAD |
| Q109 | 13270 | 13270 | 31 | Q104 | BULLET+BOLD | BOLD-LEAD |
@@ -2321,12 +2322,12 @@ The block below is the parse this document renders, byte for byte. `--check` com
"title": "**Q167 \u2014 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 \u2026"
},
{
"bytes": 8236,
"end_line": 14714,
"bytes": 8237,
"end_line": 14715,
"id": "Q168",
"kind": "record",
"line": 14696,
"lines": 19,
"lines": 20,
"role": "continuation",
"role_detail": "OPENED",
"status": null,
@@ -2358,7 +2359,8 @@ The block below is the parse this document renders, byte for byte. `--check` com
"Q69": [
11457,
14633,
14655
14655,
14716
],
"Q72": [
11526,
@@ -6014,17 +6016,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": 8236,
"end_line": 14714,
"bytes": 8237,
"end_line": 14715,
"id": "Q168",
"kind": "record",
"line": 14696,
"lines": 19,
"lines": 20,
"role": "continuation",
"role_detail": "OPENED",
"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": 7181,
"end_line": 14737,
"id": "Q69",
"kind": "heading",
"line": 14716,
"lines": 22,
"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"
}
],
"nested": [
@@ -6186,7 +6201,7 @@ The block below is the parse this document renders, byte for byte. `--check` com
"form": "BOLD-LEAD",
"id": "Q106",
"line": 13171,
"refs": 18,
"refs": 19,
"section": "Q105",
"shape": "BULLET+BOLD"
},
@@ -6574,9 +6589,9 @@ The block below is the parse this document renders, byte for byte. `--check` com
"end_line": 8,
"line": 1
},
"queue_bytes": 2557241,
"queue_lines": 14714,
"queue_sha256": "9341e983b3aecc12c5f42dbd4b9df8274d6115dea08df01a29c1875bfaa7a5d7",
"queue_bytes": 2564423,
"queue_lines": 14737,
"queue_sha256": "83792ee6e2beecbbec1377d5e7828e2e293f82a055eaa2d3d9a1b740225427eb",
"sections": [
{
"bytes": 3139,
@@ -8124,6 +8139,19 @@ The block below is the parse this document renders, byte for byte. `--check` com
"status": null,
"status_line": null,
"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": 7181,
"end_line": 14737,
"id": "Q69",
"kind": "heading",
"line": 14716,
"lines": 22,
"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"
}
]
}
+23 -6
View File
@@ -5,21 +5,32 @@
#
# The artifact under repair is NOT in this repository -- the pipe's monitor lives
# at /root/.hermes/scripts/troupe_pipe_monitor.py because the cron job runs it by
# host path -- so like CHECK-q115 this gate reads a host path. That is stated,
# not hidden (the Q106 host-pin class); moving the monitor into the tree is the
# pipe's decision, not this item's. Everything the gate grades is the deployed
# retry loop itself: the fake `curl` sits at the module's real boundary, so no
# function under test is stubbed.
# host path -- so unlike every other volt gate this one names a host path. That
# is stated, not hidden (the Q106 host-pin class); moving the monitor into the
# tree is the pipe's decision, not this item's. Everything the gate grades is the
# deployed retry loop itself: the fake `curl` sits at the module's real boundary,
# so no function under test is stubbed.
#
# Since the Q69 repair this file is the only place the pin lives: q118_verify.py
# carries no default module and no typed cache paths, it takes argv[1] or
# $Q118_MONITOR and refuses with rc 2 when neither names one. Override the
# subject with Q118_MONITOR=<path>; a host without the monitor still reads rc 2
# (could not grade), never a green.
set -u
HERE="$(cd "$(dirname "$0")" && pwd)"
VERIFY="$HERE/q118_verify.py"
MONITOR="${Q118_MONITOR:-/root/.hermes/scripts/troupe_pipe_monitor.py}"
if [ ! -f "$VERIFY" ]; then
echo "FAIL: verifier missing at $VERIFY" >&2
exit 2
fi
if [ ! -f "$MONITOR" ]; then
echo "FAIL: could not grade -- monitor missing at $MONITOR (override with Q118_MONITOR)" >&2
exit 2
fi
out="$(python3 "$VERIFY" 2>&1)"
out="$(Q118_MONITOR="$MONITOR" python3 "$VERIFY" 2>&1)"
rc=$?
printf '%s\n' "$out" | grep -E '^FAIL:|^q118:' || true
@@ -35,5 +46,11 @@ if ! printf '%s\n' "$out" | grep -q '^q118: 8 leg(s), 8 passed, 0 fault(s)$'; th
echo "FAIL: expected 8/8 legs, got: $(printf '%s\n' "$out" | tail -1)" >&2
exit 1
fi
# the host-cache leg must speak about the subject's own declared caches, which the
# instrument now reads out of the module instead of typing into itself
if ! printf '%s\n' "$out" | grep -q '^ok host-cache -- declared caches unchanged after the run: [^,]*, '; then
echo "FAIL: the host-cache leg did not name two declared caches" >&2
exit 1
fi
echo "q118: retry absorbs a transient read, names attempts= and last=, wakes on exhaustion -- OK"
exit 0
+84 -15
View File
@@ -46,10 +46,28 @@ Exit codes follow the repository's tools: 0 clean, 1 graded fault, 2 could not
grade (module or interpreter absent, or a constant anchor that no longer
matches -- a rewrite that silently did nothing would grade the live host).
Run: python3 wizard-work/volt/q118_verify.py [module.py]
The optional argument points the instrument at a copy of the module -- that is
how a whole-artifact negative control is taken (a copy whose default retry count
is 1 must red `recover` and `exhaust`).
WHERE THE SUBJECT COMES FROM -- and why no path is typed into this file
The monitor is not in this repository (the cron job runs it by absolute host
path), so this instrument used to carry that host path as `DEFAULT_MODULE` and
the two deployed cache paths as `HOST_CACHES`. Both
were literals: the file graded one host's copy from any checkout, and the
host-cache leg spoke about two paths that were fixed in this file rather than
read from the module it was pointed at -- so a copy (the documented use of
argv[1]) or a deployment that renamed its caches was watched at the old names
and its own caches were never graded (measured: pointed at a copy whose two
caches were renamed, this file's leg read `deployed caches byte-identical`
and named 0 of the copy's 2 paths). The subject is now named by the caller --
argv[1], else `Q118_MONITOR` -- and the cache paths are read out of the module
under grade, on the same two anchors `build_module` already rewrites. With
neither argv[1] nor `Q118_MONITOR` the instrument refuses with rc 2 instead of
guessing whose host to grade (Q69's rule for volt's tools; the host pin itself
is stated in `CHECK-q118`, where a host subject belongs).
Run: python3 wizard-work/volt/q118_verify.py <module.py>
Q118_MONITOR=<module.py> python3 wizard-work/volt/q118_verify.py
The argument points the instrument at the module or a copy of it -- that is how
a whole-artifact negative control is taken (a copy whose default retry count is
1 must red `recover` and `exhaust`).
"""
import hashlib
import json
@@ -61,11 +79,14 @@ import tempfile
import time
from pathlib import Path
DEFAULT_MODULE = "/root/.hermes/scripts/troupe_pipe_monitor.py"
MODULE = Path(sys.argv[1]) if len(sys.argv) > 1 else Path(DEFAULT_MODULE)
HOST_CACHES = (
Path("/root/.hermes/cache/troupe_last_touch.json"),
Path("/root/.hermes/cache/troupe_folder_listing.json"),
DEFAULT_MODULE = None # resolved per run: argv[1], then $Q118_MONITOR; else refuse
MODULE = None
MODULE_ENV = "Q118_MONITOR"
# the two anchors build_module rewrites, reused to READ the caches the graded
# module declares -- one table, so a rename cannot drift the leg from its subject
CACHE_ANCHORS = (
("CACHE", r'^CACHE = Path\("([^"]+)"\)$'),
("LISTING_CACHE", r'^LISTING_CACHE = Path\("([^"]+)"\)$'),
)
ITEMS = [
{"type": "file", "path": "replies/2026-10-28-to-zephyrus-1.md", "sha": "aaa111bbb222"},
@@ -146,8 +167,41 @@ def digest(path):
return "absent"
def resolve_module(argv):
"""Which file to grade: argv[1], then $Q118_MONITOR, then nothing.
Returning None is the refusal path: the monitor is outside this repository,
so any built-in default would be one host's copy of it (Q69).
"""
if len(argv) > 1:
return Path(argv[1]), "argv[1]"
env = os.environ.get(MODULE_ENV, "").strip()
if env:
return Path(env), MODULE_ENV
return None, ""
def declared_caches(module):
"""The cache paths the graded module declares -- read, never re-typed.
A RuntimeError here is rc 2, not a guess: an anchor that no longer matches
means this instrument cannot say which files the run must leave alone.
"""
text = module.read_text(encoding="utf-8")
out = []
for name, anchor in CACHE_ANCHORS:
m = re.search(anchor, text, re.M)
if not m:
raise RuntimeError(
f"no `{name} = Path(\"…\")` line in {module} -- cannot say which cache "
f"the graded run must leave alone")
out.append(Path(m.group(1)))
return tuple(out)
def build_module(work: Path, mutate=None) -> Path:
"""Copy the deployed module with its four outside-world constants repointed."""
assert MODULE is not None, "build_module needs a module resolved by main()"
text = MODULE.read_text(encoding="utf-8")
if mutate:
old, new = MUTATIONS[mutate]
@@ -320,10 +374,25 @@ MUTANT_CASES = (
def main() -> int:
if not MODULE.is_file():
print(f"FAIL: could not grade -- module missing at {MODULE}", file=sys.stderr)
global MODULE
module, source = resolve_module(sys.argv)
if module is None:
print(f"q118: could not grade -- no monitor named. The monitor is not in this "
f"repository, so a built-in default would be one host's copy; pass the "
f"path as argv[1] or set {MODULE_ENV}.", file=sys.stderr)
return 2
before = {str(p): digest(p) for p in HOST_CACHES}
MODULE = module
if not MODULE.is_file():
print(f"FAIL: could not grade -- module missing at {MODULE} (named by {source})",
file=sys.stderr)
return 2
try:
caches = declared_caches(MODULE)
except (RuntimeError, OSError) as exc:
print(f"FAIL: could not grade -- {exc}", file=sys.stderr)
return 2
named = ", ".join(str(p) for p in caches)
before = {str(p): digest(p) for p in caches}
passed = 0
try:
for name, fn in DEPLOYED_CASES:
@@ -343,11 +412,11 @@ def main() -> int:
print(f"FAIL: could not grade -- {exc}", file=sys.stderr)
return 2
after = {str(p): digest(p) for p in HOST_CACHES}
after = {str(p): digest(p) for p in caches}
if before != after:
fault("host-cache", f"a graded run wrote host state: {before} -> {after}")
fault("host-cache", f"a graded run wrote the module's declared cache: {before} -> {after}")
else:
ok("host-cache", "deployed caches byte-identical after the run")
ok("host-cache", f"declared caches unchanged after the run: {named}")
passed += 1
total = len(DEPLOYED_CASES) + len(MUTANT_CASES) + 1
+8 -1
View File
@@ -647,7 +647,14 @@ PIN_OPENED = [51, 52, 53, 65, 100, 101, 102, 103, 104, 105, 106, 107, 109,
# append, which named exactly these five faults and no others, and the audit
# that repairs this item now grades this pin as a second axis in the commit --
# this record's own commit included.
PIN_COUNTS = {"headings": 119, "heading_ids": 103, "records": 131,
# Q69 addendum 3 (2026-11-04): the same shape as addendum 2 -- a section heading
# (## Q69 addendum 3 ...) over a lead that says Q69 stays open, so no record and
# no id is scored: headings 119 -> 120 with heading_ids staying 103 (Q69 already
# carries a heading), and every record counter, ids and record_only unchanged:
# 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,
"record_only": 55}
+136
View File
@@ -0,0 +1,136 @@
#!/usr/bin/env bash
# CHECK -- the Q69 repair of wizard-work/volt/q118_verify.py's host pin.
#
# The instrument hard-coded three host-absolute paths: the deployed monitor as
# DEFAULT_MODULE, and the deployed pair of caches as HOST_CACHES. The Q69 defect
# is the first one (whoever ran the tool without an argument graded one host's
# copy from any checkout); the second is the same defect one level down -- the
# host-cache leg spoke about two paths typed into this file rather than read out
# of the module it was pointed at, so a copy (the documented use of argv[1]) or
# a deployment that renamed its caches was watched at the old names and its own
# caches were never graded. Five legs, each falsifiable on its own:
# text the instrument carries no host-absolute string literal
# census the AST census lists no row for the instrument (rows are mentions)
# refuse with no argv[1] and no $Q118_MONITOR it refuses rc 2 and says how
# derive a copy with renamed caches is graded at ITS names; the pre-fix blob
# over the same copy is graded at the host names it carries (0 of 2)
# teeth the text leg's predicate fires on a copy carrying the literal back
# rc 0 clean, rc 1 a fault it graded, rc 2 it could not grade at all.
set -u
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
SUB="wizard-work/volt/q118_verify.py"
CENSUS="wizard-work/volt/q69_hostroot_census.py"
PRE_FIX_REV=6d8ddb9 # the commit this repair is measured against
faults=0
leg() { printf '%-7s %s\n' "$1" "$2"; }
for f in "$ROOT/$SUB" "$ROOT/$CENSUS"; do
if [ ! -f "$f" ]; then
echo "q69-q118: missing $f; cannot grade" >&2
exit 2
fi
done
if ! git -C "$ROOT" rev-parse --git-dir >/dev/null 2>&1; then
echo "q69-q118: $ROOT is not a git repository; the pre-fix leg cannot read it" >&2
exit 2
fi
TMP="$(mktemp -d "${TMPDIR:-/tmp}/q69-q118.XXXXXX")" || exit 2
trap 'rm -rf "$TMP"' EXIT
# text -- no host-absolute literal survives in the instrument
hits="$(grep -c '"/\(root\|home\|var\|srv\|opt\|mnt\)/' "$ROOT/$SUB")"
if [ "$hits" -eq 0 ]; then
leg text "ok (0 host-absolute literal)"
else
leg text "FAULT ($hits host-absolute literal)"; faults=$((faults + 1))
fi
# census -- the AST census mentions the instrument not at all
if python3 "$ROOT/$CENSUS" --json "$TMP/census.json" >"$TMP/census.out" 2>&1; then
rows="$(grep -c 'q118_verify.py' "$TMP/census.json")"
if [ "$rows" -eq 0 ]; then
leg census "ok (0 row for $SUB)"
else
leg census "FAULT ($rows row(s) name the instrument)"; faults=$((faults + 1))
fi
else
leg census "FAULT (census rc $? -- $(tail -1 "$TMP/census.out"))"
faults=$((faults + 1))
fi
# refuse -- no subject named is rc 2 with the way to name one, never a default
rout="$(env -u Q118_MONITOR python3 "$ROOT/$SUB" 2>&1)"; rrc=$?
if [ "$rrc" -eq 2 ] && printf '%s\n' "$rout" | grep -q 'Q118_MONITOR'; then
leg refuse "ok (rc 2, message names Q118_MONITOR)"
else
leg refuse "FAULT (rc $rrc, message: $(printf '%s\n' "$rout" | tail -1))"
faults=$((faults + 1))
fi
# derive -- the host-cache leg follows the module's own declaration
git -C "$ROOT" show "$PRE_FIX_REV:$SUB" >"$TMP/pre118.py" 2>"$TMP/pre.err"
if [ ! -s "$TMP/pre118.py" ]; then
leg derive "FAULT (no pre-fix blob at $PRE_FIX_REV:$SUB -- $(tail -1 "$TMP/pre.err"))"
faults=$((faults + 1))
else
mkdir -p "$TMP/copy"
python3 - "$TMP/copy/troupe_pipe_monitor.py" <<'PY' >"$TMP/copy.out" 2>&1
import re, sys
from pathlib import Path
src = Path("/root/.hermes/scripts/troupe_pipe_monitor.py")
if not src.is_file():
raise SystemExit("no deployed module to copy")
dest = Path(sys.argv[1])
text = src.read_text(encoding="utf-8")
for pat, rep in ((r"^CACHE = .*$", 'CACHE = Path("%s")' % (dest.parent / "attrib-copy.json")),
(r"^LISTING_CACHE = .*$", 'LISTING_CACHE = Path("%s")' % (dest.parent / "listing-copy.json"))):
text, n = re.subn(pat, rep, text, count=1, flags=re.M)
if n != 1:
raise SystemExit("anchor %r matched %d time(s)" % (pat, n))
dest.write_text(text, encoding="utf-8")
PY
copyrc=$?
if [ "$copyrc" -ne 0 ] || [ ! -f "$TMP/copy/troupe_pipe_monitor.py" ]; then
leg derive "FAULT (could not build the copy: $(tail -1 "$TMP/copy.out"))"
faults=$((faults + 1))
else
python3 "$ROOT/$SUB" "$TMP/copy/troupe_pipe_monitor.py" >"$TMP/new.out" 2>&1
newrc=$?
python3 "$TMP/pre118.py" "$TMP/copy/troupe_pipe_monitor.py" >"$TMP/old.out" 2>&1
oldrc=$?
newhas="$(grep -c "^ok host-cache -- declared caches unchanged after the run: $TMP/copy/attrib-copy.json, $TMP/copy/listing-copy.json$" "$TMP/new.out")"
oldspoke="$(grep -c '^ok host-cache -- deployed caches byte-identical after the run$' "$TMP/old.out")"
oldhas="$(grep -c "$TMP/copy/attrib-copy.json" "$TMP/old.out")"
# the pre-fix blob's own rc is not graded here: its timing legs (firstok
# asserts a tick under 1.5 s wall) read rc 1 once under load in this
# clone and rc 0 on two immediate re-runs. What is graded is that its
# host-cache leg SPOKE (about the host pair) and named the copy 0 times.
if [ "$newrc" -eq 0 ] && [ "$newhas" -eq 1 ] && [ "$oldspoke" -eq 1 ] && [ "$oldhas" -eq 0 ]; then
leg derive "ok (copy's 2 paths named: new 2 of 2, pre-fix 0 of 2)"
else
leg derive "FAULT (new rc $newrc names copy: $newhas; pre-fix rc $oldrc spoke: $oldspoke names copy: $oldhas)"
faults=$((faults + 1))
fi
fi
fi
# teeth -- the text leg's predicate is not one that cannot fire
cp "$ROOT/$SUB" "$TMP/pinned.py" || exit 2
printf 'DEFAULT_MODULE = "/root/.hermes/scripts/troupe_pipe_monitor.py"\n' >>"$TMP/pinned.py"
poison="$(grep -c '"/\(root\|home\|var\|srv\|opt\|mnt\)/' "$TMP/pinned.py")"
if [ "$poison" -ge 1 ]; then
leg teeth "ok (poisoned copy reads $poison, clean copy reads 0)"
else
leg teeth "FAULT (poisoned copy reads 0 -- the text leg cannot fail)"
faults=$((faults + 1))
fi
if [ "$faults" -eq 0 ]; then
echo "q69-q118: 5 leg(s), 0 fault(s)"
exit 0
fi
echo "q69-q118: 5 leg(s), $faults fault(s)"
exit 1