Commit Graph

5 Commits

Author SHA1 Message Date
Levi Neuwirth f876836454 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
2026-07-31 19:47:43 -04:00
Levi Neuwirth 2892e7b2cd Give §1.1's ruling a normative footprint, and fix two impossible mutations
1. The ruling had no normative/API surface. §1.1 assigns authority, but Pin 3
   still said "nothing else in core" and the touch table listed graph.rs under
   "Not touched" -- leaving the contract and P13-S16 as the only carriers of
   supposedly normative meaning while core_spec.tex remained ambiguous. A
   normative ruling that lives only in a contract is not normative.

   Added pin 4b requiring all four sites, and narrowed pin 3 to the codec
   surface ("no other CODE change in core"):

   - graph.rs:819 Staff.group -- sole authority. Note this field has NO doc
     comment today; it must be written, not amended.
   - graph.rs:1614 StaffGroup.members -- non-authoritative projection, must
     not be read for membership, may be stale in both directions. Also
     currently undocumented.
   - core_spec.tex at the Staff/StaffGroup declarations -- the same rule
     normatively. This is the document that declared both fields without
     ranking them, so it is where the ambiguity actually lives.
   - operation_catalog.tex -- explicit stale-form semantics in the new
     CreateStaffGroup section AND the existing CreateStaff section (:1104).
     CreateStaff needs it because it is the operation that creates the
     missing form, and its section currently promises nothing.

   Each cross-references P13-S16. graph.rs moves into the touch table
   (documentation only; no type changes anywhere in core). Added t14 to guard
   the two field doc comments, sliced per-field on t12's discipline since a
   file-wide grep cannot fail here.

2. t8b's two mutations were assigned to the reducer that runs FIRST in each
   order, so neither could reach the state its assertion names:

   - Missing form (CreateStaffGroup then CreateStaff): create_staff_group
     cannot append a staff that does not exist yet. Mutation moved to
     create_staff -- append the newly minted staff to g.members.
   - Spurious form (CreateStaff then CreateStaffGroup): create_staff has no
     later group to repair. Mutation moved to create_staff_group -- reject or
     normalize away the non-empty carried members.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
2026-07-29 11:39:54 -04:00
Levi Neuwirth ec25a5e0c1 Ratify §1.1 as disposition B, and file the gap it defers
Ruling, ratified 2026-07-29:

- Staff.group is the SOLE authority for membership.
- StaffGroup.members is a non-authoritative denormalized projection.
- G3a stores it but neither maintains nor trusts it.
- BOTH stale forms are permitted, equally: 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). The earlier draft
  named only the first, which left the spurious form reading as a bug rather
  than a permitted state.

Withdraws the earlier draft's argument for B. "B adds no semantics while A
does" was wrong: B assigns authority to a field the specification left
unranked, which IS a semantic change. What B defers is enforcement, not
meaning. The honest advantage is narrower -- B adds semantics without adding
machinery, leaving the mint a mint.

Files P13-S16, which makes the contract's "filed gap" claim true; it was
false when written, since no such entry existed. The entry records both
stale forms, the disposition-A fix, candidate invariant 21, the re-carry
comparison question A must answer, and the standing instruction that
consumers read Staff.group and never StaffGroup.members for membership.

Remaining repairs:

- PLAN_GENESIS_OPS.md still claimed G3a "closes the staff-group half".
  Narrowed to satisfiability, matching the contract.
- Boundary accounting normalized to six crossings across both documents: one
  exhaustive-match site plus five literal/prose sentinels. The two classes
  are counted together but named apart because they fail differently -- the
  match site refuses to compile, while every sentinel stays green while
  meaning something narrower than it says.
- t4 now runs four independent mutations, one per struct_codec! layout;
  these are four separate layouts and one mutation signs one of them.
  Collapsing is permitted only if the implementation consolidates them
  behind a shared mechanism, and must be stated if it does.
- t8 split: t8 asserts satisfiability only; new t8b pins BOTH asymmetric
  authoring orders as states the ruling permits, with a mutation each. A
  test pinning one order leaves the other free to change silently.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
2026-07-29 11:34:54 -04:00
Levi Neuwirth 012a2de16d G3a contract repairs: the authorship cycle, and four maps the pin promised without
Five review findings, all confirmed against the tree before repair.

1. StaffGroup/Staff authorship cycle. CreateStaff requires its group live
   (reduce.rs:4117); CreateStaffGroup requires its members live. With mints
   only, NO authoring order yields a bidirectionally consistent group, and the
   inconsistency is unrepairable in-packet -- there is no ModifyStaffGroup and
   deletes are deferred. Invariant 10 checks resolution in both directions
   independently (invariants.rs:1126, :1135) and agreement in neither; the
   spec declares both fields (core_spec.tex:4231, :5578) without saying which
   is authoritative. Added as §1.1, UNRESOLVED, with two dispositions and a
   recommendation -- the shape G2b's accidental_extensions pin took. t8's
   claim is narrowed accordingly: what closes is that CreateStaff's group
   precondition becomes satisfiable, not that a consistent group becomes
   authorable. The unqualified "defect closes" framing was wrong.

