From 3328b2c0e27804f7944dd53cd59e973145be066c Mon Sep 17 00:00:00 2001 From: Levi Neuwirth Date: Mon, 10 Aug 2026 17:30:27 +0200 Subject: [PATCH] =?UTF-8?q?P13-S16=20post-acceptance=20reconciliation:=20t?= =?UTF-8?q?he=20three=20documents=20=C2=A74a=20held=20back?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Contract 4a deliberately kept these out of aee4ff9 because they describe the state of the repository rather than the change, and staging them during execution would have asserted that S16 had landed. It has, so they move now. CLAUDE.md - Green baseline 1577 -> 1583, still the single origin for the count. - Added: use --no-fail-fast whenever anything is failing. The bare command stops at the first failing suite, which is exactly the situation every mutation creates -- S16's M6a read six failures over four suites bare and seven over all forty-two with the flag. - The authority is currently 1, not 0, and a base materialized before S16 must be rebuilt rather than reused. - The bump rule now names BOTH classes it always covered: a change to a reduction verdict OR to canonical reduced state. S16 carried one of each, and the state-only kind is the easier to overlook while invalidating a base just as completely. - Two-tracks table: S16 LANDED, with a pointer to its unamended findings. spec/HANDOFF_2026-08-07.md - Chain state and §4.3 item 9 -> LANDED at aee4ff9, each retaining what it said before, since the block is a record of what moved. - The POST-S27 authority paragraph -> currently 1, both bump classes named. - Records the two S16 findings that bite outside their own contract: the --no-fail-fast truncation, and invariant 21 abstaining on dangling membership rather than detecting the undo hole 0.6 attributed to it. spec/PASS13_CANDIDATES.md - The S16 row is appended to, not rewritten: ACCEPTED AND LANDED at aee4ff9, superseding its own "EXECUTED ... NOTHING IS STAGED" sentence, RESOLVED, and the six contract findings listed as outstanding follow-up. The six findings remain unamended against CONTRACT_P13S16_PROJECTION.md. Its pins are frozen, so each needs its own amendment and review round; recording them at both ends is what keeps them visible until then. spec/EVIDENCE_P13S16_EXECUTION.md stays untracked -- no touch row covers it, and adding one is an amendment, not a keyboard decision. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x --- CLAUDE.md | 28 ++++++++++++++++++++++------ spec/HANDOFF_2026-08-07.md | 22 +++++++++++++++++----- spec/PASS13_CANDIDATES.md | 2 +- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 491920b..5831811 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -17,7 +17,7 @@ model with a LaTeX specification suite as its source of truth. | Track | Lives in | Current head | |---|---|---| -| **Spec / Pass 13** — wire format, bundle, ops, text projection, the `.tex` suite | `spec/`, `crates/epiphany-{core,ops,bundle,textproj,testkit}` | **P13-S27 LANDED** (`4df8e25`); **P13-S16 RATIFIED and dispatchable, pins frozen, not dispatched** | +| **Spec / Pass 13** — wire format, bundle, ops, text projection, the `.tex` suite | `spec/`, `crates/epiphany-{core,ops,bundle,textproj,testkit}` | **P13-S27 LANDED** (`4df8e25`); **P13-S16 LANDED** (`aee4ff9`) — six findings against its own contract are unamended, see its `PASS13_CANDIDATES.md` row | | **Editor / T4** — the editing seam, engraving, the toolkit spike | `spec/PLAN_EDITOR_APP.md`, `spec/CONTRACT_EDITOR_*`, `spikes/`, `crates/epiphany-{editor-core,editor-gui,engrave,layout-ir,glyphs,render-svg}` | T4 spike, round 2 built but not run | They are currently independent. The T1b/P13-S27 collision in @@ -85,12 +85,17 @@ reach today. ## Green baseline ``` -cargo test --workspace # expect 1577 passing, 0 failed, 0 ignored +cargo test --workspace # expect 1583 passing, 0 failed, 0 ignored cargo clippy --workspace --all-targets -- -D warnings # clean ``` **This is the single origin for the count** — `spec/HANDOFF_2026-08-07.md` used to -repeat it in three places and now points here. It moved 1570 → 1577 when P13-S27 landed. +repeat it in three places and now points here. It moved 1570 → 1577 when P13-S27 landed, +and 1577 → 1583 when P13-S16 landed (six net-new tests). + +**Use `--no-fail-fast` whenever anything is failing.** The bare command stops at the +first failing suite, so a partial failure set reads as the whole one — P13-S16's M6a +reported six failures over four suites bare, and seven over all forty-two with the flag. If the count differs on arrival, reconcile that **before** starting new work — the mutation discipline above depends on a known-green baseline. @@ -103,14 +108,25 @@ applies, and base-bearing bundles are constructible again through the ordinary A **What replaced it, and it is not "anything goes":** a canonical base is accepted only when its `reduction_algorithm_version` equals the running authority, -`epiphany_ops::CURRENT_REDUCTION_ALGORITHM_VERSION` — **currently `0`**. A mismatch is +`epiphany_ops::CURRENT_REDUCTION_ALGORITHM_VERSION` — **currently `1`**. A mismatch is `CanonicalBaseRequiresRebuild { base, current }`, refused on **both** the read side (`open`) and the write side (`commit`/`commit_versioned`). Legacy-epoch bundles still refuse a base outright. +**Any base materialized before P13-S16 must be rebuilt, not reused** — it declares `0` +and holds state the current semantics would not have computed. + **The bump discipline is the whole guarantee.** Any change to a canonical reduction -verdict MUST bump that constant — **no mechanism can detect a semantics change**, so -nothing will catch a missed bump. P13-S16 is the first rung that must move it to `1`. +verdict **or to canonical reduced state** MUST bump that constant — **no mechanism can +detect a semantics change**, so nothing will catch a missed bump. Both classes are named +because a change leaving every verdict intact while altering the reduced graph is the +easier one to overlook, and it invalidates a base just as completely. + +P13-S16 made the first bump, `0` → `1`, and carried one change of each kind: +`CreateStaffGroup`'s verdict (applied → `ContainerNotEmpty` no-op) and `CreateStaff`'s +reduced state (it still applies, but now maintains `StaffGroup.members`). The constant's +own `Bumps` list is the record of why each version exists; a bump without its entry +leaves a number nobody can account for. Fixtures deliberately exercising arbitrary wire versions take `BundleCapabilities::synthetic_for_fixture(v)`; production paths take the crate-local diff --git a/spec/HANDOFF_2026-08-07.md b/spec/HANDOFF_2026-08-07.md index 1abc4c5..5b79a17 100644 --- a/spec/HANDOFF_2026-08-07.md +++ b/spec/HANDOFF_2026-08-07.md @@ -16,16 +16,28 @@ unpushed commits on any branch. > | **§1.2 the live constraint** | no bundle anywhere may carry a canonical base | **LIFTED.** A base is accepted when its `reduction_algorithm_version` matches the running authority and refused with `CanonicalBaseRequiresRebuild { base, current }` when it does not — read side in `open`, write side in `commit`/`commit_versioned` | > | §1.2 conformance criterion 4 | canonical-base wiring **suspended** | **RESTORED.** Both lapsed assertions are back and the suspension marker is gone from `testkit/src/roundtrip.rs`. **§1.2's warning against re-homing the snapshot to `acceleration_snapshots` stands permanently** — it was never about the suspension | > | §1.2 the third error | `ReductionAuthorityUnavailable`, temporary | **DELETED**, replaced by `CanonicalBaseRequiresRebuild { base, current }`. The two permanent repack errors are unchanged, and **§1.2's "none may degrade to read-only" rule carries to the new error verbatim** — a stale base is the wrong materialization, not a restricted-but-correct view | -> | §1.4 chain state | `P13-S27 (UNBLOCKED) → P13-S16 (blocked on S27)` | `P13-S27 (LANDED)` → **`P13-S16 (RATIFIED 2026-08-09, pins frozen, dispatchable — not dispatched, nothing implemented)`** | +> | §1.4 chain state | `P13-S27 (UNBLOCKED) → P13-S16 (blocked on S27)` | `P13-S27 (LANDED)` → **`P13-S16 (LANDED 2026-08-10, `aee4ff9`)`**. *(Read "RATIFIED … dispatchable — not dispatched, nothing implemented" until S16 landed.)* | > | §2.6, §4.3 collision | T1b and P13-S27 must not fly together | **RESOLVED** — S27 has landed. **T1b is NOT thereby free:** it remains blocked on Ruling B blocker (ii), versioned decode — see §2.3, which is still accurate | > | §3.5, §4.2, §4.3 baseline | 1570 passing | **Moved when S27 landed. The count is in `CLAUDE.md`'s *Green baseline* and is deliberately not stated here, or anywhere else in this document** — it was kept in three places and went stale in all three | > | §4.3 item 7 | dispatch P13-S27 | **done** | -> | §4.3 item 9 | P13-S16 dispatchable the moment S27 lands | **unblocked — but its contract is a DRAFT and needs ratification before dispatch** | +> | §4.3 item 9 | P13-S16 dispatchable the moment S27 lands | **DONE — ratified, executed and landed at `aee4ff9` (2026-08-10).** *(Read "unblocked — but its contract is a DRAFT and needs ratification before dispatch" until ratification.)* | > > **The authority is `epiphany_ops::CURRENT_REDUCTION_ALGORITHM_VERSION`, currently -> `0`.** Any change to a canonical reduction verdict MUST bump it, and **no mechanism -> can detect a semantics change** — the discipline is the entire guarantee. **P13-S16 is -> the first rung that must move it to `1`.** +> `1`.** Any change to a canonical reduction verdict **or to canonical reduced state** +> MUST bump it, and **no mechanism can detect a semantics change** — the discipline is +> the entire guarantee. **P13-S16 made the first bump, `0` → `1`**, carrying one change +> of each kind: `CreateStaffGroup`'s verdict and `CreateStaff`'s reduced state. *(This +> read "currently `0` … P13-S16 is the first rung that must move it to `1`" until S16 +> landed.)* **A base materialized before S16 declares `0` and must be rebuilt, not +> reused.** +> +> **P13-S16 also left six findings against its own contract** — see the `EXECUTED` +> append on its `spec/PASS13_CANDIDATES.md` row, and +> `spec/EVIDENCE_P13S16_EXECUTION.md` (untracked review artifact) for the runs behind +> them. The two that bite hardest elsewhere: `cargo test --workspace` **truncates the +> failure set** at the first failing suite, so mutation work needs `--no-fail-fast`; +> and invariant 21 **abstains on dangling membership**, which is invariant 10's +> concern, so it is not the detector for the undo hole §0.6 attributed to it. **Scope.** Written from the **spec / Pass-13 / format-epoch** session. A second session has been committing to this repository in parallel on the **editor / diff --git a/spec/PASS13_CANDIDATES.md b/spec/PASS13_CANDIDATES.md index 3187e60..5428d5a 100644 --- a/spec/PASS13_CANDIDATES.md +++ b/spec/PASS13_CANDIDATES.md @@ -111,7 +111,7 @@ evidence in isolation. | P13-S13 | **The score tuning context has no canonical persistence path: it can be saved, but never authored, replicated, or merged.** Schema major 3 (Push 4b tranche 3b-i) put `smufl` and `overrides` on the wire, but the only *persisted* carrier that embeds a `ScoreTuningContext` is the **acceleration snapshot**, which Chapter 8 makes explicitly non-canonical and regenerable and which the bundle may discard and rebuild at will. No **canonical** carrier embeds it at all: no operation authors it (`epiphany-ops` has no tuning-context payload anywhere — the vocabulary's only `tuning` references are the per-pitch `TuningReference::Inherit`), and `MaterializedState` carries effects, conflicts, anomalies, objects, spellings, breaks, page-breaks, and pending, but no tuning context. So a user who selects a tuning system or sets a per-voice override has authored something the format cannot durably represent, and `req:tuning:tuning-resolution-order`'s scopes 2–4 (`overrides`) are in practice unreachable from any document a replica could exchange | this file (found 2026-07-24 while scoping text-projection parity; verified by searching the whole `epiphany-ops` operation vocabulary and `MaterializedState`'s field list) | **CLOSED by genesis tranche G2b** (`spec/CONTRACT_GENESIS_G2B_TUNING.md`). `SetTuningContext` — kind/tag **34**, schema major **3**, minor epoch **10** — makes an operation author the tuning context, and the op log is canonical. **The closure argument is the `metadata` precedent, not the canonical base:** the base embeds no graph values for *any* field, including `metadata`, which has been op-authored since M2d and is durable purely through its operations. The rung paid the accept-set raise this entry predicted (`OperationEnvelopeBlock` 2→3), charged to this one surface because minimal stamping is a pure function of each payload's value and `ScoreTuningContext` is the only genesis payload born at v3. **The payload carries `epiphany_core::TuningContextSettings`, a five-field subset, not the full graph type** — `accidental_extensions` is staged off the wire, so a full-value payload would have diverged between a live session and the same document reloaded, and `canonical_value!` could not have caught it (it compares bytes, never the originating value). Reduction leaves that field untouched. *Original filing and disposition follow.* — `spec/RULING_GENESIS_PERSISTENCE.md` (ratified 2026-07-24, 011c68a) reverses Pass-12 K8 and absorbs genesis into the operation set, naming `SetTuningContext` in its §2 settings table. **This was not a tuning-specific defect and did not get a tuning-specific fix:** the operation arrives as one of nine surfaces in a single coordinated tranche, and the wire layout is untouched. **The disposition, and the evidence that produced it:** `spec/ANALYSIS_GENESIS_PERSISTENCE.md` maps the same gap across the whole `Score`: **eight fields have no operation that can produce them** — `canvas.layout_defaults`, `instruments`, `staff_groups`, `parts`, `tuning_context` (this entry, its field 10), `spelling_precedence`, `analysis_layers`, `views`, plus `identity` — and one more (`decomposition_attachments`) can only be pruned back, never authored. Independently re-verified against the working tree: each field's sole `reduce.rs` mention is a read-only base-seed read. Of the four dispositions weighed there (a canonical genesis block; closing the op-coverage gap; promoting the canonical base to carry graph values; scope-limiting), **the second was taken** — every mutable `Score` field becomes operation-authored — so S13 closes when that tranche lands and is tracked *there*, not here. **One cost this entry contributes as evidence:** the per-field operation route is not the free schema-minor it appears. Blocks stamp *minimally*, at the lowest major whose layouts decode them, and `bundle.rs`'s `max_supported_major` currently caps `OperationEnvelopeBlock` at **2** on the explicit ground that no operation payload embeds the tuning context. A `SetTuningContext`-style operation would make its blocks stamp v3, dragging a role accept-set raise along with the kind append — for one field of eight. That is a concrete instance of the analysis's closing constraint, that any option enumerating fields must be re-audited against its table whenever `Score` gains a field. **This cost is now paid deliberately rather than avoided — but NOT amortised, as first written.** The ruling's "one accept-set raise, spent once" implied a single batch landing every new kind at `OperationEnvelopeBlock` major 3, spreading the raise across nine surfaces. Re-derived 2026-07-28 against the working tree, that is wrong: minimal stamping is a pure function of each payload's value, so the other eight surfaces stamp at major 0, 2, or 2 and never reach the raised bound at all. `SetTuningContext` is the sole payload born at v3, so the raise is charged to **exactly this surface** after all — which is why `spec/PLAN_GENESIS_OPS.md` §4 splits G2 and isolates it in **G2b**. **And the closure argument is not the canonical base:** the base is role-bound to major 0 (`mis_stamped_canonical_base`) and is a `MaterializedState`, which embeds no graph values for *any* field — including `metadata`, op-authored since M2d and durable purely through its operations. S13 closes on that precedent: the op log is canonical, and G2b makes an operation author the tuning context. Consequence to carry forward: once G2b lands, pruning would discard *authored* genesis state rather than merely re-derivable state, so the standing prohibition on pruning (blocked on disposition C) gains real teeth. Note `bundle.rs` documents the cap of 2 *with the tuning-context rationale in prose*, so that comment must move with the cap. Note the wire layouts themselves are already frozen and correct under every disposition: this was never about how the tuning context encodes, only about which carrier embeds it. Not a regression — nothing ever worked; major 3 made the gap visible by giving the value a wire form and no way to reach it) | | P13-S14 | **The chunk schema *minor* is a normative MUST that no writer has ever honoured, so every appended operation discriminant is unattributable to version skew.** `binary_format.tex:2330` requires a writer to raise the chunk schema minor when it emits any discriminant appended after the minor it otherwise declares, with a stated rationale: so that a decode failure on an unknown appended discriminant is attributable to a version skew rather than to corruption. `SchemaVersion::for_major` (`bundle/src/ids.rs:204`) maps a major to a fixed constant — `V0` is `{0, 1}`, not `{0, 0}` (`ids.rs:173`), and `V1`/`V2`/`V3` carry minor 0 — and, decisively, **takes only a major**, so no per-kind additive minor can reach it — and **both** writer-side staging paths derive nothing but the major (`testkit/src/bundle_harness.rs:25`, `textproj/src/serialize.rs:183`, each mapping `max(OperationEnvelope::schema_major)` through `for_major`). So every kind appended after the initial vocabulary has no additive-version record: **24–27** (Phase-3 first tranche), **28–29** (the schema-major-2 repeat revision), **30** (Push 4a `TransposeInterval`), and **31** (genesis G1 `CreateInstrument`). The requirement's own failure mode is exactly what the gap produces: a reader meeting kind 31 from a newer writer cannot distinguish "my vocabulary is stale" from "these bytes are damaged" | this file (found 2026-07-28 during G2a contract review; verified against the working tree — `for_major`'s signature admits no minor, and neither staging path computes one) | **RESOLVED at `ff9bd0f`** (the G-minor rung, 2026-07-28). Epoch ladder ratified as minors 2–9, one per additive event, complete against `spec/AUDIT_GMINOR_VOCABULARIES.md` and monotonic in the introducing commits' order. `introduced_minor()` landed on the five vocabularies with post-baseline variants, exhaustive and wildcard-free; envelope minor = max over emitted, block = max over envelopes, major and minor derived independently; baselines not normalised. **Two things the filing did not anticipate**, both from the audit that gated the rung: the scope was never just `OperationKind` (`OperationPayload` 3, `ReanchorReason` 6 and `PreconditionFailureReason` 10–15 also append), and the **manifest** reaches `OperationKindTag` through `edit_barriers` with no operation envelope in it — so the "no companion bump" note below is **superseded**: `TextDocument` carries the manifest `SchemaVersion` it cannot derive, and the companion moved 0.9.0 → 0.10.0. Op-block stamping did remain projection-invisible, exactly as scoped. Gate `[7f]` guards the manifest aggregate with an exact-equality oracle. *Original filing follows.* Ruled 2026-07-28: policy ratified 2026-07-28 as a **global additive epoch with content-minimal stamping** (`spec/PLAN_GMINOR_SCHEMA_MINOR.md` §4); the fix is its own rung, sequenced **after G2a and before G2b** — G2b appends kind 34, so running it first would either grow this sweep mid-flight or ship 34 with the very defect the rung retires. G2a appends kinds 32/33 and takes the violation from eight kinds to ten, knowingly — the debt is already eight deep, the +2 is immaterial against it, and one retroactive sweep over 24–33 is strictly less work than 24–31 now and 32–33 later. **What the rung owes:** a minor-assignment policy (which minor each past append belongs to — this is a retroactive judgement, not a derivation), a per-kind `schema_minor()` or equivalent, block minor = max over payloads, a `for_major` replacement that accepts one, and both staging paths. **Scoped 2026-07-28:** the minor IS in the chunk content-address preimage (`chunk_content_hash`, `chunk.rs:177`), so raising it moves every affected `ChunkId` and the manifest body naming it — real address churn, though **not** a `req:format:manifest-id` problem, since that promise is conditional on the same manifest body. It does **not** reach the text projection: op-block schemas are discarded during projection (`textproj/src/project.rs:424`), so no companion bump. And the problem is **not** per-`OperationKind`: an envelope also emits the outer `OperationPayload` discriminant (`ResolveEquivocation` = 3 carries no kind at all), so the gating work is an audit of every append-only vocabulary reachable from an affected payload. Note this is orthogonal to the *major* accept-set: `OperationEnvelopeBlock` stays at 2 through G2a and rises to 3 only at G2b | | P13-S15 | **The `OperationKind` wire golden lock stops at discriminant 29, so kinds 30–39 — ten of them, every kind appended since the lock was written — have no byte-level lock at all.** `operation_kind_wire_discriminants_are_golden` (`crates/epiphany-ops/src/payload.rs:2189`) declares `let table: [(OperationKind, u8); 30]` (`:2233`), covering 0..=29 and asserting for each that `kind.discriminant()` has not moved *and* that the discriminant byte truly leads the canonical encoding. **Absent from that table: `TransposeInterval` (30, Push 4a), `CreateInstrument` (31, G1), `SetCanvasLayoutDefaults` (32) and `SetSpellingPrecedence` (33, G2a), `SetTuningContext` (34, G2b), `CreateStaffGroup` (35), `CreatePartDefinition` (36), `CreateAnalysisLayer` (37) and `CreateView` (38, G3a), and `CreateMeasure` (39, G3b).** Their wire discriminants are unlocked: a hand edit to `OperationKind::discriminant()`'s match — itself the site Push 4a got wrong — would move any of the ten silently, and the encoding-leads-with-the-byte assertion never runs for them. **The shape is the failure this project keeps rediscovering:** a hand-maintained parallel table that quietly stopped being extended, exactly like the four literal sites found at Push 4a and the six found during G2a — and the golden lock is the one guard specifically meant to catch that class, so its own staleness is the worst place for it. The gap widened from four kinds to ten while the entry sat open, which is itself the argument for closing it now that the genesis ladder has stopped appending | this file (found 2026-07-28 by the G-minor implementation while building s1's coverage; **scope corrected 2026-07-30**, after the genesis ladder closed at G3b — the original text scoped the repair to kinds 30–33 and an array length of `; 34`, both of which were accurate when written and are now six kinds short. Re-verified against the working tree at `4f141ce`: the length literal is still `30`, and no arm for 30–39 appears in the table) | **RESOLVED 2026-07-30** (its own rung, no rider). **Never a live incorrectness:** every one of the ten discriminants was correct throughout, and `binary_format.tex:1443`ff (kind table rows 30–39) and `:1548`–`:1552` (tag table rows 30–39) carry them normatively — the gap is the *absence of a guard*, not a wrong byte. **The repair, as landed:** `operation_kind_wire_discriminants_are_golden`'s table goes from 30 to **40** entries, locking kinds 30–39 individually — each row asserting both that `kind.discriminant()` has not moved and that the discriminant byte leads the canonical encoding. **No wire, schema-version, or specification change**: this adds a guard over assignments that were already normative. **Mutation evidence:** `OperationKind::discriminant()`'s `SetTuningContext` arm was edited 34 → 44 and the extended lock failed (*"wire discriminant for SetTuningContext moved — canonical encodings are append-only"*); with the same mutation still applied, restricting the loop to `&table[..30]` — the exact pre-repair coverage — made it **pass**, which is P13-S15 itself reproduced in the tree rather than argued for. Both edits restored by hand. **On the sibling:** the tag half is total by construction and needs no extension. `the_tag_vocabulary_is_complete` (`payload.rs:2652`) is derived, not hand-written — it computes `first_unknown_discriminant()` from `PAYLOAD_FREE`'s maximum and asserts the payload-free discriminants are exactly `0..unknown` minus `Registered`'s, dense and each decoding — so it already covers 30–39, and `operation_kind_tag_vocabulary!` makes a tag without a discriminant a compile error rather than a silent omission. **One residue, scoped out and stated rather than papered over:** density plus round-trip does not pin *which* tag holds which byte, so a permutation inside the dense range (swapping two assigned discriminants) survives both that test and `phase3_tag_discriminants_are_golden` (`payload.rs:2728`), which pins literals for 24–29 only. The same permutation on the *kind* side is caught by this rung's extended table. The tag-side gap is **not** part of this rung and is **filed as P13-S22** rather than left as a closing remark — a residue recorded only inside a resolved row is a residue that gets lost | -| P13-S16 | **`StaffGroup.members` and `Staff.group` may disagree in both directions, and nothing detects it.** The two fields encode the same relation twice. `Staff.group` (`core_spec.tex:5592`, `graph.rs:848`) names the group a staff belongs to; `StaffGroup.members` (`core_spec.tex:4242`, `graph.rs:1650`) lists the staves in a group. **The specification declares both and states neither an authority nor an agreement requirement.** Graph invariant 10 checks that each side *resolves* — a staff's group is declared (`invariants.rs:1188`), a group's members are declared (`invariants.rs:1196`) — and never that the two agree, so **both stale forms pass every check in the tree**: a *missing* member (`s.group == Some(g)` while `g.members` omits `s`) and a *spurious* member (`g.members` contains `s` while `s.group` is `None` or names a different group). Genesis G3a ruled `Staff.group` the sole authority and `StaffGroup.members` a non-authoritative denormalized projection (`spec/CONTRACT_GENESIS_G3A_ENTITIES.md` §1.1, disposition B, ratified 2026-07-29) — a normative semantic ruling that makes the disagreement *defined* rather than merely undetected, but does not make it *impossible*: G3a stores the projection without maintaining it | `spec/CONTRACT_GENESIS_G3A_ENTITIES.md` §1.1 (found 2026-07-29 during G3a contract review; the authorship cycle is what surfaced it — with mints only, no authoring order produces an agreeing pair, since `CreateStaff` requires its group live at `reduce.rs:4372` and `CreateStaffGroup` requires its members live) | **open.** Deliberately no code change in G3a. The fix is disposition **A**: maintain the projection under reduction — `create_staff` with `group: Some(g)` appends to `g.members` — plus a candidate **graph invariant 21** enforcing agreement in both directions (20 exist; `invariants.rs:149` and the count guard at `:6064` both move), and a decision on whether a re-carried `CreateStaffGroup` compares against its *carried* `members` (empty) or the current derived state. **Consumers must read `Staff.group`, never `StaffGroup.members`, for membership** until that lands. The G3b sequencing note is now discharged — G3b landed, and invariant 20 is no longer competing. **Locators corrected 2026-07-31**; every code citation in this row had drifted, some by hundreds of lines, and `spec/CONTRACT_GENESIS_G3A_ENTITIES.md` carries two of the same stale pointers (corrected separately, citation-only). **The concrete implementation cost, which this row did not state:** `t8b_both_permitted_stale_forms_hold` (`reduce.rs:16340`) **pins both stale forms as passing** — asserting `staff.group == Some(g)` while `g.members == vec![]`, and `g2.members == vec![staff2]` while `staff2.group == None` — and its own doc block (`:16317`–`:16339`) names disposition A's two maintenance rules as mutations that **must break** it. So the fix is precisely the mutation an existing test exists to detect: that test must be rewritten, not merely supplemented, and rewriting it is the rung's real cost. **Complete participant set**, none of it obvious from the two field declarations: `create_staff` (`reduce.rs:4330`) and `create_staff_group` (`:4458`); both byte-identical re-carry comparators (`:4334`, `:4466`), which under A must compare the **carried** value, never the derived one; both undo `retain` arms (`:2967`, `:2977`), where undoing a `CreateStaff` currently leaves its id in a live group's `members` with no guard — the reverse direction is guarded at `:6736` and this one is not; base ingest (`:1604`, `:1611`), which can seed a disagreeing pair from a blob authored before the rule; `valuegen::staff_group` (`valuegen.rs:376`), which documents that it never normalizes; and the four G3a undo-repair tests (`:16838`, `:16992`, `:17138`, `:17345`) that each construct the missing-member form. **No schema consequence:** `CreateStaffGroup` is schema major 0 and the accept-set does not move — but if A normalizes at *construction or decode* rather than at reduction, the pinned literal-byte vector at `ops/src/vectors.rs:829` and the text-projection golden at `textproj/src/vectors.rs:198` both break on re-encode injectivity. Reduction-time refusal leaves both untouched — the design fork is resolved that way in the contract. **Scoped 2026-07-31 as `spec/CONTRACT_P13S16_PROJECTION.md` (DRAFT), and immediately BLOCKED on P13-S27.** Two findings from that scoping changed the rung's size in opposite directions. **Cheaper than feared:** the refusal needs no new `PreconditionFailureReason` and no schema-minor epoch — `reduce.rs:1236`'s `container_not_empty()` helper already covers "a create carrying children" by its own doc, and three creates already call it for exactly this shape (`create_region` `:4174`, `create_staff_instance` `:4246`, `create_voice` `:4310`); `create_staff_group` is the sole outlier. **More expensive than feared:** this is a **canonical reduction-semantics change** — the same operation set now reduces to a different `Score` — so `core_spec.tex:11614` applies: canonical bases materialized beforehand cannot be reused without rebuilding. That requirement is currently **unenforceable** (P13-S27), so the rung may not execute until S27 has a disposition. Also found while scoping: base ingest (`reduce.rs:1619`) reseeds `staff_group_values` from the *maintained* value, so a snapshot round trip launders derived members into the carried slot and a re-carry misverdicts **only after a reload**; and `t6` (`:16154`), `t7` (`:16229`) and `t9` (`:16454`) each assert behaviour the refusal removes, alongside the already-known `t8b`. **Blocking chain, 2026-07-31: S16 → P13-S27 → P13-S28.** S16 does **not** become dispatchable when S27 lands; it additionally needs S27's pin-2a legacy-base disposition, which S28 owns. **UNBLOCKED 2026-08-09 — P13-S27 landed and was accepted at `4df8e25`.** The preceding sentence is **superseded**: pin 2a's legacy-base disposition was settled from *outside* S27, by the format-epoch rung's pin 8 (legacy bases are refused by container epoch, never by version arithmetic), so the extra condition it names no longer exists — S27's pin 10 was amended in review round 12 for exactly this reason. **An authority now exists** (`epiphany_ops::CURRENT_REDUCTION_ALGORITHM_VERSION`, currently `0`) and a stale base is refused with `CanonicalBaseRequiresRebuild` on both the read and write paths, so pin 0's blocker is discharged. **UNBLOCKED IS NOT DISPATCHABLE:** `spec/CONTRACT_P13S16_PROJECTION.md` is a **DRAFT** and has not been through adversarial review; it needs ratification before dispatch, and its pin 11 was amended the same day since it mandated a ledger state ("blocked on P13-S27") that had become false. **RATIFIED 2026-08-09 at `25b4925`, on the authority of the repository owner, after twelve independent whole-artifact rounds — the last returning zero findings; the preceding sentence's "has not been through adversarial review" is superseded.** **PINS FROZEN**: executed, not edited; a defect found during execution is reported as its own amendment with its own review round. **DISPATCHABLE but NOT DISPATCHED — nothing is implemented, so this row does NOT move to RESOLVED.** 32 findings closed before ratification (19 in draft amendment 1 and revisions A–J, 13 across rounds 1–11); **none was in the pins' substance** — the maintenance rule, the refusal, invariant 21, the undo strip and the authority bump have been stable since draft amendment 1, and every finding was in the evidence apparatus. Two cells of §3's expected-outcome table (`t8d` under M2, `t9` under M1) are **predictions to be falsified at execution**, and §4a's landing obligation is outstanding by construction. **This rung's first act is bumping the authority to `1`**, because it changes `CreateStaffGroup`'s reduction verdict **EXECUTED 2026-08-09 — implementation complete and left in the worktree for review; NOTHING IS STAGED and nothing is accepted, so this row does NOT move to RESOLVED.** The refusal reuses **`ContainerNotEmpty`** (discriminant 10); a new `PreconditionFailureReason` was considered and proved **unnecessary** — the existing reason describes exactly this precondition, and adding one would move the accept set for no gain. The **base-ingest hazard** is closed by seeding `staff_group_values` with `members` emptied in `seed_from_graph`: a `group.clone()` there launders the *derived* value into the carried slot, so the re-carry misverdicts `RecreateContentMismatch` only **after a reload**, and `t8d` is the only test that crosses that boundary. **`t8b` inverted** to `t8b_the_projection_is_maintained_and_the_spurious_form_is_refused`, keeping both authoring orders with the verdicts reversed. **`t6`/`t7`/`t9` revised**: `t6`'s `CreateStaffGroup` arm now expects `ContainerNotEmpty` and no longer tests a referential loop; `t7`'s arm **inverts**, because an empty-container precondition asks only about the carried value and therefore refuses base-free too; `t9`'s group carries `[]` and its mutation set shrinks from three loop-drops to two. **The authority is now `1`** — the 'currently `0`' above is superseded — and **per pin 0 any canonical base materialized before this rung MUST be rebuilt, not reused**, since it holds state these semantics would not have computed; `open` and `commit` both refuse it with `CanonicalBaseRequiresRebuild`. **Execution reported four findings against the contract rather than patching pins:** (i) §0.6, pin 5a and pin 6b attribute the undo residue to invariant 21, which **abstains** on dangling members — M5 observed invariant 10 `CrossCuttingRefsResolve` firing instead, so that hole was already covered and `u5`'s direct members assertion is what signs pin 5; (ii) §3's M6a row names **six** failing tests where the observed set is **seven**, because its four-`all()`-consumer list omits `crates/epiphany-core/tests/score_graph.rs:146`; (iii) pin 10 cites **four of the nine** sites its instruction covers — eight carrying disposition-B semantics, plus `core_spec.tex`'s 'exactly 20 invariants' count sentence, which is not disposition-B prose and which gate 6 cannot see because it checks only that the enumeration ends at 21; (iv) `cargo test --workspace` **truncates** the failure set at the first failing suite, so every mutation run needs `--no-fail-fast` to produce the complete set §3 requires | +| P13-S16 | **`StaffGroup.members` and `Staff.group` may disagree in both directions, and nothing detects it.** The two fields encode the same relation twice. `Staff.group` (`core_spec.tex:5592`, `graph.rs:848`) names the group a staff belongs to; `StaffGroup.members` (`core_spec.tex:4242`, `graph.rs:1650`) lists the staves in a group. **The specification declares both and states neither an authority nor an agreement requirement.** Graph invariant 10 checks that each side *resolves* — a staff's group is declared (`invariants.rs:1188`), a group's members are declared (`invariants.rs:1196`) — and never that the two agree, so **both stale forms pass every check in the tree**: a *missing* member (`s.group == Some(g)` while `g.members` omits `s`) and a *spurious* member (`g.members` contains `s` while `s.group` is `None` or names a different group). Genesis G3a ruled `Staff.group` the sole authority and `StaffGroup.members` a non-authoritative denormalized projection (`spec/CONTRACT_GENESIS_G3A_ENTITIES.md` §1.1, disposition B, ratified 2026-07-29) — a normative semantic ruling that makes the disagreement *defined* rather than merely undetected, but does not make it *impossible*: G3a stores the projection without maintaining it | `spec/CONTRACT_GENESIS_G3A_ENTITIES.md` §1.1 (found 2026-07-29 during G3a contract review; the authorship cycle is what surfaced it — with mints only, no authoring order produces an agreeing pair, since `CreateStaff` requires its group live at `reduce.rs:4372` and `CreateStaffGroup` requires its members live) | **open.** Deliberately no code change in G3a. The fix is disposition **A**: maintain the projection under reduction — `create_staff` with `group: Some(g)` appends to `g.members` — plus a candidate **graph invariant 21** enforcing agreement in both directions (20 exist; `invariants.rs:149` and the count guard at `:6064` both move), and a decision on whether a re-carried `CreateStaffGroup` compares against its *carried* `members` (empty) or the current derived state. **Consumers must read `Staff.group`, never `StaffGroup.members`, for membership** until that lands. The G3b sequencing note is now discharged — G3b landed, and invariant 20 is no longer competing. **Locators corrected 2026-07-31**; every code citation in this row had drifted, some by hundreds of lines, and `spec/CONTRACT_GENESIS_G3A_ENTITIES.md` carries two of the same stale pointers (corrected separately, citation-only). **The concrete implementation cost, which this row did not state:** `t8b_both_permitted_stale_forms_hold` (`reduce.rs:16340`) **pins both stale forms as passing** — asserting `staff.group == Some(g)` while `g.members == vec![]`, and `g2.members == vec![staff2]` while `staff2.group == None` — and its own doc block (`:16317`–`:16339`) names disposition A's two maintenance rules as mutations that **must break** it. So the fix is precisely the mutation an existing test exists to detect: that test must be rewritten, not merely supplemented, and rewriting it is the rung's real cost. **Complete participant set**, none of it obvious from the two field declarations: `create_staff` (`reduce.rs:4330`) and `create_staff_group` (`:4458`); both byte-identical re-carry comparators (`:4334`, `:4466`), which under A must compare the **carried** value, never the derived one; both undo `retain` arms (`:2967`, `:2977`), where undoing a `CreateStaff` currently leaves its id in a live group's `members` with no guard — the reverse direction is guarded at `:6736` and this one is not; base ingest (`:1604`, `:1611`), which can seed a disagreeing pair from a blob authored before the rule; `valuegen::staff_group` (`valuegen.rs:376`), which documents that it never normalizes; and the four G3a undo-repair tests (`:16838`, `:16992`, `:17138`, `:17345`) that each construct the missing-member form. **No schema consequence:** `CreateStaffGroup` is schema major 0 and the accept-set does not move — but if A normalizes at *construction or decode* rather than at reduction, the pinned literal-byte vector at `ops/src/vectors.rs:829` and the text-projection golden at `textproj/src/vectors.rs:198` both break on re-encode injectivity. Reduction-time refusal leaves both untouched — the design fork is resolved that way in the contract. **Scoped 2026-07-31 as `spec/CONTRACT_P13S16_PROJECTION.md` (DRAFT), and immediately BLOCKED on P13-S27.** Two findings from that scoping changed the rung's size in opposite directions. **Cheaper than feared:** the refusal needs no new `PreconditionFailureReason` and no schema-minor epoch — `reduce.rs:1236`'s `container_not_empty()` helper already covers "a create carrying children" by its own doc, and three creates already call it for exactly this shape (`create_region` `:4174`, `create_staff_instance` `:4246`, `create_voice` `:4310`); `create_staff_group` is the sole outlier. **More expensive than feared:** this is a **canonical reduction-semantics change** — the same operation set now reduces to a different `Score` — so `core_spec.tex:11614` applies: canonical bases materialized beforehand cannot be reused without rebuilding. That requirement is currently **unenforceable** (P13-S27), so the rung may not execute until S27 has a disposition. Also found while scoping: base ingest (`reduce.rs:1619`) reseeds `staff_group_values` from the *maintained* value, so a snapshot round trip launders derived members into the carried slot and a re-carry misverdicts **only after a reload**; and `t6` (`:16154`), `t7` (`:16229`) and `t9` (`:16454`) each assert behaviour the refusal removes, alongside the already-known `t8b`. **Blocking chain, 2026-07-31: S16 → P13-S27 → P13-S28.** S16 does **not** become dispatchable when S27 lands; it additionally needs S27's pin-2a legacy-base disposition, which S28 owns. **UNBLOCKED 2026-08-09 — P13-S27 landed and was accepted at `4df8e25`.** The preceding sentence is **superseded**: pin 2a's legacy-base disposition was settled from *outside* S27, by the format-epoch rung's pin 8 (legacy bases are refused by container epoch, never by version arithmetic), so the extra condition it names no longer exists — S27's pin 10 was amended in review round 12 for exactly this reason. **An authority now exists** (`epiphany_ops::CURRENT_REDUCTION_ALGORITHM_VERSION`, currently `0`) and a stale base is refused with `CanonicalBaseRequiresRebuild` on both the read and write paths, so pin 0's blocker is discharged. **UNBLOCKED IS NOT DISPATCHABLE:** `spec/CONTRACT_P13S16_PROJECTION.md` is a **DRAFT** and has not been through adversarial review; it needs ratification before dispatch, and its pin 11 was amended the same day since it mandated a ledger state ("blocked on P13-S27") that had become false. **RATIFIED 2026-08-09 at `25b4925`, on the authority of the repository owner, after twelve independent whole-artifact rounds — the last returning zero findings; the preceding sentence's "has not been through adversarial review" is superseded.** **PINS FROZEN**: executed, not edited; a defect found during execution is reported as its own amendment with its own review round. **DISPATCHABLE but NOT DISPATCHED — nothing is implemented, so this row does NOT move to RESOLVED.** 32 findings closed before ratification (19 in draft amendment 1 and revisions A–J, 13 across rounds 1–11); **none was in the pins' substance** — the maintenance rule, the refusal, invariant 21, the undo strip and the authority bump have been stable since draft amendment 1, and every finding was in the evidence apparatus. Two cells of §3's expected-outcome table (`t8d` under M2, `t9` under M1) are **predictions to be falsified at execution**, and §4a's landing obligation is outstanding by construction. **This rung's first act is bumping the authority to `1`**, because it changes `CreateStaffGroup`'s reduction verdict **EXECUTED 2026-08-09 — implementation complete and left in the worktree for review; NOTHING IS STAGED and nothing is accepted, so this row does NOT move to RESOLVED.** The refusal reuses **`ContainerNotEmpty`** (discriminant 10); a new `PreconditionFailureReason` was considered and proved **unnecessary** — the existing reason describes exactly this precondition, and adding one would move the accept set for no gain. The **base-ingest hazard** is closed by seeding `staff_group_values` with `members` emptied in `seed_from_graph`: a `group.clone()` there launders the *derived* value into the carried slot, so the re-carry misverdicts `RecreateContentMismatch` only **after a reload**, and `t8d` is the only test that crosses that boundary. **`t8b` inverted** to `t8b_the_projection_is_maintained_and_the_spurious_form_is_refused`, keeping both authoring orders with the verdicts reversed. **`t6`/`t7`/`t9` revised**: `t6`'s `CreateStaffGroup` arm now expects `ContainerNotEmpty` and no longer tests a referential loop; `t7`'s arm **inverts**, because an empty-container precondition asks only about the carried value and therefore refuses base-free too; `t9`'s group carries `[]` and its mutation set shrinks from three loop-drops to two. **The authority is now `1`** — the 'currently `0`' above is superseded — and **per pin 0 any canonical base materialized before this rung MUST be rebuilt, not reused**, since it holds state these semantics would not have computed; `open` and `commit` both refuse it with `CanonicalBaseRequiresRebuild`. **Execution reported four findings against the contract rather than patching pins:** (i) §0.6, pin 5a and pin 6b attribute the undo residue to invariant 21, which **abstains** on dangling members — M5 observed invariant 10 `CrossCuttingRefsResolve` firing instead, so that hole was already covered and `u5`'s direct members assertion is what signs pin 5; (ii) §3's M6a row names **six** failing tests where the observed set is **seven**, because its four-`all()`-consumer list omits `crates/epiphany-core/tests/score_graph.rs:146`; (iii) pin 10 cites **four of the nine** sites its instruction covers — eight carrying disposition-B semantics, plus `core_spec.tex`'s 'exactly 20 invariants' count sentence, which is not disposition-B prose and which gate 6 cannot see because it checks only that the enumeration ends at 21; (iv) `cargo test --workspace` **truncates** the failure set at the first failing suite, so every mutation run needs `--no-fail-fast` to produce the complete set §3 requires **ACCEPTED AND LANDED 2026-08-10 at `aee4ff9`, on the authority of the repository owner, after nineteen independent review rounds during execution.** The `EXECUTED … NOTHING IS STAGED` sentence above is **superseded**: the fourteen touch-table paths are committed and the working tree is clean. **RESOLVED — IMPLEMENTED 2026-08-10 (`aee4ff9`).** The rung's six findings against its own contract stand unamended and are the outstanding follow-up: (i) invariant 21's dangling abstention vs the undo-hole attribution in §0.6, pin 5a and pin 6b; (ii) §3's M6a row naming six failing tests where seven are observed; (iii) §3's `t8d`-under-M2 survivor cell, falsified — it fails on non-vacuity, not idempotence; (iv) pin 10 citing four of the nine sites its instruction covers; (v) `cargo test --workspace` truncating the failure set without `--no-fail-fast`; (vi) pin 8's drifted line numbers. **`spec/EVIDENCE_P13S16_EXECUTION.md` holds the verbatim runs behind all of it** — deliberately untracked, since no touch row covers it. `CLAUDE.md` and `spec/HANDOFF_2026-08-07.md` were reconciled in a separate commit after acceptance, per §4a | | P13-S17 | **Binary Format revision history omitted genesis tranche G2b entirely, including the accept-set raise it performed.** `spec/binary_format.tex`'s Revision History chapter ran G2a 0.12.0 straight to G-minor 0.13.0 to G3a 0.14.0, with no row anywhere recording G2b (`spec/CONTRACT_GENESIS_G2B_TUNING.md`, kind/tag 34, `SetTuningContext`) — even though `OperationEnvelopeBlock`'s accept-set raise 2→3, the first accept-set move since genesis tranche G2a explicitly recorded staying at 2, reached the normative tables (the per-chunk-role accept-set prose at `binary_format.tex:2353`–`:2363`, which names the `OperationEnvelopeBlock` role's maximum as 3 "as of genesis tranche G2b", and the `OperationKind` minor-additive bullet at `:2395`–`:2418`, which records "genesis tranche G2b took 34 (`SetTuningContext`)") and never the history. G2b's own contract touch table row 27 required "version, Revision History row" among the four-document ritual, and the rung was signed off without it — the gate did not catch a documentation MUST because nothing tests the revision history | `spec/CONTRACT_GENESIS_G3A_UNDO_REPAIR.md` §0 (found 2026-07-29 during the G3a undo-repair contract review, verified against the working tree: `binary_format.tex:3599`, `:3628`, `:3643` before this rung's edit) | **RESOLVED in this same commit.** The chronology is restored: G2b lands as its own 0.14.0 row between G-minor and G3a, and G3a renumbers to 0.15.0 (`spec/CONTRACT_GENESIS_G3A_UNDO_REPAIR.md` Packet B, pins B2–B3). A new scoped guard in `epiphany-testkit` makes the omission recurrence-detectable — a distinct principal marker per standalone-row rung (G2a, G-minor, G2b, G3a — G1 is deliberately unguarded, having no standalone row of its own), strictly ordered, with G2b's content anchored within its own row segment — so the entry is filed and closed by the same packet that finds it, unlike **P13-S15** and **P13-S16**, which stay open because their fixes are sequenced to later rungs | | P13-S18 | **Graph invariant 20's agreement and boundary-consistency checks are partial, but only three of the checker's nine non-success paths are the real gap — not the whole checker, as first filed and over-sized.** `check_measure_meter_consistency` (`invariants.rs:2662`) has nine non-success paths across its two clauses, enumerated and classified by both its own doc comment and `spec/CONTRACT_P13S18_MATRIX.md`'s 18-cell outcome matrix (agreement: A1-A4; boundary: B1-B5). A1 (`None` declared signature) is **inapplicable** — nothing to disagree with. A3/B3 (`Governing20::None`, an empty governing candidate set) are **vacuous** (pin 6c case 1). A2/B2 (an unresolving declared or governing signature) are **delegated** to invariant 10's own resolution check (`invariants.rs:1220`ff, its per-measure and instance-local-grid arms) — verified, not merely asserted: the matrix rung's mutations M7/M8 delete each arm in turn and show the SAME condition go unreported by the ENTIRE workspace suite, not merely by invariant 20. B1 (the first measure) is the already-filed pickup/anacrusis deferral, **P13-S19**. **Exactly three paths are genuine abstention: A4 and B4 (`Governing20::Indeterminate` — the comparable relation cannot place a candidate) and B5 (a decided governing selection with no computable musical delta — order without distance).** Also corrected: the earlier **"any `Measure` *end* anchor is incomparable"** claim was wrong only in its "any" — same-id, same-position `End`<->`End` IS comparable under c2 **when its offsets compare** (`measure20_offset_order`, `:2419`, returns `None` only for `Musical` against `WallClock`); distinct-id `End` anchors genuinely are incomparable (c3 restricts to `Start`+`Zero`) and do reach A4/B4/B5; and the `resolve_anchor` `Measure` arm citation (now `:503`-`:516`, formerly miscited as `:400`ff — see the companion line-number repair to `CONTRACT_GENESIS_G3B_MEASURE.md:206`) names the missing duration machinery, not invariant 20's own execution path, which never calls `resolve_anchor`. And the `WallClock`-anchored measure start `epiphany-ops::valuegen::measure` (`ops/src/valuegen.rs:447`) actually emits does **not** uniformly abstain both clauses: against `WallClock`-anchored meter changes (c5) agreement DECIDES and only the boundary clause abstains (B5, since `measure20_musical_delta` never returns a `WallClock` delta); against `Region`-anchored meter changes both abstain (A4/B4), because `WallClock` against `Region` has no comparability arm at all | `spec/CONTRACT_P13S18_MATRIX.md` pin 8 (ratified 2026-07-31, a diagnostic and bookkeeping rung: test coverage over `check_measure_meter_consistency`'s existing nine paths plus these three ledger repairs, no behaviour change) | **open, at its true size.** A4, B4 and B5 remain real, still gated on the deferred common-timeline machinery — but the capability that closes them is now filed as **P13-S23** (below), not P11-C5: P11-C5 is a narrower re-anchoring proximity metric this entry previously over-cited as the gate; P13-S23 is the broader "place any anchor pair on a common timeline and measure musical distance" capability that actually owns A4, B4 and B5 | | P13-S19 | **A pickup's *successor*, not the pickup itself, is what `CreateMeasure` and invariant 20 refuse — pickup/anacrusis measures are authorable, but the rest of the instance becomes unauthorable once one exists.** Genesis tranche G3b (`spec/CONTRACT_GENESIS_G3B_MEASURE.md` pin 9) makes `create_measure`'s clauses 1 (ordering) and 3 (boundary distance) vacuous for a first measure, and invariant 20's boundary clause is symmetrically exempt at `i == 0` — both for lack of a predecessor. **The agreement clause (clause 2) is not predecessor-dependent and applies to a first measure like any other**: a pickup declaring a signature that disagrees with the governing grid is itself refused (`MeasureMeterMismatch`) and flagged; only a pickup declaring `None` or a matching signature clears it, and only when its other preconditions (a live parent `StaffInstance`, resolving referents) are satisfied too. **The real defect is one measure downstream**: both rules compare `delta(prev.start, m.start)` against the *governing signature's full* `measure_duration()`, when the true distance is `prev`'s own content duration — those coincide only for full measures. A pickup's successor is therefore refused (`MeasureMeterMismatch`) by `create_measure` and flagged by invariant 20, which is what actually makes the rest of the instance unauthorable once a pickup is minted. This applies to **any** partial measure, not only a first one: a mid-score partial measure enters successfully (nothing examines its own duration when it is created), while *its* successor is refused the identical way — the failure is always attributed to the measure after the partial one. Closing this needs a per-measure duration — the "partial measure" notion this entry already names — and that is deliberately **not** introduced by the correction that reworded this entry. See also **P13-S24**, the Chapter 3 derived-notation deferral that shares this same missing concept but touches neither invariant 20 nor `CreateMeasure` | `spec/CONTRACT_GENESIS_G3B_MEASURE.md` pin 9 (filed 2026-07-30 during the G3b contract's own drafting); corrected 2026-07-31 by `spec/CONTRACT_P13S19_PARTIAL.md`, which found the original wording true only of the pickup itself and, read as written, indistinguishable from "pickups work" | **open, deliberately.** A pickup/anacrusis authoring story — whatever shape it takes — is later schema-fill work, sequenced after the genesis ladder closes; it now depends on a per-measure duration concept, which does not yet exist |