Fourth broad-K0 subsystem group — three value-typed LWW field-overwrite ops, one
per settings cluster (additive: OperationKind variants 21-23; framework frozen):
- SetMetadata { metadata: ScoreMetadata } — overwrite the score-singleton
metadata (title/composer/copyright); concurrent differing ⇒
StructuralFieldCollision.
- SetMetricGrid { region, grid: Option<MetricGrid> } — overwrite a region's
default metric grid (LWW keyed by region; concurrent differing ⇒ collision).
- SetUserPageBreak { region, anchor, present } — the page-break sibling of
SetUserSystemBreak: a canonical LWW advisory.
- core: expose ScoreMetadata + MetricGrid via CanonicalValue (no new byte layout
— they already have whole-score Codec impls).
- SetMetadata / SetMetricGrid mirror the modify ops: the resolved value lives in
the graph (reduce_onto), with new last_metadata / last_metric_grid LWW working
state for concurrent-differing detection; MaterializedState records only the
effect and conflict.
- SetUserPageBreak mirrors SetUserSystemBreak's canonical advisory: a new
MaterializedState.page_breaks map (encode + decode added, parallel to breaks),
plus the graph's region user_page_breaks.
Migration: v1-native (no lossy v0 predecessor) -> project/migrate by identity;
the round-trip identity test now covers all four M2 groups.
Coverage:
- testkit operation_payload + ops fuzz gen_payload emit the three kinds, so the
convergence / determinism / migration-equivalence and MaterializedState
decode-roundtrip gates exercise them (incl. page_breaks) at scale.
- reduce_onto graph tests: the three settings materialize in graph and ledger
(metadata title, region default metric grid, region user page break +
MaterializedState.page_breaks), invariant-clean; plus a concurrent-differing
SetMetadata conflict test.
Gates: build/fmt/clippy -D warnings clean; cargo test --workspace green (519);
conformance_suite scale 1 passes. Catalog sections + DECISIONS for the M2 groups
land in M2e per the staged plan. The unrelated Agent-I working tree is left
uncommitted; this commit stages only core/ops/testkit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Third broad-K0 subsystem group — six new value-typed ops for the score-graph
containers, reusing M1's disciplines (additive: OperationKind variants 15-20,
new apply arms + reduction methods; framework frozen). Per the project lead's
call, container deletes are EMPTY-ONLY (no cascade): a precondition NoOp unless
the container has no live children, so the caller deletes contents first.
- CreateRegion / DeleteRegion, CreateStaffInstance / DeleteStaffInstance,
CreateVoice / DeleteVoice. Creates are value-typed mints of an empty container
(set-union creation); deletes are delete-wins tombstones gated on emptiness.
- core: expose Region / StaffInstance / Voice via CanonicalValue (no new byte
layout — they already have whole-score Codec impls), with round-trip coverage.
- New PreconditionFailureReason::ContainerNotEmpty (additive discriminant 10;
encode + decode), reported when an empty-only delete hits a non-empty container.
Reduction (reduce.rs):
- Two child-existence indices, region_instances and instance_voices, drive the
emptiness checks (a voice's events are read from voice_occupancy), so the
ledger projection and the graph agree on every delete result. Populated by
seed_from_graph, the create ops, and implicit voice creation in insert_event.
- CreateStaffInstance / DeleteStaffInstance maintain the region's staff_extent so
it lists exactly the manifested staves (Chapter 5 RegionExtents); valuegen's
fresh region uses a far-future wall-clock extent so it never overlaps an
existing region in both time and staff.
Migration: v1-native (no lossy v0 predecessor) -> project/migrate by identity;
group1_and_group2_kinds_round_trip_by_identity extended to cover Group 3.
Coverage:
- testkit operation_payload + ops fuzz gen_payload emit the six kinds, so the
convergence / determinism / migration-equivalence gates exercise the
bookkeeping projection at scale.
- A reduce_onto graph test materializes a region -> staff instance -> voice
subtree (invariant-clean), asserts the empty-only delete refuses a non-empty
container with ContainerNotEmpty, and verifies an ordered teardown clears the
subtree from both graph and ledger.
Gates: build/fmt/clippy -D warnings clean; cargo test --workspace green (criterion
1 green with the new container objects in the corpus); conformance_suite scale 1
passes. Catalog sections + DECISIONS for these ops land in M2e per the staged
plan. The unrelated Agent-I working tree is left uncommitted; this commit stages
only core/ops/testkit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Second broad-K0 subsystem group — two new value-typed ops reusing M1's proven
disciplines (additive: OperationKind variants 13-14, new apply arms + reduction
methods; framework frozen):
- DeleteCrossCutting { structure: TypedObjectId } — delete-wins tombstone of a
cross-cutting structure (idempotent concurrent deletes; guarded to the
Tie/Slur/Beam/Spanner kinds). Drops the transient endpoint/LWW indices so a
later event-tombstone re-anchoring pass never re-processes the deleted
structure.
- ModifyCrossCutting { structure: CrossCuttingValue } — LWW field-overwrite by
the structure's id; concurrent differing => StructuralFieldCollision. Mirrors
modify_event (resolved value lives in the graph, not MaterializedState);
re-derives endpoints from the new value, and mirrors CreateCrossCutting's
beam->=2 / endpoints-live preconditions.
Graph materialization (reduce_onto): graph_delete_cross_cutting removes the
structure by id; graph_modify_cross_cutting replaces it in place by id, across
all four kinds (Slur/Tie/Beam/Spanner). New last_cross_cutting_modify LWW map,
synced through WorkingSnapshot/snapshot/restore.
Migration: v1-native (no lossy v0 predecessor) -> project/migrate by identity;
group1_and_group2_kinds_round_trip_by_identity extended to cover them.
Coverage:
- testkit operation_payload + ops fuzz gen_payload now emit both kinds, so the
convergence / determinism / migration-equivalence gates exercise the
bookkeeping projection at scale.
- Targeted reduce_onto graph tests (tests/graph_reduction.rs) cover every kind
arm of graph_delete/graph_modify_cross_cutting (Slur/Tie/Beam/Spanner) plus
the beam->=2 reject branch of modify, with check_invariants; plus two
bookkeeping unit tests (delete tombstones; concurrent differing modify
conflicts).
Not wired into graph_edit_session (criterion 1): doing so requires creating
structures in the session, which exposes a pre-existing M1 reanchor/graph-delete
divergence (a slur whose endpoint event is deleted is re-anchored in bookkeeping
but removed from the graph). That is a separate DeleteEvent fix; the targeted
reduce_onto tests above give the M2b graph paths guaranteed coverage meanwhile.
Gates: build/fmt/clippy -D warnings clean; cargo test --workspace green (ops lib
53, ops graph_reduction 18); conformance_suite scale 1 passes. Catalog sections +
DECISIONS for these ops land in M2e per the staged plan. The unrelated Agent-I
working tree is left uncommitted; this commit stages only ops/testkit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
First broad-K0 subsystem group — five new value-typed ops reusing M1's proven
disciplines (additive: new OperationKind variants 8–12, new apply arms +
reduction methods; framework frozen):
- ModifyEvent { event: Event } — field-overwrite LWW by EventId; concurrent
differing ⇒ StructuralFieldCollision.
- Transpose { targets, chromatic_steps } — order-dependent; pitch ids preserved;
canonical footprint = effect-log entry; reduce_onto applies a minimal CMN
alteration shift (rich interval algebra deferred — P12-K2).
- InsertIdentifiedPitch / DeleteIdentifiedPitch — pitch-within-event mint /
delete-wins tombstone.
- ModifyIdentifiedPitch { pitch, value: Pitch } — field-overwrite LWW (the pitch
VALUE, distinct from RespellPitch's spelling-only overwrite).
Design (honesty rule): the modify/transpose ops record effect + conflict
canonically — the resolved values live in the graph (reduce_onto), since
MaterializedState is bookkeeping, not a second graph; respell stays special
because spelling is a bookkeeping-owned annotation. LWW diff uses new
`last_event_modify`/`last_pitch_modify` working maps (synced through
WorkingSnapshot/snapshot/restore).
- core: expose Pitch + IdentifiedPitch via CanonicalValue (no new layout).
- The five kinds are v1-native (no lossy v0 predecessor): project/migrate them by
identity; only the original kinds reconstruct from a lossy v0 form.
- Generators (testkit operation_payload, ops fuzz gen_payload) now emit the new
kinds, so the convergence / determinism / migration-equivalence gates exercise
them at scale; plus targeted migrate identity + reduce LWW/mint/delete tests.
Gates: build/fmt/clippy -D warnings clean; cargo test --workspace green (ops lib
51 tests); conformance_suite scale 1 passes. Catalog sections + DECISIONS for
these ops land in M2e per the staged plan.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Foundation milestone for Track B's Operation Catalog: shift epiphany-ops from
the v0 identifier-only payload projections to durable value-typed payloads, and
scaffold the companion spec. Scope: the representative §6.10 set (7 primitives +
2 meta-ops); the slice-driven K0 expansion follows.
Core (the K↔J seam):
- epiphany-core exposes a public `CanonicalValue` trait (canonical_bytes /
decode_canonical) delegating to the existing private `Codec` machinery, for
Event/Rest/PitchSpelling/Tie/Slur/Beam/Spanner/RegionTimeModel/TimeAnchor.
No new byte layout — a value's bytes equal what the whole-score codec emits,
so all goldens / criterion 4 stay byte-identical.
Ops (value-typed payloads, frozen reduction rules):
- InsertEventOp{staff_instance,event:Event}, RespellPitchOp{pitch,spelling:
PitchSpelling}, CreateCrossCuttingOp{structure:CrossCuttingValue},
ChangeRegionTimeModelOp{...,new_time_model:RegionTimeModel},
SetUserSystemBreakOp{...,anchor:TimeAnchor}, ReplaceWithRest{rest:Rest}.
Payloads frame each value's CanonicalValue bytes behind a u32 length prefix.
- reduce.rs: read-sites only moved onto the value (rules, conflicts, ordering,
promotion, re-anchoring, undo, transactions unchanged); reduce_onto now
materializes the real event/structure instead of the C4 placeholder.
MaterializedState.spellings now stores PitchSpelling (encode + decode updated).
- v0.rs: frozen identifier-only shapes (migration regression guard).
- migrate.rs: migrate_v0_envelope(v0, &Score) + project_v1_to_v0 + MigrationError;
deterministic and equivalence-preserving. Respell spelling recovered from the
score context; irreversible case is P12-K1.
- valuegen.rs: shared value-type builders (reused by fuzz, migration, tests,
testkit). Resolves P11-C1; P11-C10 Dismiss recorded.
Testkit (Agent F merge gate):
- migration.rs: reduce(v1)==reduce(migrate(project(v1))) byte-identical, plus
migration determinism and a non-vacuity guard; wired into acceptance.rs as
agent_k_migration_equivalence_gate. Generators/harnesses build v1 payloads.
Spec:
- spec/operation_catalog.{tex,pdf}: new companion (independent semver) — framework
+ per-primitive template, the 7+2 representative primitives, the v0→v1 migration
contract, and K1 framework slots for the remaining K0 primitives. Builds clean.
- PASS12_BATCH.md: P12-K1 (respell fingerprint irreversibility).
Gates: cargo build/fmt/clippy -D warnings clean; cargo test --workspace green
(incl. criteria 1/4/5/6 and the new K gate); conformance_suite scale 1 passes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>