From 4043627898373948f4d15d552cbead76b86ebf58 Mon Sep 17 00:00:00 2001 From: Levi Neuwirth Date: Tue, 28 Jul 2026 15:47:17 -0400 Subject: [PATCH] Contract G2a round five: the sixth hand-maintained site, and locking Registered The literal-site count said four and named three plus two generator bounds. The omitted one is OperationKind::discriminant() -- the hand-written match that Push 4a got wrong in the first place, and the one the contract elsewhere notes the tag macro does not guard. All six are now enumerated, with the count after row 29's derivation stated as five so the next tranche inherits an accurate number rather than this one's. s10's layout-stub half asserted kinds 30-33, which would have survived deleting the required Registered append -- PAYLOAD_FREE excludes it by design and the generator's doc promises every variant, so the gap between them is exactly where the bug would live. It now asserts PAYLOAD_FREE union {Registered}, with removal of Registered as the mutation. Future built-ins follow structurally with no test change; the one payload-bearing variant that cannot stays locked. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV --- spec/CONTRACT_GENESIS_G2A_SETTINGS.md | 42 ++++++++++++++++++++------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/spec/CONTRACT_GENESIS_G2A_SETTINGS.md b/spec/CONTRACT_GENESIS_G2A_SETTINGS.md index 2f241cf..e22c4e9 100644 --- a/spec/CONTRACT_GENESIS_G2A_SETTINGS.md +++ b/spec/CONTRACT_GENESIS_G2A_SETTINGS.md @@ -400,10 +400,18 @@ show it dies. A test that cannot see its own bug is not a test. other suites treat as exhaustive, so a kind absent from them is untested everywhere downstream while every suite stays green — which is how `TransposeInterval` and `CreateInstrument` came to be missing from both. - Assert that a bounded draw from each generator yields all four appended kinds - (30–33). **Mutation:** drop one arm / leave a bound unwidened → the assertion - fires. Row 29's derived form should make its half of this unfailable by - construction; if it does not, the derivation is wrong. + For row 28, assert that a bounded draw yields all four appended kinds (30–33). + **Mutation:** drop one arm / leave the bound unwidened → the assertion fires. + + For row 29, **do not assert 30–33** — that would pass with the derivation's + `Registered` append deleted, even though `PAYLOAD_FREE` excludes it by design + (`payload.rs:469`) and the generator's own doc promises *every* variant. + Assert the draw covers exactly **`PAYLOAD_FREE` ∪ {`Registered`}**. + **Mutation:** remove the `Registered` append → the assertion fires. Future + built-ins then follow structurally with no test change, while the one + payload-bearing variant that cannot follow structurally stays locked. If + either half of s10 can survive its mutation, the derivation is wrong — report + that rather than weakening the assertion. ## Blast radius @@ -428,13 +436,25 @@ exists precisely because Push 4a added `TransposeInterval` to a hand-written match and nothing else, and its own doc says four hand-maintained lists stayed green (`payload.rs:461`). The macro made the *compile-enforced* half safe — and these three lists went stale at that same append anyway, because nothing -forces a `rng.below(N)` bound or a literal count to move. So the vocabulary now -has **four** hand-maintained literal sites (`layout-ir/src/barrier.rs:1105`, -`testkit/tests/text_projection_grammar.rs:307`, `ops/src/textproj_kind.rs:597`, -plus the two generator bounds), and each new kind must visit all of them. Row -29's fix is the only structural one available here — derive from `PAYLOAD_FREE` -— so **prefer deriving over extending wherever a list can be derived**, and say -in the report which sites could not be. +forces a hand-written match arm, an `rng.below(N)` bound, or a literal count to +move. So **every new kind must visit six hand-maintained sites**, none of which +the compiler checks: + +1. `ops/src/payload.rs:266` — `OperationKind::discriminant()`, a hand-written + match. **This is the exact site Push 4a got wrong**, and it is still + unguarded; the macro guards the *tag* space beside it, not this one. +2. `layout-ir/src/barrier.rs:1105` — the "one past the vocabulary" literal. +3. `testkit/tests/text_projection_grammar.rs:307` — a kind count. +4. `ops/src/textproj_kind.rs:597` — a second kind count. +5. `testkit/src/generators.rs:647` — an `rng.below(N)` bound over hand-written + arms. +6. `testkit/src/layout_stub.rs:951` — the same, over tags. + +Row 29 converts **6** into a derivation, leaving **five** manual visits for +every future append. That is the only structural fix available in this packet — +so **prefer deriving over extending wherever a list can be derived**, and name +in the report every site that could not be, so the next tranche inherits an +accurate count rather than this one's. Expect `the_canonical_base_is_byte_identical_across_data_model_majors` (`reduce.rs:10715`) to require a **conscious re-pin**: the seeded corpus's