G3a contract: ten source locators, corrected forward

The ratified reasoning is untouched — every changed token is a bare line
number. What the contract argues, pins, and disposes of is unchanged;
only its pointers move, so a reader following them lands on the code the
sentences describe.

Ten, not the two first found: reduce.rs:4119 and :4117 both name
CreateStaff's group precondition, now :4372; invariants.rs:1126/:1135
name invariant 10's two resolution arms, now :1188/:1196; graph.rs:819
and :1614 name the two fields, now :848 and :1650, cited twice each.

core_spec.tex:5578 appears twice and needed two different corrections —
at the prose it quotes the doc line "Visual grouping: which staff group",
now :5585; in the pin-4b table it parallels :4231's struct declaration,
so it wants `pub struct Staff {`, now :5564. A single substitution would
have been wrong in one of the two places.

Forward, not by amendment: the contract is ratified and pushed, and its
hash is cited by the ledger and the genesis plan.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
This commit is contained in:
Levi Neuwirth 2026-07-31 19:47:43 -04:00
parent f90a5b1c29
commit f876836454
1 changed files with 9 additions and 9 deletions

View File

@ -30,7 +30,7 @@ through base ingest (`reduce.rs:1449``:1563`). No operation mints any of them
Two consequences hold in the tree today: Two consequences hold in the tree today:
* `CreateStaff` validates `Staff.group` against a live `StaffGroup` * `CreateStaff` validates `Staff.group` against a live `StaffGroup`
(`reduce.rs:4119`). Under **from-empty** reduction — the path G1 created and (`reduce.rs:4372`). Under **from-empty** reduction — the path G1 created and
T1b depends on — that precondition is **unsatisfiable**. A document built T1b depends on — that precondition is **unsatisfiable**. A document built
only from operations can never author a grouped staff. only from operations can never author a grouped staff.
* `TimeAnchor::Measure` (`reduce.rs:1280`) can never resolve from empty. That * `TimeAnchor::Measure` (`reduce.rs:1280`) can never resolve from empty. That
@ -50,7 +50,7 @@ user — the shape G2b's `accidental_extensions` pin took.
### The cycle ### The cycle
`CreateStaff` requires its `group` to be a live `StaffGroup` `CreateStaff` requires its `group` to be a live `StaffGroup`
(`reduce.rs:4117`). `CreateStaffGroup` (pin 4) requires each of its `members` (`reduce.rs:4372`). `CreateStaffGroup` (pin 4) requires each of its `members`
to be a live `Staff`. Neither can name the other first, so **with mints only, to be a live `Staff`. Neither can name the other first, so **with mints only,
no authoring order produces a bidirectionally consistent group**: no authoring order produces a bidirectionally consistent group**:
@ -67,10 +67,10 @@ within this packet.**
### Why nothing in the tree decides it ### Why nothing in the tree decides it
Invariant 10 checks resolution in **both** directions independently — a staff's Invariant 10 checks resolution in **both** directions independently — a staff's
group is declared (`invariants.rs:1126`), a group's members are declared group is declared (`invariants.rs:1188`), a group's members are declared
(`:1135`) — and **agreement in neither**. No agreement check exists anywhere in (`:1196`) — and **agreement in neither**. No agreement check exists anywhere in
the crate. The specification declares `StaffGroup.members` the crate. The specification declares `StaffGroup.members`
(`core_spec.tex:4231`) and `Staff.group` (`:5578`, "Visual grouping: which (`core_spec.tex:4231`) and `Staff.group` (`:5585`, "Visual grouping: which
staff group (if any) this staff belongs to") without stating which is staff group (if any) this staff belongs to") without stating which is
authoritative or requiring them to agree. **This is genuinely unspecified, not authoritative or requiring them to agree. **This is genuinely unspecified, not
merely unimplemented.** merely unimplemented.**
@ -260,9 +260,9 @@ Required, all four:
| Site | What it must say | | Site | What it must say |
|---|---| |---|---|
| `core/src/graph.rs:819` — `Staff.group` | **Currently has no doc comment at all.** Write one: this field is the **sole authority** for group membership. | | `core/src/graph.rs:848` — `Staff.group` | **Currently has no doc comment at all.** Write one: this field is the **sole authority** for group membership. |
| `core/src/graph.rs:1614` — `StaffGroup.members` | **Currently has no doc comment at all.** Write one: a **non-authoritative denormalized projection**; MUST NOT be read to decide membership; may be stale in **both** directions. | | `core/src/graph.rs:1650` — `StaffGroup.members` | **Currently has no doc comment at all.** Write one: a **non-authoritative denormalized projection**; MUST NOT be read to decide membership; may be stale in **both** directions. |
| `core_spec.tex` — the `Staff`/`StaffGroup` declarations (`:5578`, `:4231`) | The same authority rule, normatively. This is the document that declared both fields without ranking them, so this is where the ambiguity actually lives. | | `core_spec.tex` — the `Staff`/`StaffGroup` declarations (`:5564`, `:4231`) | The same authority rule, normatively. This is the document that declared both fields without ranking them, so this is where the ambiguity actually lives. |
| `operation_catalog.tex` — the **new** `CreateStaffGroup` section **and** the **existing** `CreateStaff` section (`:1104`) | Explicit stale-form semantics: both the missing and the spurious form are **permitted outcomes**, named as such, with the authoring orders that produce them. `CreateStaff` needs it too — it is the operation that *creates* the missing form, and its section currently promises nothing about the projection. | | `operation_catalog.tex` — the **new** `CreateStaffGroup` section **and** the **existing** `CreateStaff` section (`:1104`) | Explicit stale-form semantics: both the missing and the spurious form are **permitted outcomes**, named as such, with the authoring orders that produce them. `CreateStaff` needs it too — it is the operation that *creates* the missing form, and its section currently promises nothing about the projection. |
Cross-reference **P13-S16** from each, so a reader who meets the disagreement Cross-reference **P13-S16** from each, so a reader who meets the disagreement
@ -368,7 +368,7 @@ Every line number below re-verified against the working tree 2026-07-29.
|---|---| |---|---|
| `crates/epiphany-core/src/codec.rs` | four `canonical_value!` entries (`:3518` list) | | `crates/epiphany-core/src/codec.rs` | four `canonical_value!` entries (`:3518` list) |
| `crates/epiphany-core/src/invariants.rs` | pin 6: invariant-10 doc comment (`:59``:62`) | | `crates/epiphany-core/src/invariants.rs` | pin 6: invariant-10 doc comment (`:59``:62`) |
| `crates/epiphany-core/src/graph.rs` | **pin 4b**: write the authority doc comment on `Staff.group` (`:819`) and the projection doc comment on `StaffGroup.members` (`:1614`) — **neither field is documented today** | | `crates/epiphany-core/src/graph.rs` | **pin 4b**: write the authority doc comment on `Staff.group` (`:848`) and the projection doc comment on `StaffGroup.members` (`:1650`) — **neither field is documented today** |
| `crates/epiphany-core/DECISIONS.md` | the rung's record | | `crates/epiphany-core/DECISIONS.md` | the rung's record |
**Not touched:** `textvalue_graph.rs` (pin 3), `lib.rs` (already exported). No **Not touched:** `textvalue_graph.rs` (pin 3), `lib.rs` (already exported). No