2. Pin 4 promised byte-identical re-carry without the machinery that makes it
   work. Comparing "the same value" requires retaining it, and the object map
   holds only Live/Tombstoned. Exactly three carried-value maps exist
   (reduce.rs:999-1007), each threaded through seven sites; G3a needs four
   more, so 28 touch points the first draft omitted entirely. Added pin 4a
   with the seven sites enumerated. Site 4, base seeding, is the one that
   fails silently: a re-carry test that only reduces from empty cannot see a
   missing seed at all. Added t5b (base re-carry) and t13 (each of the four
   seeds killed separately), modelled on G1's documented instrument_values
   precedent at reduce.rs:13264.

3. The companion bump was stale. The tree is at 0.11.0 (G2b bumped it,
   textproj/src/lib.rs:47); the contract repeated G2b's 0.10.0 -> 0.11.0.
   Corrected to 0.11.0 -> 0.12.0 at both sites, with the negative vector
   rejecting 0.11.0.

4. Mutation table repairs:
   - t4's mutation was impossible. A create op's encode_canonical is a single
     push_lp_bytes line over one carried value, so there is nothing in the op
     to reorder. Moved to the carried type's struct_codec! declaration
     (codec.rs:1790), which is where the layout actually lives and is
     self-consistent across both halves -- exactly trap 4's shape.
   - t6 omitted PartDefinition.staves. Now three independent mutations, one
     per referential loop; an uncovered loop is a loop that deletes green.
   - t9 moved fixture and production together, which proves only that a bad
     score fails a checker. Fixture now constant and already dangling; only
     production mutates, one skipped check at a time.
   - t12 could not fail: grepping the whole file matches the implementation
     body, which contains the identifiers the doc comment is meant to gain.
     Now slices the invariant-10 doc block and searches only that.

5. Touch table missed testkit/src/layout_stub.rs:1373, whose 30..=34 range
   restates the coverage claim in prose. Added there and to the plan's trap 6,
   now five boundary-crossing literals rather than four.

Editor authorization recorded as granted narrowly: barriers.rs for the four
exhaustive subjects_of arms only, barrier.rs for the invalid-tag literal,
comment, and assertions 35 -> 39 only. No other change in either crate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
2026-07-29 11:26:41 -04:00
Levi Neuwirth f1ce25f8f8 Ratify the G3 rulings and draft the G3a contract
Folds the three open PLAN_GENESIS_OPS.md §6 rulings, ratified 2026-07-29:

1. Deletes: mints only, all five deferred out of G3. The former "live
   dependents -> container-not-empty" sentence is superseded outright --
   ContainerNotEmpty concerns owned children (effect.rs:156), while the G3
   hazard is dangling inbound references from independently-live objects,
   which would need a new typed reason and its own epoch.
2. decomposition_attachments: derived, not authored.
3. Measure.time_signature: resolution-plus-agreement. An optional explicit
   declaration at the measure start, neither an override of the metric grid
   nor a cache of it. Invariant 20 (G3b) covers agreement and boundary
   consistency only, not reference resolution.

G3 splits: G3a (four root-level mints, kinds/tags 35-38, epoch 11, all
schema major 0) and G3b (CreateMeasure, kind/tag 39, epoch 12, carrying
invariant 20 and a new precondition reason at discriminant 16).

Correction of record: an earlier scoping claimed invariant 10 "covers
cross-cutting refs, not this". False -- read off the variant's doc comment
rather than the check body. Invariant 10 already resolves a staff's group, a
group's members, a part's staves, a view's active layers, and measure and
grid time-signature references (invariants.rs:1122-1156, :1180-1212), tested
at :3596. Its doc comment names none of them, so G3a owes a prose
reconciliation and no enum entry.

Also corrects five drifted citations that a touch table exists to prevent:
reduce.rs 3850->4075 and 2342->2559, barriers.rs 437->313, barrier.rs
1105->1156, text_projection_grammar.rs 307->315; and "five siblings" ->
"four siblings" now that CreateMeasure is its own packet.

Verified against the tree, not assumed: all four carried types are schema
major 0 (no versioned walk exists; both decode_v0_score and the live walk
read them through plain Codec::dec), TypedObjectId already carries all five
variants, and struct_codec! generates TextValue as well as Codec -- so G3a
moves no wire bound, appends no typed id, and needs no textvalue_graph.rs
work. It does close a live defect: every G3 object kind becomes Live only
through base ingest, so CreateStaff's group precondition is currently
unsatisfiable under from-empty reduction.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
2026-07-29 11:12:49 -04:00