docs(901): the hook-preamble fault does not name a constant — correct the mechanics claim
The record asserted both worked pins fail with a message naming the constant to update and asking for a reason. True of `test_image_build_delegates_the_spa_suite.py`'s three pins; false of `test_hook_fire_log.py`, whose byte-identity fault reports the divergent `mentions` list and names no constant. Verified against both files rather than inferred from the neighbouring one. Decisions-Edit: yes Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015QqCpYFsKgnAnx6jVwrKiV
This commit is contained in:
@@ -7,7 +7,7 @@ supersedes: none
|
||||
superseded-by: none
|
||||
rule: 'A predicate that decides something by matching a SHAPE inside an artifact whose GRAMMAR it does not implement pins the artifact WHOLE instead — the whole file, or a whole named span, compared for equality under a STATED normalisation. The boundary is the grammar and never the file type: shell source, a workflow `run:` body, TOML, YAML, a jq expression and JSON5 all qualify, and a shape matched over the OUTPUT of a real parser for that grammar does not. Extracting a `run:` value with a real YAML parser and then matching shell inside it IS in the class, because the shell is the unparsed half. THE PIN IS THE DEFAULT FOR A NEW PREDICATE, not the remedy after a shape-matcher has been defeated once. The defeat a remedy policy waits for is a false GREEN, so it is found by a reviewer or by an incident and never by the guard: "not defeated yet" is a statement about who has looked, not about the input space. A SHAPE-MATCHER IS THE EXCEPTION, and its argument carries FOUR things, written where the predicate is and re-read whenever a clause of it is widened. (1) The GRAMMAR named, and the parser that implements it — if the shape is matched over a real parse there is no exception to write. (2) The INPUT SPACE as a CLOSED enumeration with the reason it is closed: a generator whose output form is fixed, or a canonicaliser the guard itself runs. A list of the spellings the author thought of is not that reason, and is the thing that was defeated nine, seven and five times. (3) The FAILURE DIRECTION measured rather than asserted: each defeat the matcher claims to catch is a DECLARED, executed mutation under `testing.mutation-claims-are-executed`, because a shape-matcher''s miss is a false green and an unrun claim about a fail direction is not evidence. (4) WHAT IT BUYS over the pin, priced in a cost the pin actually charges — the artifact is edited routinely or written by tooling, so a pin would redden as background noise and train its readers to ignore it; or the artifact''s population is DISCOVERED rather than fixed, so there is nothing to pin. Fewer than four is a refusal, and neither elegance nor an unwillingness to update a constant is one of the four. THE THRESHOLD for withdrawing a shape-matcher already shipped is not a count of spellings: it is the moment the NEXT spelling is found by the REVIEWER rather than by the author, which is evidence that the author''s model of the input space is not the input space. TWO RIDERS, both measured. A pin assumes it is pinning the artifact that still DECIDES — ask what else could decide this and whether the pin would still match: another FILE that outranks it, another OCCURRENCE in the same file, another WORKFLOW, or a HOOK the pinned command invokes. And WIDENING A CLAUSE RETIRES THE PROOFS CALIBRATED AGAINST THE NARROW ONE: a canary asserting that a finer mutation still SURVIVES has as its precondition that the guard is deliberately coarse there, so widening the main clause turns the canary into a tautology, which reads exactly like a passing proof — re-derive every proof calibrated against the narrow clause in the same commit that widens it. THE COST IS STATED RATHER THAN DISCOVERED LATER: any edit to a pinned artifact reddens, and the pin is updated deliberately in the same commit, with a reason. That red IS the review trigger the pin exists to be. A pin also declares its NORMALISATION and what the normalisation cannot see, because "pinned whole" invites a reader to assume byte equality.'
|
||||
signals: 'pin the artifact whole · shape-matcher is the exception that argues for itself · the boundary is the grammar not the file type · predicate does not implement the grammar it parses · defeated by the next spelling · the reviewer found the next spelling · false RED versus false GREEN · nine defects one mechanism · seven respellings of a partial config match · five spellings of a lexical preamble rule · the four-part exception argument: grammar and parser, closed input space, measured fail direction, what it buys · authority moves where the pin is not looking · an outranking config file · a decoy occurrence · an npm lifecycle hook · widening a clause retires its own canary · a survived-clause canary becomes a tautology · a pin declares its normalisation · instances: `ci.image-build-delegates-the-spa-suite`, `process.hook-resolves-inputs-from-repo-root` · paths: `scripts/tests/test_image_build_delegates_the_spa_suite.py`, `scripts/tests/test_hook_fire_log.py`, `docs/guard-inventory.md`, `docs/defect-shapes-773.md` · issues: #901, #887, #891, #774, #790, #881, #773'
|
||||
mechanics: 'Two worked pins. `scripts/tests/test_image_build_delegates_the_spa_suite.py` pins command TEXT (`PINNED_STAGE_COMMANDS`), `web/package.json`''s script map (`PINNED_PACKAGE_SCRIPTS`) and `web/vite.config.ts` entire (`PINNED_VITE_CONFIG`), the last two after a SELECTION and then a partial match were defeated; its comparison runs through `_normalise_lines`, which drops blank lines and collapses whitespace within a line, and the test states that residual rather than claiming byte equality. `scripts/tests/test_hook_fire_log.py` pins the hook preamble''s two lines byte for byte (`CANONICAL_SINK_ASSIGNMENT`, `CANONICAL_SINK_SOURCE`), named once so the checker, the mutation proofs and the hooks cannot come to mean different strings. Both failure messages name the constant to update and ask for a reason in the same commit.'
|
||||
mechanics: 'Two worked pins. `scripts/tests/test_image_build_delegates_the_spa_suite.py` pins command TEXT (`PINNED_STAGE_COMMANDS`), `web/package.json`''s script map (`PINNED_PACKAGE_SCRIPTS`) and `web/vite.config.ts` entire (`PINNED_VITE_CONFIG`), the last two after a SELECTION and then a partial match were defeated; its comparison runs through `_normalise_lines`, which drops blank lines and collapses whitespace within a line, and the test states that residual rather than claiming byte equality. `scripts/tests/test_hook_fire_log.py` pins the hook preamble''s two lines byte for byte (`CANONICAL_SINK_ASSIGNMENT`, `CANONICAL_SINK_SOURCE`), named once so the checker, the mutation proofs and the hooks cannot come to mean different strings. The image-build pins fail with a message naming the constant to update and asking for the reason in the same commit; the hook-preamble fault reports the divergent lines instead, since the two canonical strings ARE what a deliberate change edits.'
|
||||
---
|
||||
|
||||
**The class, and what approximating it costs.** A predicate over an artifact with a grammar is a
|
||||
|
||||
Reference in New Issue
Block a user