docs(901): #885 merged, so the sentence the record's structural fact refutes is corrected at its source

`scripts/tests/test_hook_fire_log.py:154` ended "this arm's errors are refusals,
never acceptances". That is false for the SELECTION, which is the half this branch's
record is about: `mentions` is chosen by the literal `ETV_HOOK_FIRE_LIB`, so a writer of
that variable which never spells the literal is outside the compared set altogether, and
the checker never sees it. The comment already conceded an acceptance hole of the same
kind six lines later, about `split("\n")` versus `splitlines()`, so the universal was
contradicted inside its own block.

The correction stays STRUCTURAL — it reads the selector one line below and says what the
selector reaches — and makes no claim about what a mutated hook would return. An outcome
claim would be a `CLAIMS` entry in `scripts/tests/mutation_manifest.py` or nothing, per
`testing.mutation-claims-are-executed` as amended by #881, which is the same reason
`mechanics:` states the selector rather than a measured result (`4d5bd0dbb`).

WHY THIS LANDS NOW: #885 closed while this branch was in review (merged as #919,
`c30847204`), which frees `scripts/tests/`. Of the two obligations `47619320e` recorded
as owed, that message is superseded here:

- DISCHARGED: this one, inline, above.
- NOT OWED, and the reason is not the blocker: the `CLAIMS` entry for the hook-preamble
  selector. `4d5bd0dbb` removed the outcome claim from `mechanics:` rather than binding
  it, so the record asserts no mutation outcome and the rule it invokes has nothing to
  bind. Re-adding a claim in order to bind it would reverse a review-mandated change; an
  executed GREEN entry (target `.claude/hooks/decisions-guard.sh`, clause = the canonical
  sink assignment, replacement = that line plus the `eval` spelling, plus the mandatory
  `reach_replacement`/`reach_expect`) remains available as an ENRICHMENT of the structural
  fact, and belongs to whoever wants the fact executed rather than argued.

Rebased onto `366a0f904..c30847204` on the way: the `docs/guard-inventory.md` conflict is
two rows, resolved by taking #885's newer `test_workflow_persist_credentials.py` row
(it gained a second invariant) and this branch's `test_image_build_delegates_the_spa_suite.py`
row (it dates the vite `DEFAULT_CONFIG_FILES` reading to 8.1.3 and to the lockfile).
`docs/decisions/README.md` regenerated, not merged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015QqCpYFsKgnAnx6jVwrKiV
This commit is contained in:
2026-09-05 16:01:18 +02:00
co-authored by Claude Fable 5.1
parent 868ab657d8
commit dc3f158bcb
+7 -1
View File
@@ -151,7 +151,13 @@ def instrumentation_faults(text: str, name: str) -> list[str]:
# `#` is a comment in every shell. `pretooluse-merge-consent.sh` legitimately discusses this
# variable in prose. Every other line mentioning it must be one of the two canonical lines, in
# order. A heredoc carrying the token would fault; no hook has one, and refusing is the safe
# direction — this arm's errors are refusals, never acceptances.
# direction for the lines this arm COMPARES — but not for the ones it SELECTS. `mentions` is
# chosen by the literal `ETV_HOOK_FIRE_LIB`, so a writer of that variable which never spells the
# literal — one composed at runtime and `eval`ed, say — is outside the compared set altogether,
# and byte-identity WITHIN a selection is not byte-identity over the file
# (`testing.guard-pins-the-artifact-not-a-shape`, which states this pin's reach because the pin
# itself does not). So this arm's errors are not all refusals, and the `split("\n")` residual
# below is the second acceptance of the same kind.
# `split("\n")`, not `splitlines()`: the latter also breaks on \x0b, \x0c, \x1c-\x1e, \x85 and the
# Unicode separators, none of which ends a line for the shell. The divergence runs BOTH ways —
# a canonical assignment followed by `\x0c` and garbage on one physical line parses clean under