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
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
Kind and tag 34, schema major 3, minor epoch 10. The last rung before G3, and
the one that closes P13-S13: the tuning context becomes operation-authored, so
it finally has a canonical carrier. The closure argument is the metadata
precedent, not the canonical base - the base embeds no graph values for any
field, and metadata has been durable purely through its operations since M2d.
The payload carries epiphany_core::TuningContextSettings, a five-field subset
of ScoreTuningContext, not the full graph type. ScoreTuningContext's codec
deliberately drops accidental_extensions, so a full-value payload would have
diverged between a live session, where accept stores the envelope as a value,
and the same document reloaded, where the field decodes empty. canonical_value!
could not have caught that: it compares bytes and never the originating value,
so a field that never reached the bytes is structurally invisible to it. The
subset makes the divergence unrepresentable instead of relying on a
normalization step nothing can enforce, and it costs no wire design - the
encoding is byte-identical to the existing five-field walk, which
tuning_context_settings_canonical_bytes_match_score_tuning_context asserts
directly. Reduction leaves accidental_extensions untouched.
SetTuningContext is the sole genesis payload born at major 3, because minimal
stamping is a function of each payload's value, so the accept-set raise is
charged to this one surface: OperationEnvelopeBlock 2 to 3. The doc comment
above it did not merely record the cap, it asserted that no operation payload
embeds the tuning context - a sentence this rung falsifies - so it is rewritten
rather than left beside a corrected constant.
Undo restores the seeded base settings, default or not, and the
never-authored versus authored-to-default distinction stays unobservable. An
earlier draft of the contract had that backwards; PLAN_GENESIS_OPS section 5
trap 5 withdrew it, and SetMetadata is the disproof.
Fixes two undefined references the interrupted run had not yet reached:
operation_catalog.tex referenced sec:evolution:major3, a label defined in
binary_format.tex, which LaTeX cannot resolve across documents. Replaced with
the sectionsc convention already used for every other cross-companion citation
in that file.
Gate: 1409 tests, clippy 0, fmt clean, conformance 8/8 including [7f], both
vector corpora regenerated, all four PDFs at 0 undefined references. The t5 and
t7 mutations were re-run independently and observed to fail as specified; the
remaining eight are not signed off, because the implementing run was stopped
before it reported them.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
Documentation only. No Rust, no .tex, no vectors, no implementation.
Records the ratified schema-minor epochs (minors 2-9, one per additive event:
M2c, Push 3, Phase-3 tranche 1, Pass-12 G-pass, schema-major-2 repeat revision,
Push 4a, G1, G2a). These are schema-minor epochs, not companion semver.
The ladder is complete against spec/AUDIT_GMINOR_VOCABULARIES.md - every
post-baseline variant appears exactly once - and monotonic in the topological
order of the commits that introduced each variant, which is what makes a
declared minor prefix-closed. Verified against git rather than assumed,
including the two events sharing 2026-07-07.
Major baselines unchanged: V0 minor 1, V1-V3 minor 0. Baseline variants impose
no additive override; M2c's operation kinds stay baseline while its
PreconditionFailureReason append requires epoch 2.
Manifest::SCHEMA is narrowly superseded. Changed child ChunkRefs still never
raise the manifest minor, but emitted barrier tags do: a manifest naming a tag
in 24-33 takes that tag's epoch. Major stays 0. The derivation seam is left to
the implementation contract, with the case that must not be discovered late
written down - epiphany-bundle depends on neither ops nor layout-ir and
preserves barrier bytes verbatim, so a repack can carry a blob it cannot
decode, and "decode and inspect" does not cover it.
PLAN_GENESIS_OPS.md:257 no longer says "per-kind minor". That policy was
rejected; the paragraph now carries the ratified rule and records why.
Every gate in PLAN_GMINOR_SCHEMA_MINOR.md section 5 is discharged. The
implementation contract may now be drafted.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
TransposeInterval is missing from both Core normative listings, which carry the
older Transpose and never gained its successor at kind 30. So the vocabulary
has drifted from its normative listings for two tranches, not one, and both
listings need four additions rather than two. The contract's grep list gains
TransposeInterval, and names the signature worth hunting: a spelled-out count
that disagrees with the enumeration beside it.
for_major does not return {major, 0} unconditionally -- V0 is {0, 1}, and only
V1 through V3 carry minor 0. Corrected in the contract, the plan, and P13-S14.
The finding is unchanged: the function accepts only a major, so no per-kind
additive minor can reach it.
Ladder order is now explicit as G2a -> G-minor -> G2b, with the reason. The
sweep is scoped to kinds 24-33, which is what exists once G2a lands; running
G2b first appends kind 34 and would either grow the sweep mid-flight or ship 34
carrying the defect the rung exists to retire.
Core is five live-text edits plus one historical annotation, not five edits.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
All four findings verified against the tree before fixing; all four hold.
The schema-minor MUST (binary_format.tex:2330) has never been implemented.
SchemaVersion::for_major accepts no minor and returns {major, 0}, and both
staging paths derive only the major, so kinds 24-27, 28-29, 30, and 31 already
carry no additive-version record -- and the requirement's own rationale is
exactly what the gap defeats: a reader meeting an appended discriminant cannot
tell a stale vocabulary from damaged bytes. Filed as P13-S14 and ruled a
separate rung after G2a, sweeping 24-33 in one retroactive pass rather than
blocking G2a on a debt eight kinds deep or paying for two partial sweeps. G2a
now says explicitly that it extends the violation by two, knowingly, and
forbids working around the absence.
s7 could not fail. WorkingSnapshot::restore reassigns the whole graph
independently of every write chain, so omitting a chain leaves stale history
while the field still rolls back -- the prescribed assertion passed under its
own mutation. Two framings of this test were wrong; the third asserts against
a later undo's predecessor, and the contract now requires the mutation be run
rather than reasoned about. s8's mutation was impossible as written: each
payload has one field, so there are no adjacent fields to swap. Swapping
discriminants 32/33 in both halves is the self-consistent mutation that leaves
round-trips green and kills correctly-named literal vectors.
The normative repair surface doubles: eleven sites across four documents, five
of them G1 debt. Core's normative OperationKind and OperationKindTag listings
are missing CreateInstrument as well as both new kinds; the catalog's
value-restoration family list is normative for undo and omitting a family is a
silent semantic gap; two spelled-out payload counts move. Since two independent
reviews each found sites the other missed, the list is a floor and the contract
now prescribes grepping the load-bearing phrases.
Also: core_spec said "two edits" and prescribed more, and the split-cost
accounting counted only Text Projection when G2b repeats the Binary Format and
Operation Catalog work too.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
All four findings verified independently against the tree before fixing; all
four hold, and the first is worse than filed.
P1 (normative wire docs) is not a G2a omission but a G1 regression. 3b09595
touched operation_catalog.tex and text_projection.tex and no other .tex, so it
shipped four falsehoods: binary_format's payload-layout and tag tables stop at
kind 30 while 31 is assigned in code, and req:binfmt:kind-discriminants says
each row pins the payload's byte layout; binary_format:2432 still asserts there
is no CreateInstrument; core_spec:12186 still says Canvas.layout_defaults and
Instrument.range reach only the non-canonical snapshot; and the catalog gained
a CreateInstrument section with no version bump against its own convention.
G2a now repairs all four and adds its own two surfaces, with explicit version
and changelog dispositions for binary_format (0.11.0 -> 0.12.0), the catalog
(0.9.0 -> 0.10.0, covering G1 retroactively), and two narrow core_spec edits.
The core_spec:5114 amendment is pinned rather than left to a subagent. The
K8 paragraph has a load-bearing half the ruling does not touch -- root and
canvas remain structural givens no operation mints -- and only the
outside-the-operation-set clause is superseded.
P1 (source) adds ops/src/lib.rs re-exports and the textproj parse.rs literal
HEADER fixture, whose tracking test is a tripwire that fires by design.
P2: s8 and s9 gain the mutations they lacked, and s2's was fabricated --
set_metadata contains no comparison to reverse, it records and overwrites
unconditionally, so the mutation is now setter-local first-write-wins. s7's
framing was backwards: WorkingSnapshot is transaction rollback, so omitting a
chain retains a failed transaction's write rather than losing history, and the
wrong framing would have sent the test hunting the wrong symptom.
Records the G2b holdout: ScoreTuningContext's Codec deliberately drops
accidental_extensions while OperationSet::accept stores envelopes as objects,
so a naive full-value SetTuningContext diverges between a live session and the
same document reloaded -- and canonical_value! cannot see it, because its
check compares bytes and never the originating value.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
G2 was scoped as one packet of three LWW setters. Reading the frozen codec
walks rather than the type labels shows they do not sit at the same major:
SpellingPrecedence has never been versioned, CanvasLayoutDefaults is versioned
in the containing Canvas walk and not the leaf, and only ScoreTuningContext is
born at v3. So the accept-set raise — a one-way door — is charged to one
surface, not amortised across nine as the ruling's framing implied. G2 splits:
G2a is the two major-0 setters and touches epiphany-bundle not at all; G2b is
SetTuningContext alone, carrying the raise and the S13 close.
Withdraws plan trap 5. SetMetadata already answers it: Score::empty seeds
metadata exactly as it seeds tuning_context, the base ingest seeds the LWW
chain from it, and restoring that seed is correct for both never-authored and
authored-to-default. These are always-valued fields, not map keys, so the
Predecessor::Base/::Write distinction that matters for spellings and breaks
does not apply here.
Records the G1 lesson as a trap in its own right: an OperationKind variant is
not containable to core+ops, and the G2a contract budgets all three downstream
literal sites up front instead of discovering them mid-dispatch.
Corrects S13's amortisation claim, and states the closure argument properly —
the canonical base is a MaterializedState that embeds no graph values for any
field, so S13 closes on the metadata precedent, not on the base. Notes the
consequence: after G2b, pruning would discard authored state.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
The ruling names nine surfaces. Each op touches roughly thirteen places -- the
kind variant, four hand-written matches, the decode arm and its validation, the
reduction arm, both text-projection arms, validate, vectors, the fuzz
generators, and the catalog. Nine at thirteen is not one dispatch, so this plans
a ladder rather than a contract.
The load-bearing finding is that G1 is one operation. Score::empty gives
Canvas::default() and empty vectors, and the chain to a note is
CreateInstrument -> CreateStaff -> CreateRegion -> CreateStaffInstance ->
CreateVoice -> InsertEvent, of which only the first is missing. Every later
arrow already exists with graph-aware preconditions. So a single new kind
satisfies the ruling's acceptance criteria 1 and 3 and unblocks T1b.
It is also cheap. Instrument's major-2 appends are mandatory rather than
Option-hidden, so CreateInstrument is unconditionally born at major 2 -- exactly
where CreateStaff already sits, and the op-block accept-set is already 2. No
raise, no wire change. Checked every carried type's fields for the same
property: eight of the nine are major 0 or 2, and SetTuningContext alone drags
OperationEnvelopeBlock to 3, so the raise is spent once in G2, where S13 closes.
The tranche also designs no wire layouts. All nine carried types already have
Codec impls and already ship inside Score; CanonicalValue delegates to them
without introducing a layout, and its generated decode_canonical already
rejects non-canonical encodings, so each payload inherits strict-form
enforcement on the same seam the decode-vector corpus uses.
Traps recorded, including one that would bite quietly: OperationKind's
discriminant match is hand-written and is a DIFFERENT space from the
macro-guarded tag space -- they are not aligned, and Push 4a's four-green-lists
failure is why the tag half is a macro now. Also that bundle.rs documents the
accept-set cap with the tuning-context rationale in prose, so the comment must
move with the number.
Four questions need ratification before a G1 contract: delete/modify coverage
per family, the decomposition_attachments derived-not-authored call, the
measure/meter invariant, and the ladder shape itself.
All fifteen line citations verified against the working tree.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV