//! The canonical reduction (Chapter 6 §"The Canonical Reduction").
//!
//! The materialized score state is the deterministic reduction of the operation
//! set. This module is the determinism heart of the architecture:
//!
//! * [`canonical_reduction_order`] is the **single function** that orders
//!   operations (Chapter 6 §6.3.3). The order is causal-first, then by the HLC
//!   tuple `(physical, logical, replica, counter)`. A deterministic topological
//!   pass enforces causal precedence even for an accepted remote envelope whose
//!   HLC contradicts its causal context; HLC orders only ready operations.
//! * [`reduce_operation_set`] walks that order and produces a
//!   [`MaterializedState`] whose [`canonical_bytes`](MaterializedState::canonical_bytes)
//!   are **byte-identical across any permutation of the input** (Appendix D
//!   §"Canonical score determinism"; v0 acceptance criteria 1 and 5).
//!
//! The reduction handles, deterministically: equivocated-slot and
//! anomalous-segment exclusion, the missing-causal-predecessor rule (dependents
//! held pending), atomic transactions with the descriptor-precedence rule,
//! tombstones with re-anchoring, conflict generation with content-derived ids,
//! LWW-advisory fields, and forward (compensating) undo.
//!
//! ## Prototype scope
//!
//! The per-kind reduction implements the representative operations of §6.10
//! against the canonical bookkeeping Chapter 6 owns. [`OperationSet::reduce_onto`]
//! additionally seeds that state from and materializes it into Agent B's
//! [`Score`]. Rich values absent from the provisional operation payloads remain
//! deferred to the Operation Catalog (§6.11); see `DECISIONS.md` for the exact
//! boundary.

use std::cmp::{Ordering, Reverse};
use std::collections::{BTreeMap, BTreeSet, BinaryHeap};

use epiphany_core::{
    canonical_pitch_bytes, derive_promoted_voice_id, simplest_spelling, AnalysisLayer,
    AnalysisLayerId, AnchorOffset, AnnotationAnchor, CanonicalValue, CanvasLayoutDefaults, Event,
    EventDuration, EventId, EventPosition, GestureAnchoring, Instrument, InstrumentId, Measure,
    MeasureId, MeasurePosition, MeterChange, MetricGrid, MusicalDuration, MusicalPosition,
    OperationId, PartDefinition, PartDefinitionId, Pitch, PitchId, PitchSpelling, RationalTime,
    RegionEdge, RegionId, RegionTimeModel, RepeatStructure, RepeatStructureId, ReplicaId, Score,
    ScoreMetadata, SpellingAttachment, SpellingDirective, SpellingPrecedence, SpellingScope,
    SpellingSource, Staff, StaffGroup, StaffGroupId, StaffId, StaffInstance, StaffInstanceId,
    StaffLineConfiguration, TempoMap, TempoSegment, TempoShape, TimeAnchor, TimeSignature,
    TimeSignatureId, TransactionId, TransposeRefusal, TranspositionInterval, TuningContextSettings,
    TypedObjectId, ViewDefinition, ViewId, Voice, VoiceId, VoiceOrigin, WallClockDuration,
};
use epiphany_determinism::CanonicalEncode;

use crate::anomaly::{detect_replica_anomalies, IntegrityAnomaly, IntegrityAnomalyKind};
use crate::conflict::{
    ConflictKind, ConflictRecord, ConflictRegistry, FieldPath, ResolutionAction,
};
use crate::effect::{
    NoOpReason, OperationEffect, PreconditionFailureReason, ReanchorReason, RepairKind,
    RepairRecord, TupletCompensationKind,
};
use crate::encode::{push_canon, push_len, push_lp_bytes, push_u8_bool};
use crate::envelope::OperationEnvelope;
use crate::opset::OperationSet;
use crate::payload::{
    resolved_anchor_position, CreateAnalysisLayerOp, CreateCrossCuttingOp, CreateInstrumentOp,
    CreateMeasureOp, CreatePartDefinitionOp, CreateRegionOp, CreateRepeatStructureOp,
    CreateStaffGroupOp, CreateStaffInstanceOp, CreateStaffOp, CreateViewOp, CreateVoiceOp,
    CrossCuttingValue, DeleteCrossCuttingOp, DeleteEventOp, DeleteIdentifiedPitchOp,
    DeleteRegionOp, DeleteRepeatStructureOp, DeleteStaffInstanceOp, DeleteVoiceOp, InsertEventOp,
    InsertIdentifiedPitchOp, ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp,
    OperationKind, OperationPayload, RespellPitchOp, SetCanvasLayoutDefaultsOp, SetMetadataOp,
    SetMetricGridOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp,
    SetTimeSignatureOp, SetTuningContextOp, SetUserPageBreakOp, TransposeIntervalOp, TransposeOp,
    TupletCompensation,
};
use crate::stamp::StampTuple;
use crate::support::{ObjectKind, SerializedCanonicalInputs};
use crate::undo::{UndoPolicy, UndoTransactionPayload};

/// Orders operation envelopes into the canonical reduction order (Chapter 6
/// §6.3.3): causal-first, then by the HLC tuple `(physical, logical, replica,
/// counter)`. Returns the envelopes in that order.
///
/// This is the single ordering function the determinism property tests against.
/// It performs deterministic Kahn topological ordering over causal-context
/// coverage, choosing the smallest HLC reduction tuple among ready operations.
/// A malformed causal cycle has no valid topological order; the smallest HLC
/// tuple deterministically breaks the cycle so every replica still converges.
///
/// ## Subquadratic construction (worklist F1 → K fix)
///
/// The order is *defined* pairwise: an edge `p → s` exists iff `p != s` and
/// `s.causal_context.covers(p.id)`; an envelope is *ready* when every present
/// covered predecessor has been emitted; the smallest reduction tuple among
/// ready envelopes emits next (slice position breaks the — duplicate-id-only —
/// tuple ties, matching `min_by_key`'s first-minimum rule, which the retained
/// test-only `canonical_reduction_order_reference` oracle implements literally
/// in O(n²)). Materializing the edges is inherently quadratic for the common
/// chain-context shape (every DVV floor covers the full replica prefix), so
/// this implementation never enumerates pairs. It decomposes each context into
/// *requirement terms* whose conjunction is exactly pairwise readiness:
///
/// * A **vector floor** `(r, n)` covers precisely the present envelopes of
///   replica `r` with counter `<= n` (the zero-based DVV floor, P11-C7) —
///   a *prefix* of the replica's lane sorted by `(counter, slice index)`.
///   The term is satisfied when the lane's emission frontier (the first
///   unemitted lane slot) passes the prefix; a floor that covers the
///   envelope's *own* id exempts only the self-pair, so that term is instead
///   "frontier at own slot and *second* frontier past the prefix". Both
///   frontiers are monotone, so each term is woken exactly once from a
///   `BTreeMap` keyed by the threshold slot.
/// * An **explicit dot** covers precisely the present envelopes bearing that
///   id; the term is satisfied when the id's unemitted multiplicity reaches
///   zero (or one, for a dot naming the envelope's own id). A dot also lying
///   under one of the context's own floors yields a (redundant) second term —
///   harmless, because readiness is the conjunction of terms, not a
///   predecessor count, so no per-pair dedup is needed.
///
/// Context entries covering no present envelope (absent replicas, floors below
/// every present counter, absent dots) yield no term, exactly as they yield no
/// edge pairwise. Total work is `O((n + Σ context entries) · log n)`.
pub fn canonical_reduction_order<'a>(
    envelopes: &[&'a OperationEnvelope],
) -> Vec<&'a OperationEnvelope> {
    let len = envelopes.len();
    let keys: Vec<StampTuple> = envelopes
        .iter()
        .map(|env| env.stamp.reduction_tuple())
        .collect();

    // Static indexes over the present set: per-replica lanes sorted by
    // (counter, slice index), each envelope's (lane, slot) position, and the
    // per-id unemitted multiplicity (> 1 only for duplicate ids, e.g.
    // equivocation twins fed to this function directly).
    let mut lane_of: BTreeMap<ReplicaId, usize> = BTreeMap::new();
    let mut lanes: Vec<OrderLane> = Vec::new();
    let mut position = vec![(0usize, 0usize); len];
    {
        let mut sorted: Vec<(ReplicaId, u64, usize)> = envelopes
            .iter()
            .enumerate()
            .map(|(index, env)| (env.id.replica, env.id.counter, index))
            .collect();
        sorted.sort_unstable();
        for (replica, counter, index) in sorted {
            let lane_index = *lane_of.entry(replica).or_insert_with(|| {
                lanes.push(OrderLane::default());
                lanes.len() - 1
            });
            let lane = &mut lanes[lane_index];
            position[index] = (lane_index, lane.slots.len());
            lane.slots.push(index);
            lane.counters.push(counter);
        }
        for lane in &mut lanes {
            // All slots start unemitted: frontier 0, second frontier 1
            // (clamped to the lane length, the "exhausted" sentinel).
            lane.second = 1.min(lane.slots.len());
        }
    }
    let mut id_slots: BTreeMap<OperationId, IdSlot> = BTreeMap::new();
    for env in envelopes {
        id_slots.entry(env.id).or_default().unemitted += 1;
    }

    // One requirement term per covering context entry; `remaining` counts the
    // currently-unsatisfied terms. Terms already satisfied here (they cover
    // nothing, or nothing beyond the envelope itself) register no watcher.
    let mut remaining = vec![0usize; len];
    for (index, env) in envelopes.iter().enumerate() {
        for (&replica, &floor) in &env.causal_context.vector {
            let Some(&lane_index) = lane_of.get(&replica) else {
                continue;
            };
            let lane = &mut lanes[lane_index];
            let prefix = lane.counters.partition_point(|&counter| counter <= floor);
            if prefix == 0 {
                continue;
            }
            if env.id.replica == replica && env.id.counter <= floor {
                // The floor covers this envelope's own id; only the self-pair
                // is exempt. Required: every other prefix slot emitted, i.e.
                // frontier at the own slot *and* second frontier past the
                // prefix (the own slot stays unemitted until emission).
                let own_slot = position[index].1;
                if lane.frontier < own_slot {
                    remaining[index] += 1;
                    lane.frontier_watchers.entry(own_slot).or_default().push(
                        FloorWatcher::ExceptSelf {
                            node: index,
                            prefix,
                        },
                    );
                } else if lane.second < prefix {
                    remaining[index] += 1;
                    lane.second_watchers.entry(prefix).or_default().push(index);
                }
            } else if lane.frontier < prefix {
                remaining[index] += 1;
                lane.frontier_watchers
                    .entry(prefix)
                    .or_default()
                    .push(FloorWatcher::Whole { node: index });
            }
        }
        for dot in env.causal_context.dots() {
            let Some(id_slot) = id_slots.get_mut(&dot) else {
                continue; // absent id: covers nothing present, no edge
            };
            if dot == env.id {
                // A dot naming the envelope's own id covers only duplicates.
                if id_slot.unemitted > 1 {
                    remaining[index] += 1;
                    id_slot.watch_one.push(index);
                }
            } else {
                remaining[index] += 1;
                id_slot.watch_zero.push(index);
            }
        }
    }

    // Deterministic Kahn walk. The heap holds every envelope whose terms are
    // all satisfied (pushed exactly at the transition; entries for envelopes
    // already emitted through cycle-breaking are skipped lazily), keyed by
    // (reduction tuple, slice index) — the reference's `min_by_key` order.
    let mut heap: BinaryHeap<Reverse<(StampTuple, usize)>> = (0..len)
        .filter(|&index| remaining[index] == 0)
        .map(|index| Reverse((keys[index], index)))
        .collect();
    let mut by_key: Vec<usize> = (0..len).collect();
    by_key.sort_unstable_by_key(|&index| (keys[index], index));
    let mut cycle_cursor = 0usize;

    let mut emitted = vec![false; len];
    let mut ordered = Vec::with_capacity(len);
    let mut woken: Vec<usize> = Vec::new();
    while ordered.len() < len {
        let mut ready = None;
        while let Some(Reverse((_, index))) = heap.pop() {
            if !emitted[index] {
                ready = Some(index);
                break;
            }
        }
        let next = match ready {
            Some(index) => index,
            None => {
                // A cycle is malformed, but selecting by the canonical
                // tie-breaker keeps reduction deterministic and unlocks the
                // forced envelope's dependents.
                while emitted[by_key[cycle_cursor]] {
                    cycle_cursor += 1;
                }
                by_key[cycle_cursor]
            }
        };
        emitted[next] = true;
        ordered.push(envelopes[next]);

        // Dot wake-ups: the id's unemitted multiplicity dropped by one.
        let id_slot = id_slots
            .get_mut(&envelopes[next].id)
            .expect("every present id has a slot");
        id_slot.unemitted -= 1;
        if id_slot.unemitted <= 1 {
            woken.append(&mut id_slot.watch_one);
        }
        if id_slot.unemitted == 0 {
            woken.append(&mut id_slot.watch_zero);
        }

        // Floor wake-ups: advance the lane frontiers (both point at unemitted
        // slots — or the lane length — by invariant, so an emission below the
        // second frontier is at one of them) and drain the passed watchers.
        let (lane_index, slot) = position[next];
        let lane = &mut lanes[lane_index];
        if slot == lane.frontier {
            lane.frontier = lane.second;
            lane.second = next_unemitted(&lane.slots, &emitted, lane.frontier + 1);
        } else if slot == lane.second {
            lane.second = next_unemitted(&lane.slots, &emitted, slot + 1);
        }
        while let Some(entry) = lane.frontier_watchers.first_entry() {
            if *entry.key() > lane.frontier {
                break;
            }
            for watcher in entry.remove() {
                match watcher {
                    FloorWatcher::Whole { node } => woken.push(node),
                    FloorWatcher::ExceptSelf { node, prefix } => {
                        if lane.second >= prefix {
                            woken.push(node);
                        } else {
                            lane.second_watchers.entry(prefix).or_default().push(node);
                        }
                    }
                }
            }
        }
        while let Some(entry) = lane.second_watchers.first_entry() {
            if *entry.key() > lane.second {
                break;
            }
            for node in entry.remove() {
                woken.push(node);
            }
        }

        for node in woken.drain(..) {
            remaining[node] -= 1;
            if remaining[node] == 0 && !emitted[node] {
                heap.push(Reverse((keys[node], node)));
            }
        }
    }
    ordered
}

/// One replica's present envelopes in [`canonical_reduction_order`], sorted by
/// `(counter, slice index)`, with the two monotone emission frontiers and the
/// floor-term watchers keyed by the frontier slot they wait for.
#[derive(Default)]
struct OrderLane {
    /// Envelope slice indexes, sorted by `(counter, slice index)`.
    slots: Vec<usize>,
    /// The slots' counters (parallel to `slots`, ascending).
    counters: Vec<u64>,
    /// First unemitted slot (== `slots.len()` once exhausted).
    frontier: usize,
    /// Second unemitted slot (>= `slots.len()` once fewer than two remain).
    second: usize,
    /// Floor terms waiting for `frontier >= key`.
    frontier_watchers: BTreeMap<usize, Vec<FloorWatcher>>,
    /// Self-exempt floor terms waiting for `second >= key`.
    second_watchers: BTreeMap<usize, Vec<usize>>,
}

/// One present `OperationId`'s bookkeeping in [`canonical_reduction_order`]:
/// its unemitted multiplicity and the dot terms watching it.
#[derive(Default)]
struct IdSlot {
    /// Present envelopes bearing this id that are not yet emitted.
    unemitted: usize,
    /// Dot terms satisfied when `unemitted` reaches zero.
    watch_zero: Vec<usize>,
    /// Self-dot terms (duplicate ids) satisfied when `unemitted` reaches one.
    watch_one: Vec<usize>,
}

/// A floor term parked in [`OrderLane::frontier_watchers`].
enum FloorWatcher {
    /// Satisfied outright when the frontier reaches its key (the prefix end).
    Whole { node: usize },
    /// A floor covering the node's own id: when the frontier reaches the
    /// node's own slot (its key), the term is satisfied if the second
    /// frontier already passed `prefix`, else it re-parks on the second
    /// frontier.
    ExceptSelf { node: usize, prefix: usize },
}

/// The first unemitted slot position at or after `from` (== `slots.len()` when
/// exhausted). Frontier scans only ever move forward, so the total scan work
/// per lane is linear.
fn next_unemitted(slots: &[usize], emitted: &[bool], from: usize) -> usize {
    let mut at = from.min(slots.len());
    while at < slots.len() && emitted[slots[at]] {
        at += 1;
    }
    at
}

/// The pre-F1 O(n²) implementation, retained verbatim as the property-test
/// oracle for [`canonical_reduction_order`]: it materializes every covered
/// `(predecessor, successor)` pair and re-scans the whole set per emission,
/// which *is* the order's pairwise definition, executed literally.
#[cfg(test)]
pub(crate) fn canonical_reduction_order_reference<'a>(
    envelopes: &[&'a OperationEnvelope],
) -> Vec<&'a OperationEnvelope> {
    let len = envelopes.len();
    let mut indegree = vec![0usize; len];
    let mut successors = vec![Vec::<usize>::new(); len];
    for predecessor in 0..len {
        for successor in 0..len {
            if predecessor != successor
                && envelopes[successor]
                    .causal_context
                    .covers(envelopes[predecessor].id)
            {
                successors[predecessor].push(successor);
                indegree[successor] += 1;
            }
        }
    }

    let mut emitted = vec![false; len];
    let mut ordered = Vec::with_capacity(len);
    for _ in 0..len {
        let ready = (0..len)
            .filter(|&index| !emitted[index] && indegree[index] == 0)
            .min_by_key(|&index| envelopes[index].stamp.reduction_tuple());
        let next = ready.unwrap_or_else(|| {
            // A cycle is malformed, but selecting by the canonical tie-breaker
            // keeps reduction deterministic and unlocks its outgoing edges.
            (0..len)
                .filter(|&index| !emitted[index])
                .min_by_key(|&index| envelopes[index].stamp.reduction_tuple())
                .expect("an un-emitted operation remains")
        });
        emitted[next] = true;
        ordered.push(envelopes[next]);
        for &successor in &successors[next] {
            indegree[successor] = indegree[successor].saturating_sub(1);
        }
    }
    ordered
}

/// The state of an object's identifier in the materialized graph (Chapter 6
/// §"Object Existence and Tombstones"). `Unknown` is not represented: an
/// identifier the reduction has never seen simply has no entry.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ObjectState {
    /// Resolves to a current object.
    Live,
    /// Resolves to a deletion record carrying the deleting and minting
    /// operations. Tombstones are never resurrected except by an explicit
    /// inverse-of-delete (Chapter 6 §6.3.4).
    Tombstoned {
        deleted_by: OperationId,
        minted_by: OperationId,
    },
}

impl ObjectState {
    fn discriminant(&self) -> u8 {
        match self {
            ObjectState::Live => 0,
            ObjectState::Tombstoned { .. } => 1,
        }
    }
}

impl CanonicalEncode for ObjectState {
    fn encode_canonical(&self, out: &mut Vec<u8>) {
        out.push(self.discriminant());
        if let ObjectState::Tombstoned {
            deleted_by,
            minted_by,
        } = self
        {
            push_canon(out, deleted_by);
            push_canon(out, minted_by);
        }
    }
}

/// Why an operation is held pending rather than reduced (Chapter 6 §6.5, §6.6).
/// A pending operation is retained in the operation set but produces no
/// canonical effect until its blocking cause is resolved.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum PendingReason {
    /// A causal predecessor is absent from the operation set entirely.
    MissingCausalPredecessor { missing: OperationId },
    /// A causal predecessor's slot is equivocated.
    DependsOnEquivocated { on: OperationId },
    /// A causal predecessor was excluded by an anomalous-replica segment.
    DependsOnExcluded { on: OperationId },
    /// A causal predecessor is itself held pending.
    DependsOnPending { on: OperationId },
    /// Reduction halted at a system-derived identifier collision (Chapter 5
    /// §"System-Derived Counter Collisions"): this operation is at or past the
    /// collision point in canonical order — or is the earlier occupant of the
    /// collided counter — and is held pending external recovery. `at` is the
    /// operation whose mint collided.
    HaltedBySystemCollision { at: OperationId },
}

impl PendingReason {
    fn discriminant(&self) -> u8 {
        match self {
            PendingReason::MissingCausalPredecessor { .. } => 0,
            PendingReason::DependsOnEquivocated { .. } => 1,
            PendingReason::DependsOnExcluded { .. } => 2,
            PendingReason::DependsOnPending { .. } => 3,
            PendingReason::HaltedBySystemCollision { .. } => 4,
        }
    }
    fn blocker(&self) -> OperationId {
        match self {
            PendingReason::MissingCausalPredecessor { missing } => *missing,
            PendingReason::DependsOnEquivocated { on }
            | PendingReason::DependsOnExcluded { on }
            | PendingReason::DependsOnPending { on } => *on,
            PendingReason::HaltedBySystemCollision { at } => *at,
        }
    }
}

impl CanonicalEncode for PendingReason {
    fn encode_canonical(&self, out: &mut Vec<u8>) {
        out.push(self.discriminant());
        push_canon(out, &self.blocker());
    }
}

/// The canonical materialized state produced by the reduction (Chapter 6 §6.3).
/// Every field is in a normative total order, so [`MaterializedState::canonical_bytes`]
/// is byte-identical across any permutation of the input operation set.
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct MaterializedState {
    /// The effect log: one [`OperationEffect`] per reduced operation, in
    /// canonical reduction order (Chapter 6 §6.3.2). Part of canonical state.
    pub effects: Vec<(OperationId, OperationEffect)>,
    /// The conflict registry, ordered by `ConflictId`.
    pub conflicts: ConflictRegistry,
    /// The integrity-anomaly register, ordered by `IntegrityAnomalyId`.
    pub anomalies: Vec<IntegrityAnomaly>,
    /// Object existence (live/tombstoned), keyed by `TypedObjectId`.
    pub objects: BTreeMap<TypedObjectId, ObjectState>,
    /// Current resolved spelling per pitch (the `RespellPitch` field).
    pub spellings: BTreeMap<PitchId, PitchSpelling>,
    /// User system-break preferences (LWW advisory), keyed by region+anchor.
    pub breaks: BTreeMap<(RegionId, MusicalPosition), bool>,
    /// User page-break preferences (LWW advisory), keyed by region+anchor (the
    /// page-break sibling of [`MaterializedState::breaks`], M2d).
    pub page_breaks: BTreeMap<(RegionId, MusicalPosition), bool>,
    /// Operations held pending, ordered by `OperationId`.
    pub pending: Vec<(OperationId, PendingReason)>,
}

/// The result of reducing an operation set onto a canonical base score.
///
/// `state` remains the byte-canonical Chapter 6 reduction product. `score` is
/// the corresponding Agent B graph materialization used by editing, invariant
/// checking, indexing, and layout; it is derived state, never the source of
/// truth.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct GraphMaterialization {
    pub state: MaterializedState,
    pub score: Score,
}

impl MaterializedState {
    /// The canonical byte serialization of the materialized state. Two
    /// reductions of the same operation set — in any order — produce identical
    /// bytes (the determinism property; v0 acceptance criteria 1 and 5).
    pub fn canonical_bytes(&self) -> Vec<u8> {
        let mut out = Vec::new();
        // Effects, in reduction order.
        push_len(&mut out, self.effects.len());
        for (id, eff) in &self.effects {
            push_canon(&mut out, id);
            let mut scratch = Vec::new();
            eff.encode_canonical(&mut scratch);
            crate::encode::push_lp_bytes(&mut out, &scratch);
        }
        // Conflict registry (ConflictId order).
        self.conflicts.encode_canonical(&mut out);
        // Anomaly register (IntegrityAnomalyId order).
        push_len(&mut out, self.anomalies.len());
        for a in &self.anomalies {
            let mut scratch = Vec::new();
            a.encode_canonical(&mut scratch);
            crate::encode::push_lp_bytes(&mut out, &scratch);
        }
        // Objects (TypedObjectId order).
        push_len(&mut out, self.objects.len());
        for (id, state) in &self.objects {
            push_canon(&mut out, id);
            state.encode_canonical(&mut out);
        }
        // Spellings (PitchId order). The value is the full PitchSpelling (v1),
        // encoded behind a u32 length prefix via its canonical value bytes.
        push_len(&mut out, self.spellings.len());
        for (pitch, spelling) in &self.spellings {
            push_canon(&mut out, pitch);
            push_lp_bytes(&mut out, &spelling.canonical_bytes());
        }
        // Breaks (region+anchor order).
        push_len(&mut out, self.breaks.len());
        for ((region, anchor), present) in &self.breaks {
            push_canon(&mut out, region);
            push_canon(&mut out, anchor);
            push_u8_bool(&mut out, *present);
        }
        // Page breaks (region+anchor order) — sibling of breaks (M2d).
        push_len(&mut out, self.page_breaks.len());
        for ((region, anchor), present) in &self.page_breaks {
            push_canon(&mut out, region);
            push_canon(&mut out, anchor);
            push_u8_bool(&mut out, *present);
        }
        // Pending (OperationId order).
        push_len(&mut out, self.pending.len());
        for (id, reason) in &self.pending {
            push_canon(&mut out, id);
            reason.encode_canonical(&mut out);
        }
        out
    }

    /// Decodes the exact inverse of [`MaterializedState::canonical_bytes`].
    ///
    /// The decoder validates all nested tags, lengths, primitive values,
    /// canonical ordering, and trailing-byte discipline. Structurally valid but
    /// non-canonical bytes are rejected rather than silently normalized.
    pub fn decode_canonical(bytes: &[u8]) -> Result<Self, crate::MaterializedDecodeError> {
        crate::decode::decode_materialized_state(bytes)
    }

    /// Whether the materialized state is free of conflicts and anomalies and
    /// has no pending operations — a clean reduction.
    pub fn is_clean(&self) -> bool {
        self.conflicts.is_empty() && self.anomalies.is_empty() && self.pending.is_empty()
    }

    /// The canonical base's own G-minor schema-minor epoch (pin 5): the
    /// maximum over every later-added discriminant its **own bytes** emit —
    /// today, [`ReanchorReason::SameCanvasNearer`] (nested inside
    /// [`RepairKind::Reanchored`], itself inside
    /// [`OperationEffect::AppliedWithRepair`]) and any post-baseline
    /// [`PreconditionFailureReason`] (nested inside
    /// [`NoOpReason::PreconditionFailedUnderReduction`], itself inside
    /// [`OperationEffect::NoOp`]). `None` if every effect is baseline.
    ///
    /// **Never `OperationKind`, `OperationKindTag`, or `OperationPayload`**
    /// (pin 5): `MaterializedState`'s encoder
    /// (`MaterializedState::canonical_bytes`) never emits any of those three
    /// vocabularies, so a newer *source* operation alone — e.g. one whose
    /// primitive kind is `CreateInstrument` (minor 8) — never moves this
    /// value merely by having been reduced; only the effect it *produces*
    /// can.
    pub fn introduced_minor(&self) -> Option<u16> {
        self.effects
            .iter()
            .filter_map(|(_, effect)| effect_introduced_minor(effect))
            .max()
    }
}

/// The G-minor epoch one [`OperationEffect`] contributes to
/// [`MaterializedState::introduced_minor`] (pin 5): walks the two nested
/// vocabularies the canonical base's encoder actually reaches —
/// `RepairKind::Reanchored`'s [`ReanchorReason`] and
/// `NoOpReason::PreconditionFailedUnderReduction`'s
/// [`PreconditionFailureReason`] — and returns their maximum, or `None` if
/// neither applies or both are baseline.
fn effect_introduced_minor(effect: &OperationEffect) -> Option<u16> {
    match effect {
        OperationEffect::AppliedWithRepair { repairs } => repairs
            .iter()
            .filter_map(|repair| match &repair.kind {
                RepairKind::Reanchored { reason, .. } => reason.introduced_minor(),
                RepairKind::SpannerTruncated { .. }
                | RepairKind::Orphaned
                | RepairKind::CascadeDeleted
                | RepairKind::AttachmentTombstoned
                | RepairKind::VoicePromoted { .. }
                | RepairKind::TupletCompensated { .. }
                | RepairKind::Registered(_) => None,
            })
            .max(),
        OperationEffect::NoOp { reason } => match reason {
            NoOpReason::PreconditionFailedUnderReduction { reason } => reason.introduced_minor(),
            NoOpReason::TargetTombstoned
            | NoOpReason::AlreadyApplied
            | NoOpReason::SupersededByLaterOperation { .. }
            | NoOpReason::TransactionConflict => None,
        },
        OperationEffect::Applied
        | OperationEffect::Conflicted { .. }
        | OperationEffect::TombstonedTarget { .. } => None,
    }
}

/// Reduces an [`OperationSet`] to its canonical [`MaterializedState`].
pub fn reduce_operation_set(op_set: &OperationSet) -> MaterializedState {
    Reducer::new(op_set).run().0
}

/// Reduces an [`OperationSet`] onto a canonical base [`Score`].
pub fn reduce_operation_set_onto(op_set: &OperationSet, base: &Score) -> GraphMaterialization {
    let (state, score) = Reducer::new_onto(op_set, base).run();
    GraphMaterialization {
        state,
        score: score.expect("graph-aware reduction always retains its base score"),
    }
}

/// Genesis tranche G3b packet 2 (`spec/CONTRACT_GENESIS_G3B_MEASURE.md`):
/// exposes this crate's pin 6/6b comparable relation and musical delta —
/// [`Reducer::anchors_comparable_order`] / [`Reducer::anchor_musical_delta`],
/// which stay private to this crate — so `epiphany-testkit`'s cross-crate
/// agreement test can drive the SAME anchor pairs through this
/// implementation and through `epiphany-core`'s independent invariant-20
/// implementation of the same normative relation
/// (`epiphany_core::invariants::measure_anchor_relation`) and assert they
/// agree. This is the guard against maintaining one normative relation in
/// two places without sharing code: `epiphany-core` cannot depend on this
/// crate (the dependency direction is fixed the other way), so invariant 20
/// cannot reuse `Reducer`'s methods, and there is no third crate either
/// could delegate to. `graph` seeds the reducer graph-aware, so c3 (the
/// vector-index shape) resolves exactly as production reduction resolves
/// it.
pub fn measure_anchor_relation_for_agreement_test(
    graph: &Score,
    a: &TimeAnchor,
    b: &TimeAnchor,
) -> (Option<std::cmp::Ordering>, Option<MusicalDuration>) {
    let op_set = OperationSet::new();
    let reducer = Reducer::new_onto(&op_set, graph);
    (
        reducer.anchors_comparable_order(a, b),
        reducer.anchor_musical_delta(a, b),
    )
}

/// One write in a per-key canonical-order write chain (operation_catalog
/// §UndoTransaction, "Value restoration"): the writer, the transaction it was a
/// member of (if any), and the value it wrote.
#[derive(Clone, PartialEq, Eq, Debug)]
struct ChainWrite<V> {
    op: OperationId,
    tx: Option<TransactionId>,
    value: V,
}

/// The canonical-order write chain of one LWW-overwritten key (operation_catalog
/// §UndoTransaction). `base` is the key's pre-operational value — seeded from
/// the base graph (`seed_from_graph`) or from the value a mint carried — so a
/// chain-predecessor is defined for keys that exist before the first overwrite;
/// a key with no base entry restores to *absence*. `writes` append in canonical
/// processing order (the reducer applies operations in canonical order, so
/// appends are inherently canonical and the chain is permutation-invariant).
#[derive(Clone, PartialEq, Eq, Debug)]
struct WriteChain<V> {
    base: Option<V>,
    writes: Vec<ChainWrite<V>>,
}

impl<V: Clone> WriteChain<V> {
    fn new() -> Self {
        WriteChain {
            base: None,
            writes: Vec::new(),
        }
    }

    /// Seeds the base value only if the chain has neither a base nor writes
    /// (idempotent seeding; a mint never clobbers recorded history).
    fn seed(&mut self, base: V) {
        if self.base.is_none() && self.writes.is_empty() {
            self.base = Some(base);
        }
    }

    /// Appends a write in canonical processing order.
    fn record(&mut self, op: OperationId, tx: Option<TransactionId>, value: V) {
        self.writes.push(ChainWrite { op, tx, value });
    }

    /// The most recent write, if any (the LWW concurrency comparison point;
    /// the base entry never participates in conflict detection).
    fn last_write(&self) -> Option<&ChainWrite<V>> {
        self.writes.last()
    }

    /// The key's current resolved value: the last write, falling back to the
    /// base entry.
    fn current(&self) -> Option<&V> {
        self.last_write()
            .map(|write| &write.value)
            .or(self.base.as_ref())
    }

    /// The undo verdict for transaction `tx` on this key (operation_catalog
    /// §UndoTransaction, "Value restoration").
    fn undo_verdict(&self, tx: TransactionId) -> ChainUndoVerdict<V> {
        if !self.writes.iter().any(|w| w.tx == Some(tx)) {
            return ChainUndoVerdict::NotWritten;
        }
        let last = self.writes.last().expect("chain has a write by `tx`");
        if last.tx != Some(tx) {
            return ChainUndoVerdict::Superseded { by: last.op };
        }
        // Chain-predecessor: the latest entry not written by the transaction,
        // falling back to the base value, else absence.
        let predecessor = self
            .writes
            .iter()
            .rev()
            .find(|w| w.tx != Some(tx))
            .map(|w| Predecessor::Write(w.value.clone()))
            .or_else(|| self.base.clone().map(Predecessor::Base));
        ChainUndoVerdict::Restore(predecessor)
    }
}

/// The chain-predecessor an undo restores: a prior operational write, or the
/// key's base (pre-operational) value. The distinction matters for the
/// canonical bookkeeping maps (`spellings`, `breaks`, `page_breaks`), which
/// return to key-*absence* when the predecessor is the base value — the base
/// state lives in the graph, not in the operational ledger.
#[derive(Clone, Debug)]
enum Predecessor<V> {
    Write(V),
    Base(V),
}

impl<V> Predecessor<V> {
    fn into_value(self) -> V {
        match self {
            Predecessor::Write(v) | Predecessor::Base(v) => v,
        }
    }
}

/// Genesis tranche G3b (`spec/CONTRACT_GENESIS_G3B_MEASURE.md` pin 6c): how
/// recently (in canonical order) a chain wrote, for comparing two
/// INDEPENDENT chains' last writes (`metric_grid_chain` vs
/// `meter_change_chain`) — see [`Reducer::chain_recency`]. Declaration order
/// IS the intended `Ord`: a seeded-only base predates every real write, and
/// a prospective (not-yet-applied) write is always the latest.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
enum Recency {
    /// No recorded operational write — only a seeded base, or nothing.
    Base,
    /// A recorded write, keyed by its authoring operation's canonical
    /// position.
    Write(crate::stamp::StampTuple),
    /// An in-flight, not-yet-applied prospective write (pin 6c, M31a) —
    /// always the most recent.
    Prospective,
}

/// Genesis tranche G3b (`spec/CONTRACT_GENESIS_G3B_MEASURE.md` pin 6c): the
/// outcome of finding the governing element of a partially-ordered set under
/// [`Reducer::anchors_comparable_order`] — shared by the effective-grid
/// oracle's governing meter change and by `CreateMeasure`'s "current last
/// measure" lookup.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum GoverningElement<T> {
    /// No candidate exists (an empty, or wholly-filtered-away, set) —
    /// vacuous, not a violation (pin 6c step 1).
    None,
    /// Exactly one candidate is the unique maximum (pin 6c step 2).
    Unique(T),
    /// Either some candidate is incomparable to the reference point (step 0),
    /// or multiple maxima are mutually incomparable to each other (step 3) —
    /// the caller must refuse/abstain, never guess.
    Indeterminate,
}

/// The per-key outcome of undoing a transaction's write chain.
enum ChainUndoVerdict<V> {
    /// The transaction never wrote this key.
    NotWritten,
    /// The transaction wrote the key but a later write superseded it.
    Superseded { by: OperationId },
    /// The transaction's write is still last: restore the chain-predecessor
    /// (`None` = the transaction introduced the first value; restore absence).
    Restore(Option<Predecessor<V>>),
}

/// The staff-instance layout advisories `SetStaffLayout` overwrites as a unit
/// (operation_catalog §SetStaffLayout).
type StaffLayoutValue = (Option<InstrumentId>, Option<StaffLineConfiguration>, bool);

/// One key restoration a value-restoring undo applies (operation_catalog
/// §UndoTransaction "Value restoration"). For the always-valued families
/// (event, pitch, cross-cutting, metadata, staff layout) `None` means the
/// chain knows no predecessor (an object minted before this reduction's
/// horizon, reachable only base-free): the undo verdict stands but there is no
/// value to write back — a bookkeeping-only restoration. For the optional
/// families (grid, meter change, tempo segment) the flattened `None` *is* the
/// restoration: clear/remove at the key. The canonical bookkeeping families
/// (spelling, breaks) keep the [`Predecessor`] distinction: a base predecessor
/// returns the ledger map to key-absence while the graph restores the base
/// value.
/// One target's fully-resolved transposition, computed before anything is
/// written so the operation can refuse atomically.
struct ResolvedTranspose {
    pitch: PitchId,
    value: Pitch,
    /// `(index into score.spelling_attachments, moved spelling)`.
    authored: Vec<(usize, PitchSpelling)>,
}

enum ValueRestoration {
    Event {
        event: EventId,
        value: Option<Event>,
    },
    Pitch {
        pitch: PitchId,
        value: Option<Pitch>,
    },
    Spelling {
        pitch: PitchId,
        predecessor: Option<Predecessor<PitchSpelling>>,
    },
    /// The engraved-layer explicit spelling attachments a `TransposeInterval`
    /// rewrote, restored as a set. `None` predecessor means the pitch carried
    /// none before, so they are removed.
    EngravedSpellings {
        pitch: PitchId,
        predecessor: Option<Predecessor<Vec<SpellingAttachment>>>,
    },
    CrossCutting {
        id: TypedObjectId,
        value: Option<CrossCuttingValue>,
    },
    Metadata {
        value: Option<ScoreMetadata>,
    },
    /// Genesis tranche G2a.
    CanvasLayoutDefaults {
        value: Option<CanvasLayoutDefaults>,
    },
    /// Genesis tranche G2a.
    SpellingPrecedence {
        value: Option<SpellingPrecedence>,
    },
    /// Genesis tranche G2b. The subset type — `accidental_extensions` is not
    /// part of it and is never touched by restoration.
    TuningContext {
        value: Option<TuningContextSettings>,
    },
    MetricGrid {
        region: RegionId,
        value: Option<MetricGrid>,
    },
    MeterChange {
        region: RegionId,
        position: MusicalPosition,
        value: Option<MeterChange>,
    },
    TempoSegment {
        region: Option<RegionId>,
        position: MusicalPosition,
        value: Option<TempoSegment>,
    },
    StaffLayout {
        instance: StaffInstanceId,
        value: Option<StaffLayoutValue>,
    },
    SystemBreak {
        region: RegionId,
        position: MusicalPosition,
        predecessor: Option<Predecessor<(TimeAnchor, bool)>>,
    },
    PageBreak {
        region: RegionId,
        position: MusicalPosition,
        predecessor: Option<Predecessor<(TimeAnchor, bool)>>,
    },
}

/// Whether a tempo segment's shape carries the end data it requires
/// (operation_catalog §"Meter and Tempo Overwrites"): a non-constant shape
/// needs both an explicit `end` and an `end_tempo`; a constant segment's
/// `end_tempo`, when present, must equal its `start_tempo` (the same structural
/// rules the graph-invariant checker applies to tempo maps).
fn tempo_segment_shape_well_formed(segment: &TempoSegment) -> bool {
    match segment.shape {
        TempoShape::Constant => segment
            .end_tempo
            .as_ref()
            .is_none_or(|end| end == &segment.start_tempo),
        TempoShape::Linear | TempoShape::Exponential | TempoShape::Curve => {
            segment.end_tempo.is_some() && segment.end.is_some()
        }
    }
}

/// Replaces (or removes, for `None`) the segment at `position` in `map`,
/// keeping the segment list ordered by resolved start position — the same
/// coarse anchor resolution the LWW key uses, so one resolved position holds
/// exactly one segment.
fn edit_tempo_map_segments(
    map: &mut TempoMap,
    position: &MusicalPosition,
    segment: &Option<TempoSegment>,
) {
    map.segments
        .retain(|existing| resolved_anchor_position(&existing.start) != *position);
    if let Some(segment) = segment {
        let index = map
            .segments
            .iter()
            .position(|existing| resolved_anchor_position(&existing.start) > *position)
            .unwrap_or(map.segments.len());
        map.segments.insert(index, segment.clone());
    }
}

/// The working state of one reduction pass.
struct Reducer<'a> {
    op_set: &'a OperationSet,
    // Canonical results.
    objects: BTreeMap<TypedObjectId, ObjectState>,
    spellings: BTreeMap<PitchId, PitchSpelling>,
    breaks: BTreeMap<(RegionId, MusicalPosition), bool>,
    page_breaks: BTreeMap<(RegionId, MusicalPosition), bool>,
    conflicts: ConflictRegistry,
    effects: Vec<(OperationId, OperationEffect)>,
    anomalies: BTreeMap<epiphany_core::IntegrityAnomalyId, IntegrityAnomaly>,
    // Transient indices.
    minted_by: BTreeMap<TypedObjectId, OperationId>,
    event_pitches: BTreeMap<EventId, Vec<PitchId>>,
    voice_occupancy: BTreeMap<VoiceId, Vec<(MusicalPosition, MusicalDuration, EventId)>>,
    // Per-key canonical-order write chains for every LWW overwrite family
    // (operation_catalog §UndoTransaction "Value restoration"). Each chain's
    // last write doubles as the LWW working state the concurrent-differing
    // conflict detection reads (formerly the `last_*` maps); the full chain is
    // what value-restoring undo walks. Advisory families (metadata, breaks,
    // staff layout) keep chains for undo but record no conflicts.
    respell_chain: BTreeMap<PitchId, WriteChain<PitchSpelling>>,
    /// A pitch's engraved-layer, pitch-scoped, explicit spelling attachment
    /// **set**, as one value. Written by *every* operation that changes it:
    /// `RespellPitch` and `TransposeInterval` alike (P13-S3).
    ///
    /// Both must record here or undo is wrong in both directions. If only the
    /// transpose recorded, a prior respell would not be its chain-predecessor
    /// and undoing the transpose would erase the respell; and a *later* respell
    /// would be invisible, so a strict undo would report `Applied` and wipe it
    /// instead of refusing as superseded.
    ///
    /// This is a *second* physical chain, not a replacement for `respell_chain`:
    /// that one is `RespellPitch`'s LWW working state, read by its
    /// concurrent-differing conflict detection, and folding transposes into it
    /// would make a concurrent respell conflict with a transpose and move the
    /// canonical bytes of every existing history. This chain owns the *graph
    /// attachments*; `respell_chain` owns the *ledger spelling* and the LWW
    /// verdict. Only ever written when a graph is present, so base-free
    /// reduction is byte-unchanged.
    engraved_spelling_chain: BTreeMap<PitchId, WriteChain<Vec<SpellingAttachment>>>,
    event_modify_chain: BTreeMap<EventId, WriteChain<Event>>,
    pitch_modify_chain: BTreeMap<PitchId, WriteChain<Pitch>>,
    cross_cutting_modify_chain: BTreeMap<TypedObjectId, WriteChain<CrossCuttingValue>>,
    metric_grid_chain: BTreeMap<RegionId, WriteChain<Option<MetricGrid>>>,
    metadata_chain: WriteChain<ScoreMetadata>,
    // Genesis tranche G2a (`CONTRACT_GENESIS_G2A_SETTINGS.md` pin 6/7/8):
    // score-singleton LWW chains for the two new settings setters, mirroring
    // `metadata_chain` exactly — advisory last-writer-wins, seeded from the
    // base so a value-restoring undo of the first operational write restores
    // the pre-operational value.
    canvas_layout_defaults_chain: WriteChain<CanvasLayoutDefaults>,
    spelling_precedence_chain: WriteChain<SpellingPrecedence>,
    // Genesis tranche G2b (`CONTRACT_GENESIS_G2B_TUNING.md` pin 5): same
    // discipline, carrying the **subset** type — `accidental_extensions`
    // never participates in undo, because no operation ever writes it and
    // undo must leave it exactly as it found it.
    tuning_context_chain: WriteChain<TuningContextSettings>,
    break_chain: BTreeMap<(RegionId, MusicalPosition), WriteChain<(TimeAnchor, bool)>>,
    page_break_chain: BTreeMap<(RegionId, MusicalPosition), WriteChain<(TimeAnchor, bool)>>,
    // Meter/tempo overwrite chains (Phase-3 tranche): `Some` = a set/replace at
    // the key, `None` = an explicit removal. The meter value is the graph-level
    // `MeterChange` (anchor + signature id) so a restoration can re-install it.
    meter_change_chain: BTreeMap<(RegionId, MusicalPosition), WriteChain<Option<MeterChange>>>,
    tempo_segment_chain:
        BTreeMap<(Option<RegionId>, MusicalPosition), WriteChain<Option<TempoSegment>>>,
    staff_layout_chain: BTreeMap<StaffInstanceId, WriteChain<StaffLayoutValue>>,
    // Carried values of set-union-minted staves and time signatures, for the
    // byte-identical-re-carry idempotence check (operation_catalog §CreateStaff:
    // identical re-create is idempotent; a differing value under a live id is a
    // precondition no-op). Seeded from the base graph.
    staff_values: BTreeMap<StaffId, Staff>,
    time_signature_values: BTreeMap<TimeSignatureId, TimeSignature>,
    // Carried values of set-union-minted instruments (genesis tranche G1),
    // mirroring `staff_values`: the byte-identical-re-carry idempotence check
    // against a *base* instrument (pin 8 of
    // `CONTRACT_GENESIS_G1_INSTRUMENT.md`) has nothing to compare without this
    // — `TypedObjectId::Instrument` liveness is seeded from the base
    // (`seed_from_graph`), but the base seed left no value map before this.
    instrument_values: BTreeMap<InstrumentId, Instrument>,
    // Carried values of the four genesis tranche G3a root-level mints
    // (`spec/CONTRACT_GENESIS_G3A_ENTITIES.md` pin 4a), mirroring
    // `staff_values`/`instrument_values`: the byte-identical-re-carry
    // idempotence check against a *base*-seeded entity has nothing to compare
    // without these.
    staff_group_values: BTreeMap<StaffGroupId, StaffGroup>,
    part_definition_values: BTreeMap<PartDefinitionId, PartDefinition>,
    analysis_layer_values: BTreeMap<AnalysisLayerId, AnalysisLayer>,
    view_values: BTreeMap<ViewId, ViewDefinition>,
    // Genesis tranche G3b (`CONTRACT_GENESIS_G3B_MEASURE.md` pin 5): carried
    // values of append-only-minted measures, WITH the owning instance —
    // `Measure` has no back-pointer to its parent, so a map keyed by
    // `MeasureId` alone could not tell the graph-removal arm which
    // `StaffInstance.measures` to remove from, nor support a re-carry's
    // parent-mismatch check (a re-carry naming a *different* parent under an
    // otherwise-identical measure is `RecreateContentMismatch`, not
    // `AlreadyApplied` — the parent is part of identity here).
    measure_values: BTreeMap<MeasureId, (StaffInstanceId, Measure)>,
    // Genesis tranche G3b (contract pin 10.4): carried values of minted repeat
    // structures. `CrossCuttingValue` is `Tie | Slur | Beam | Spanner` — it has
    // no `RepeatStructure` variant, so `cross_cutting_modify_chain` can never
    // hold one, and the repeat strand-guard surface (pin 10.5) needs a value
    // to read `anchor_sites()` from. Deliberately NO delete site:
    // `delete_repeat_structure` tombstones the id in `objects` but leaves the
    // entry here — the uniform project discipline every other value map
    // follows (no `.remove` anywhere in this reducer), and the retained value
    // is what makes a tombstoned repeat still observably name a measure (the
    // guard's `Live` conjunct is what blocks a corpse, not pruning the map).
    repeat_values: BTreeMap<RepeatStructureId, RepeatStructure>,
    // Genesis tranche G3b (contract pin 6c, disposition A): whether a staff
    // instance authored a local metric-grid override, distinguishing override
    // from "never told us" — `StaffInstance.local_metric_grid` overrides the
    // enclosing region's default, but nothing tracked that distinction
    // base-free before this. `Some(None)` = an authored explicit-inherit;
    // `Some(Some(grid))` = an authored override; absent = never told (mint
    // only ever inserts, so a live instance is always present after it is
    // minted or base-seeded).
    instance_grid: BTreeMap<StaffInstanceId, Option<MetricGrid>>,
    structures: BTreeMap<TypedObjectId, Vec<TypedObjectId>>,
    // Live child sets for the structural-container empty-only delete (Group 3):
    // a region's live staff instances, and a staff instance's live voices. (A
    // voice's live events are read from `voice_occupancy`.)
    region_instances: BTreeMap<RegionId, BTreeSet<StaffInstanceId>>,
    instance_voices: BTreeMap<StaffInstanceId, BTreeSet<VoiceId>>,
    // The staff each staff instance manifests, for the containment-proximity
    // key of the re-anchoring "nearest" ordering (same staff = rank 2). Kept
    // base-free (seeded + maintained by CreateStaffInstance) so reduce() and
    // reduce_onto() rank identically wherever both represent the scenario.
    instance_staff: BTreeMap<StaffInstanceId, StaffId>,
    // Regions whose content carries a staff-based slot (staff-based or hybrid),
    // and so can hold a metric grid or user break. FreeGraphic regions cannot.
    // Tracking this lets SetMetricGrid / SetUserPageBreak / SetUserSystemBreak
    // reach the same precondition verdict for any region *represented in reducer
    // state* (those an op stream creates/deletes) whether or not a graph is
    // present. A base-only region exists in reducer state solely after
    // `seed_from_graph` (reduce_onto), so a base-free reduce() that never sees it
    // can still diverge on a base-region target — the corpus targets only
    // op-created regions, where the two agree.
    staff_based_regions: BTreeSet<RegionId>,
    migrated_regions: BTreeSet<RegionId>,
    region_migrator: BTreeMap<RegionId, OperationId>,
    descriptors: BTreeMap<TransactionId, OperationId>,
    // Losing insert -> (promoted voice, winning insert).
    promotion: BTreeMap<OperationId, (VoiceId, OperationId)>,
    // System-derived mint registry for the counter-collision check (Chapter 5
    // §"System-Derived Counter Collisions"): (kind, derived counter) → the
    // canonical inputs that derived it, plus the minting operation (None for
    // an occupant seeded from the base graph). Consulted only by the pre-walk
    // collision detection, never mutated during apply, so it needs no
    // transaction snapshot.
    system_mints: BTreeMap<(ObjectKind, u64), (SerializedCanonicalInputs, Option<OperationId>)>,
    tx_minted: BTreeMap<TransactionId, Vec<TypedObjectId>>,
    current_tx: Option<TransactionId>,
    // ResolveEquivocation promotion results (operation_catalog
    // §"ResolveEquivocation"), computed by the set-level pre-pass in `run`:
    // target slot id → (governing resolve id, chosen candidate hash), and
    // target slot id → the promoted candidate envelope (from the opset's
    // diagnostic candidate store). Pure functions of the slot map — never
    // mutated during apply — so, like `system_mints`, they need no transaction
    // snapshot.
    equivocation_resolutions: BTreeMap<OperationId, (OperationId, crate::EnvelopeHash)>,
    promoted_singles: BTreeMap<OperationId, &'a OperationEnvelope>,
    graph: Option<Score>,
    // Genesis tranche G1 (`spec/CONTRACT_GENESIS_G1_INSTRUMENT.md` pin 9):
    // whether `new_onto`'s *pristine* base was exactly `Score::empty(identity)`
    // — captured once, before any operation mutates `graph`, since by the time
    // `run()` finishes `graph` is no longer empty and cannot answer this
    // question itself. Gates the identity-cursor derivation to from-empty
    // reduction only, never a transaction snapshot (fixed for the whole run).
    from_empty_base: bool,
}

/// A snapshot of the working state, for atomic transaction rollback.
struct WorkingSnapshot {
    objects: BTreeMap<TypedObjectId, ObjectState>,
    spellings: BTreeMap<PitchId, PitchSpelling>,
    breaks: BTreeMap<(RegionId, MusicalPosition), bool>,
    page_breaks: BTreeMap<(RegionId, MusicalPosition), bool>,
    conflicts: ConflictRegistry,
    minted_by: BTreeMap<TypedObjectId, OperationId>,
    event_pitches: BTreeMap<EventId, Vec<PitchId>>,
    voice_occupancy: BTreeMap<VoiceId, Vec<(MusicalPosition, MusicalDuration, EventId)>>,
    respell_chain: BTreeMap<PitchId, WriteChain<PitchSpelling>>,
    /// A pitch's engraved-layer, pitch-scoped, explicit spelling attachment
    /// **set**, as one value. Written by *every* operation that changes it:
    /// `RespellPitch` and `TransposeInterval` alike (P13-S3).
    ///
    /// Both must record here or undo is wrong in both directions. If only the
    /// transpose recorded, a prior respell would not be its chain-predecessor
    /// and undoing the transpose would erase the respell; and a *later* respell
    /// would be invisible, so a strict undo would report `Applied` and wipe it
    /// instead of refusing as superseded.
    ///
    /// This is a *second* physical chain, not a replacement for `respell_chain`:
    /// that one is `RespellPitch`'s LWW working state, read by its
    /// concurrent-differing conflict detection, and folding transposes into it
    /// would make a concurrent respell conflict with a transpose and move the
    /// canonical bytes of every existing history. This chain owns the *graph
    /// attachments*; `respell_chain` owns the *ledger spelling* and the LWW
    /// verdict. Only ever written when a graph is present, so base-free
    /// reduction is byte-unchanged.
    engraved_spelling_chain: BTreeMap<PitchId, WriteChain<Vec<SpellingAttachment>>>,
    event_modify_chain: BTreeMap<EventId, WriteChain<Event>>,
    pitch_modify_chain: BTreeMap<PitchId, WriteChain<Pitch>>,
    cross_cutting_modify_chain: BTreeMap<TypedObjectId, WriteChain<CrossCuttingValue>>,
    metric_grid_chain: BTreeMap<RegionId, WriteChain<Option<MetricGrid>>>,
    metadata_chain: WriteChain<ScoreMetadata>,
    canvas_layout_defaults_chain: WriteChain<CanvasLayoutDefaults>,
    spelling_precedence_chain: WriteChain<SpellingPrecedence>,
    tuning_context_chain: WriteChain<TuningContextSettings>,
    break_chain: BTreeMap<(RegionId, MusicalPosition), WriteChain<(TimeAnchor, bool)>>,
    page_break_chain: BTreeMap<(RegionId, MusicalPosition), WriteChain<(TimeAnchor, bool)>>,
    meter_change_chain: BTreeMap<(RegionId, MusicalPosition), WriteChain<Option<MeterChange>>>,
    tempo_segment_chain:
        BTreeMap<(Option<RegionId>, MusicalPosition), WriteChain<Option<TempoSegment>>>,
    staff_layout_chain: BTreeMap<StaffInstanceId, WriteChain<StaffLayoutValue>>,
    staff_values: BTreeMap<StaffId, Staff>,
    time_signature_values: BTreeMap<TimeSignatureId, TimeSignature>,
    instrument_values: BTreeMap<InstrumentId, Instrument>,
    staff_group_values: BTreeMap<StaffGroupId, StaffGroup>,
    part_definition_values: BTreeMap<PartDefinitionId, PartDefinition>,
    analysis_layer_values: BTreeMap<AnalysisLayerId, AnalysisLayer>,
    view_values: BTreeMap<ViewId, ViewDefinition>,
    measure_values: BTreeMap<MeasureId, (StaffInstanceId, Measure)>,
    repeat_values: BTreeMap<RepeatStructureId, RepeatStructure>,
    instance_grid: BTreeMap<StaffInstanceId, Option<MetricGrid>>,
    structures: BTreeMap<TypedObjectId, Vec<TypedObjectId>>,
    region_instances: BTreeMap<RegionId, BTreeSet<StaffInstanceId>>,
    instance_voices: BTreeMap<StaffInstanceId, BTreeSet<VoiceId>>,
    instance_staff: BTreeMap<StaffInstanceId, StaffId>,
    staff_based_regions: BTreeSet<RegionId>,
    migrated_regions: BTreeSet<RegionId>,
    region_migrator: BTreeMap<RegionId, OperationId>,
    descriptors: BTreeMap<TransactionId, OperationId>,
    tx_minted: BTreeMap<TransactionId, Vec<TypedObjectId>>,
    graph: Option<Score>,
}

/// The precondition no-op a structural create or delete returns when a container
/// is non-empty where the operation requires it empty (a create carrying children,
/// or a delete of a container with live children).
fn container_not_empty() -> OperationEffect {
    OperationEffect::NoOp {
        reason: NoOpReason::PreconditionFailedUnderReduction {
            reason: PreconditionFailureReason::ContainerNotEmpty,
        },
    }
}

/// Apply a user break to a region's break list under the canonical LWW key — the
/// anchor's resolved musical position. Any existing anchor resolving to that same
/// position is dropped first, so two anchors at one position never both persist,
/// then the new anchor is pushed iff the break is present. The graph break list
/// then matches the resolved-position-keyed ledger map.
fn apply_break_lww(breaks: &mut Vec<TimeAnchor>, anchor: &TimeAnchor, present: bool) {
    let resolved = crate::payload::resolved_anchor_position(anchor);
    breaks.retain(|existing| crate::payload::resolved_anchor_position(existing) != resolved);
    if present {
        breaks.push(anchor.clone());
    }
}

/// The 64-byte canonical input preimage of a promoted-voice derivation
/// (`MUSCSVCE`, Chapter 5 §"System-Promoted Voices"): staff_instance ‖
/// original_voice ‖ winning_op ‖ losing_op, 16 big-endian bytes each — exactly
/// the bytes [`derive_promoted_voice_id`] hashes. The collision check compares
/// these inputs to distinguish two derivations contending for one counter.
fn promoted_voice_inputs(
    staff_instance: StaffInstanceId,
    original_voice: VoiceId,
    winning_op: OperationId,
    losing_op: OperationId,
) -> Vec<u8> {
    let mut inputs = Vec::with_capacity(64);
    inputs.extend_from_slice(&staff_instance.canonical_bytes());
    inputs.extend_from_slice(&original_voice.canonical_bytes());
    inputs.extend_from_slice(&winning_op.canonical_bytes());
    inputs.extend_from_slice(&losing_op.canonical_bytes());
    inputs
}

fn intervals_overlap(
    a_position: &MusicalPosition,
    a_duration: &MusicalDuration,
    b_position: &MusicalPosition,
    b_duration: &MusicalDuration,
) -> bool {
    if !a_duration.is_positive() || !b_duration.is_positive() {
        return false;
    }
    let a_end = a_position.clone() + a_duration.clone();
    let b_end = b_position.clone() + b_duration.clone();
    a_position < &b_end && b_position < &a_end
}

fn insert_intervals_overlap(a: &InsertEventOp, b: &InsertEventOp) -> bool {
    intervals_overlap(
        &a.musical_position(),
        &a.musical_duration(),
        &b.musical_position(),
        &b.musical_duration(),
    )
}

pub(crate) fn graph_voice_location(score: &Score, voice: VoiceId) -> Option<(usize, usize, usize)> {
    for (region_index, region) in score.canvas.regions.iter().enumerate() {
        for (instance_index, instance) in region.staff_instances().iter().enumerate() {
            if let Some(voice_index) = instance
                .voices
                .iter()
                .position(|candidate| candidate.id == voice)
            {
                return Some((region_index, instance_index, voice_index));
            }
        }
    }
    None
}

/// The verdict on a [`ModifyEvent`](OperationKind::ModifyEvent)'s placement: whether
/// it moves the target event's metric span, and if so whether the move keeps
/// invariant 3 (`VoiceEventsSortedNonOverlap`). A non-metric or same-placement modify
/// is [`Unchanged`](PlacementVerdict::Unchanged) — handled by the existing field-edit
/// path.
enum PlacementVerdict {
    /// Same placement, or a non-metric event: nothing to materialize or refuse.
    Unchanged,
    /// A metric move that would overlap a sibling, or carries a non-positive span.
    Refused,
    /// A valid metric move to `position`/`duration` within `voice`.
    Moved {
        voice: VoiceId,
        position: MusicalPosition,
        duration: MusicalDuration,
    },
}

/// The graph value inserted by a value-typed InsertEvent: the carried [`Event`]
/// itself, with its voice rebound to the (possibly system-promoted) target
/// voice. The Operation Catalog (v1) carries the real event, so this is no
/// longer a placeholder reconstruction.
fn graph_event_from_insert(op: &InsertEventOp, target_voice: VoiceId) -> Event {
    let mut event = op.event.clone();
    event.set_voice(target_voice);
    event
}

// --- Re-anchoring referent support (Chapter 6 §"Total Ordering for Nearest",
// §"The Re-Anchoring Rule Table"). --------------------------------------------

/// The tombstoned referent's resolved placement and containment, captured from
/// the graph at the moment [`Reducer::materialize_graph_delete`] removes it —
/// the referent side of the four-key "nearest" ordering and of the range
/// reconstructions in the re-anchoring rule table.
struct ReferentContext {
    voice: VoiceId,
    region: Option<RegionId>,
    position: EventPosition,
    duration: EventDuration,
}

/// Proximity bound "same staff instance" (the rule table's declared maximum for
/// markers and graphic gestures): candidates ranked farther than the referent's
/// staff instance are excluded from "nearest".
const PROXIMITY_SAME_STAFF_INSTANCE: u8 = 1;

/// Maps an *established* containment-proximity rank (k1 of the "nearest"
/// ordering) to the ratified [`ReanchorReason`] vocabulary. Rank 4 (same
/// canvas) records the appended `SameCanvasNearer` (Pass 12, P12-C4; wire
/// discriminant 6 — `DeclaredByExtension` already owned 5). Callers with a
/// possibly-*unestablished* rank 4 — `containment_rank` also returns 4 when a
/// voice's placement is unresolvable, a selection-order tie the recording
/// must not launder into a positive proximity claim — route through
/// [`Reduction::rank_reason`], which downgrades those to `ExplicitFallback`.
fn reason_for_rank(rank: u8) -> ReanchorReason {
    match rank {
        0 => ReanchorReason::SameVoiceNearer,
        1 => ReanchorReason::SameStaffInstanceNearer,
        2 => ReanchorReason::SameStaffNearer,
        3 => ReanchorReason::SameRegionNearer,
        4 => ReanchorReason::SameCanvasNearer,
        _ => ReanchorReason::ExplicitFallback,
    }
}

/// The OBJECT references among a set of [`TimeAnchor`]s — events, measures,
/// and regions (a wall-clock anchor references nothing). The mint-time
/// liveness set: every one of these must be `Live` for a mint to leave the
/// graph satisfying the reference-resolution invariants
/// (`anchor_target_exists` checks exactly these three kinds). Both reduction
/// modes agree: the base seed registers regions and measures in `objects`,
/// and base-free reductions simply have fewer live objects.
fn anchor_object_refs<'a>(anchors: impl IntoIterator<Item = &'a TimeAnchor>) -> Vec<TypedObjectId> {
    anchors
        .into_iter()
        .filter_map(|anchor| match anchor {
            TimeAnchor::Event { id, .. } => Some(TypedObjectId::Event(*id)),
            TimeAnchor::Measure { id, .. } => Some(TypedObjectId::Measure(*id)),
            TimeAnchor::Region { id, .. } => Some(TypedObjectId::Region(*id)),
            TimeAnchor::WallClock { .. } => None,
        })
        .collect()
}

/// Genesis tranche G3b (`spec/CONTRACT_GENESIS_G3B_MEASURE.md` pin 10.5):
/// whether a write-chain key's prospective POST-UNDO value references the
/// strand guard's target. Shared by every restoration-capable surface of
/// the `Measure` strand guard — spanner (`cross_cutting_modify_chain`),
/// meter change, system break, page break, and tempo segment (both anchor
/// sites) — so mutations M59/M60 target this ONE function, not five
/// separate call sites.
///
/// `matcher` returns `Some(restored_value)` when the restoration is FOR
/// this key (the target undo wrote it — `restored_value` itself may be
/// `None`, meaning "no predecessor: absent"), else `None` (this
/// restoration is unrelated to the key, i.e. the undone transaction never
/// wrote it). `references_target` asks, of a bare surface value, whether
/// IT ITSELF names the target — the one place that question is answered,
/// so a non-referencing value and an absent value are already equivalent
/// to every caller (no caller ever wants the value back, only whether it
/// blocks).
///
/// The three arms are independently mutable:
/// - a written key whose restoration REFERENCES the target blocks (M59:
///   mutating this arm to fall through to `current` instead is the
///   REINSTATED-reference regression — the restoration that would put the
///   reference back is ignored);
/// - a written key whose restoration does NOT reference the target does
///   NOT block, regardless of what the about-to-be-superseded `current`
///   value (written by the SAME undone transaction) says (M60: mutating
///   this arm to consult `current` instead is the ADDED-reference
///   regression — the transaction's own now-superseded write wrongly
///   governs);
/// - an unwritten key falls through to `current` (unaffected by M59/M60;
///   this is what the six base "surface blocks" rows exercise).
fn prospective_references_target<V>(
    restorations: &[ValueRestoration],
    matcher: impl Fn(&ValueRestoration) -> Option<Option<V>>,
    current: Option<V>,
    references_target: impl Fn(&V) -> bool,
) -> bool {
    let current_references = current.is_some_and(|v| references_target(&v));
    match restorations.iter().find_map(matcher) {
        Some(Some(restored)) if references_target(&restored) => true,
        Some(_) => false,
        None => current_references,
    }
}

/// The event references among a set of [`TimeAnchor`]s (the referent-index
/// entries a tombstone must repair). Non-event anchors contribute nothing.
fn anchor_event_refs<'a>(anchors: impl IntoIterator<Item = &'a TimeAnchor>) -> Vec<TypedObjectId> {
    anchors
        .into_iter()
        .filter_map(|anchor| match anchor {
            TimeAnchor::Event { id, .. } => Some(TypedObjectId::Event(*id)),
            _ => None,
        })
        .collect()
}

/// The event references an annotation anchor carries: its point event, or any
/// event-anchored range endpoints. Region anchors reference no event.
fn annotation_anchor_event_refs(anchor: &AnnotationAnchor) -> Vec<TypedObjectId> {
    match anchor {
        AnnotationAnchor::Event(event) => vec![TypedObjectId::Event(*event)],
        AnnotationAnchor::Range { start, end } => anchor_event_refs([start, end]),
        AnnotationAnchor::Region(_) => Vec::new(),
    }
}

/// The event references a gesture anchoring carries. `Free` anchoring follows
/// no score content and so never enters the referent index (table row: "for
/// Free anchoring, no action").
fn gesture_event_refs(anchoring: &GestureAnchoring) -> Vec<TypedObjectId> {
    match anchoring {
        GestureAnchoring::Events(events) => {
            events.iter().copied().map(TypedObjectId::Event).collect()
        }
        GestureAnchoring::Range { start, end, .. } => anchor_event_refs([start, end]),
        GestureAnchoring::Free => Vec::new(),
    }
}

/// Replaces a range endpoint anchored to the tombstoned event with the
/// containing region's edge — the deterministic "truncate" reading for
/// range-anchored referents (start endpoints move to the region start, end
/// endpoints to the region end; see DECISIONS.md and the proposed Pass-12 row
/// on the underdetermined "truncate" semantics).
fn retarget_dead_endpoint(
    endpoint: &mut TimeAnchor,
    deleted: EventId,
    region: RegionId,
    edge: RegionEdge,
) {
    if matches!(endpoint, TimeAnchor::Event { id, .. } if *id == deleted) {
        *endpoint = TimeAnchor::Region {
            id: region,
            edge,
            offset: AnchorOffset::Zero,
        };
    }
}

/// Degrades an orphaned annotation anchor's dead event references to the
/// containing-region forms, so the orphaned (kept) referent stays
/// reference-clean under invariant 10. The ledger records `Orphaned`; this is
/// anchor hygiene, not a re-anchoring choice.
fn orphan_annotation_anchor(anchor: &mut AnnotationAnchor, deleted: EventId, region: RegionId) {
    match anchor {
        AnnotationAnchor::Event(event) if *event == deleted => {
            *anchor = AnnotationAnchor::Region(region);
        }
        AnnotationAnchor::Range { start, end } => {
            retarget_dead_endpoint(start, deleted, region, RegionEdge::Start);
            retarget_dead_endpoint(end, deleted, region, RegionEdge::End);
        }
        _ => {}
    }
}

impl<'a> Reducer<'a> {
    fn new(op_set: &'a OperationSet) -> Self {
        Reducer {
            op_set,
            objects: BTreeMap::new(),
            spellings: BTreeMap::new(),
            breaks: BTreeMap::new(),
            page_breaks: BTreeMap::new(),
            conflicts: ConflictRegistry::new(),
            effects: Vec::new(),
            anomalies: BTreeMap::new(),
            minted_by: BTreeMap::new(),
            event_pitches: BTreeMap::new(),
            voice_occupancy: BTreeMap::new(),
            respell_chain: BTreeMap::new(),
            engraved_spelling_chain: BTreeMap::new(),
            event_modify_chain: BTreeMap::new(),
            pitch_modify_chain: BTreeMap::new(),
            cross_cutting_modify_chain: BTreeMap::new(),
            metric_grid_chain: BTreeMap::new(),
            metadata_chain: WriteChain::new(),
            canvas_layout_defaults_chain: WriteChain::new(),
            spelling_precedence_chain: WriteChain::new(),
            tuning_context_chain: WriteChain::new(),
            break_chain: BTreeMap::new(),
            page_break_chain: BTreeMap::new(),
            meter_change_chain: BTreeMap::new(),
            tempo_segment_chain: BTreeMap::new(),
            staff_layout_chain: BTreeMap::new(),
            staff_values: BTreeMap::new(),
            time_signature_values: BTreeMap::new(),
            instrument_values: BTreeMap::new(),
            staff_group_values: BTreeMap::new(),
            part_definition_values: BTreeMap::new(),
            analysis_layer_values: BTreeMap::new(),
            view_values: BTreeMap::new(),
            measure_values: BTreeMap::new(),
            repeat_values: BTreeMap::new(),
            instance_grid: BTreeMap::new(),
            structures: BTreeMap::new(),
            region_instances: BTreeMap::new(),
            instance_voices: BTreeMap::new(),
            instance_staff: BTreeMap::new(),
            staff_based_regions: BTreeSet::new(),
            migrated_regions: BTreeSet::new(),
            region_migrator: BTreeMap::new(),
            descriptors: BTreeMap::new(),
            promotion: BTreeMap::new(),
            system_mints: BTreeMap::new(),
            tx_minted: BTreeMap::new(),
            current_tx: None,
            equivocation_resolutions: BTreeMap::new(),
            promoted_singles: BTreeMap::new(),
            graph: None,
            from_empty_base: false,
        }
    }

    fn new_onto(op_set: &'a OperationSet, base: &Score) -> Self {
        let mut reducer = Self::new(op_set);
        // Captured from the pristine `base` argument, before `graph` is
        // populated and mutated below — `graph` is no longer empty by the
        // time `run()` needs this answer.
        reducer.from_empty_base = *base == Score::empty(base.identity.clone());
        reducer.graph = Some(base.clone());
        reducer.seed_from_graph();
        reducer
    }

    /// Seeds reduction indices from the canonical base graph. Base objects are
    /// live but have no operation minter; if a later operation tombstones one,
    /// that deleting operation is used as the provenance fallback already
    /// defined by the bookkeeping reducer.
    fn seed_from_graph(&mut self) {
        let Some(score) = self.graph.as_ref() else {
            return;
        };

        for instrument in &score.instruments {
            self.objects
                .insert(TypedObjectId::Instrument(instrument.id), ObjectState::Live);
            // The carried value backs CreateInstrument's byte-identical-re-carry
            // idempotence check against base instruments (contract pin 8) —
            // without this, `TypedObjectId::Instrument` liveness is seeded but
            // there is nothing to compare a re-carry against.
            self.instrument_values
                .insert(instrument.id, instrument.clone());
        }
        for staff in &score.staves {
            self.objects
                .insert(TypedObjectId::Staff(staff.id), ObjectState::Live);
            // The carried value backs CreateStaff's byte-identical-re-carry
            // idempotence check against base staves.
            self.staff_values.insert(staff.id, staff.clone());
        }
        for group in &score.staff_groups {
            self.objects
                .insert(TypedObjectId::StaffGroup(group.id), ObjectState::Live);
            // Genesis tranche G3a (contract pin 4a, site 4): without this seed,
            // a byte-identical re-carry against a *base* staff group finds no
            // retained value and misclassifies (the G1 `instrument_values`
            // hazard, `reduce.rs:13264`–`:13268`, copied here for all four
            // families).
            self.staff_group_values.insert(group.id, group.clone());
        }
        for part in &score.parts {
            self.objects
                .insert(TypedObjectId::PartDefinition(part.id), ObjectState::Live);
            self.part_definition_values.insert(part.id, part.clone());
        }
        for signature in &score.time_signatures {
            self.objects.insert(
                TypedObjectId::TimeSignature(signature.id),
                ObjectState::Live,
            );
            self.time_signature_values
                .insert(signature.id, signature.clone());
        }
        for layer in &score.analysis_layers {
            self.objects
                .insert(TypedObjectId::AnalysisLayer(layer.id), ObjectState::Live);
            self.analysis_layer_values.insert(layer.id, layer.clone());
        }
        for view in &score.views {
            self.objects
                .insert(TypedObjectId::View(view.id), ObjectState::Live);
            self.view_values.insert(view.id, view.clone());
        }

        // The score-level LWW chains seed with the base values so a
        // value-restoring undo of the first operational write can restore the
        // pre-operational state (operation_catalog §UndoTransaction).
        self.metadata_chain.seed(score.metadata.clone());
        // Genesis tranche G2a (contract pin 6): same discipline for the two new
        // settings setters. Both are always-valued `Score` fields — like
        // `metadata`, not a map key — so there is no "never authored" state to
        // distinguish; restoring the seeded base default is correct whether the
        // base was authored-to-default or never touched.
        self.canvas_layout_defaults_chain
            .seed(score.canvas.layout_defaults);
        self.spelling_precedence_chain
            .seed(score.spelling_precedence.clone());
        // Genesis tranche G2b (contract pin 5): same discipline, seeded with
        // only the five wire-bearing fields — the subset the chain's value
        // type carries. `accidental_extensions` is not part of the seed and
        // is never touched by undo.
        self.tuning_context_chain.seed(TuningContextSettings {
            default_pitch_space: score.tuning_context.default_pitch_space.clone(),
            default_tuning_system: score.tuning_context.default_tuning_system.clone(),
            reference: score.tuning_context.reference.clone(),
            smufl: score.tuning_context.smufl,
            overrides: score.tuning_context.overrides.clone(),
        });
        for segment in &score.tempo_map.segments {
            self.tempo_segment_chain
                .entry((None, resolved_anchor_position(&segment.start)))
                .or_insert_with(WriteChain::new)
                .seed(Some(segment.clone()));
        }

        for region in &score.canvas.regions {
            self.objects
                .insert(TypedObjectId::Region(region.id), ObjectState::Live);
            if let Some(content) = region.content.staff_based() {
                self.staff_based_regions.insert(region.id);
                self.metric_grid_chain
                    .entry(region.id)
                    .or_insert_with(WriteChain::new)
                    .seed(content.default_metric_grid.clone());
                if let Some(grid) = &content.default_metric_grid {
                    for change in &grid.meter_sequence {
                        self.meter_change_chain
                            .entry((region.id, resolved_anchor_position(&change.anchor)))
                            .or_insert_with(WriteChain::new)
                            .seed(Some(change.clone()));
                    }
                }
                for anchor in &content.user_system_breaks {
                    self.break_chain
                        .entry((region.id, resolved_anchor_position(anchor)))
                        .or_insert_with(WriteChain::new)
                        .seed((anchor.clone(), true));
                }
                for anchor in &content.user_page_breaks {
                    self.page_break_chain
                        .entry((region.id, resolved_anchor_position(anchor)))
                        .or_insert_with(WriteChain::new)
                        .seed((anchor.clone(), true));
                }
            }
            if let Some(local) = &region.local_tempo_map {
                for segment in &local.segments {
                    self.tempo_segment_chain
                        .entry((Some(region.id), resolved_anchor_position(&segment.start)))
                        .or_insert_with(WriteChain::new)
                        .seed(Some(segment.clone()));
                }
            }
            let instance_set = self.region_instances.entry(region.id).or_default();
            for instance in region.staff_instances() {
                instance_set.insert(instance.id);
            }
            for instance in region.staff_instances() {
                self.objects
                    .insert(TypedObjectId::StaffInstance(instance.id), ObjectState::Live);
                self.instance_staff.insert(instance.id, instance.staff);
                self.staff_layout_chain
                    .entry(instance.id)
                    .or_insert_with(WriteChain::new)
                    .seed((
                        instance.instrument_override,
                        instance.staff_lines_override.clone(),
                        instance.visible,
                    ));
                // Genesis tranche G3b (contract pin 6c, disposition A): record
                // whether this instance authored a local grid override, so a
                // later CreateMeasure can distinguish override from
                // inheritance without consulting the graph (base-free parity).
                self.instance_grid
                    .insert(instance.id, instance.local_metric_grid.clone());
                let voice_set = self.instance_voices.entry(instance.id).or_default();
                for voice in &instance.voices {
                    voice_set.insert(voice.id);
                }
                for measure in &instance.measures {
                    self.objects
                        .insert(TypedObjectId::Measure(measure.id), ObjectState::Live);
                    // Genesis tranche G3b (contract pin 5): the carried value
                    // backs CreateMeasure's byte-identical-re-carry
                    // idempotence check against a *base* measure — without
                    // this, `TypedObjectId::Measure` liveness is seeded but
                    // there is nothing to compare a re-carry against (the G1
                    // `instrument_values` hazard).
                    self.measure_values
                        .insert(measure.id, (instance.id, measure.clone()));
                }
                for voice in &instance.voices {
                    self.objects
                        .insert(TypedObjectId::Voice(voice.id), ObjectState::Live);
                    // Register base system-promoted voices in the mint registry
                    // so a promotion minted by this reduction is collision-checked
                    // against them (Chapter 5 §"System-Derived Counter Collisions").
                    // Base-internal duplicates keep the first registration: a base
                    // that already collided is invariant-11/18 territory, not a
                    // reduction-time mint.
                    if voice.id.replica() == ReplicaId::SYSTEM_DERIVED {
                        if let VoiceOrigin::SystemPromoted {
                            winning_operation,
                            losing_operation,
                            original_voice,
                        } = &voice.origin
                        {
                            let inputs = promoted_voice_inputs(
                                instance.id,
                                *original_voice,
                                *winning_operation,
                                *losing_operation,
                            );
                            self.system_mints
                                .entry((ObjectKind::Voice, voice.id.counter()))
                                .or_insert((SerializedCanonicalInputs(inputs), None));
                        }
                    }
                }
            }
        }

        for event in score.events.iter_canonical() {
            let event_id = event.id();
            self.objects
                .insert(TypedObjectId::Event(event_id), ObjectState::Live);
            self.event_modify_chain
                .entry(event_id)
                .or_insert_with(WriteChain::new)
                .seed(event.clone());
            let mut pitch_ids = Vec::new();
            let mut pitches = Vec::new();
            event.collect_identified_pitches(&mut pitches);
            for pitch in pitches {
                pitch_ids.push(pitch.id);
                self.objects
                    .insert(TypedObjectId::Pitch(pitch.id), ObjectState::Live);
                self.pitch_modify_chain
                    .entry(pitch.id)
                    .or_insert_with(WriteChain::new)
                    .seed(pitch.pitch.clone());
                // Register base synthetic pitches in the mint registry (same
                // rule as promoted voices above).
                if pitch.id.replica() == ReplicaId::SYSTEM_DERIVED {
                    self.system_mints
                        .entry((ObjectKind::Pitch, pitch.id.counter()))
                        .or_insert((
                            SerializedCanonicalInputs(canonical_pitch_bytes(&pitch.pitch)),
                            None,
                        ));
                }
            }
            self.event_pitches.insert(event_id, pitch_ids);

            if let (EventPosition::Musical(position), EventDuration::Musical(duration)) =
                (event.position(), event.duration())
            {
                self.voice_occupancy
                    .entry(event.voice())
                    .or_default()
                    .push((position.clone(), duration.clone(), event_id));
            }

            // A cue event *references* its source events (Chapter 5 §"Cue
            // Events"), so it enters the referent index: a source tombstone
            // cascade-deletes the cue through the re-anchoring rule table.
            if let Event::Cue(cue) = event {
                if !cue.source.is_empty() {
                    self.structures.insert(
                        TypedObjectId::Event(event_id),
                        cue.source
                            .iter()
                            .copied()
                            .map(TypedObjectId::Event)
                            .collect(),
                    );
                }
            }
        }

        for slur in &score.cross_cutting.slurs {
            let id = TypedObjectId::Slur(slur.id);
            self.objects.insert(id, ObjectState::Live);
            self.cross_cutting_modify_chain
                .entry(id)
                .or_insert_with(WriteChain::new)
                .seed(CrossCuttingValue::Slur(slur.clone()));
            self.structures.insert(
                id,
                vec![
                    TypedObjectId::Event(slur.start_event),
                    TypedObjectId::Event(slur.end_event),
                ],
            );
        }
        for tie in &score.cross_cutting.ties {
            let id = TypedObjectId::Tie(tie.id);
            self.objects.insert(id, ObjectState::Live);
            self.cross_cutting_modify_chain
                .entry(id)
                .or_insert_with(WriteChain::new)
                .seed(CrossCuttingValue::Tie(tie.clone()));
            self.structures.insert(
                id,
                vec![
                    TypedObjectId::Event(tie.start_event),
                    TypedObjectId::Event(tie.end_event),
                ],
            );
        }
        for beam in &score.cross_cutting.beams {
            let id = TypedObjectId::Beam(beam.id);
            self.objects.insert(id, ObjectState::Live);
            self.cross_cutting_modify_chain
                .entry(id)
                .or_insert_with(WriteChain::new)
                .seed(CrossCuttingValue::Beam(beam.clone()));
            self.structures.insert(
                id,
                beam.events
                    .iter()
                    .copied()
                    .map(TypedObjectId::Event)
                    .collect(),
            );
        }
        for tuplet in &score.cross_cutting.tuplets {
            let id = TypedObjectId::Tuplet(tuplet.id);
            self.objects.insert(id, ObjectState::Live);
            self.structures.insert(
                id,
                tuplet
                    .members
                    .iter()
                    .copied()
                    .map(TypedObjectId::Event)
                    .collect(),
            );
        }
        for spanner in &score.cross_cutting.spanners {
            let id = TypedObjectId::Spanner(spanner.id);
            self.objects.insert(id, ObjectState::Live);
            self.cross_cutting_modify_chain
                .entry(id)
                .or_insert_with(WriteChain::new)
                .seed(CrossCuttingValue::Spanner(spanner.clone()));
            // Record the spanner's event-anchored endpoints so a later event
            // tombstone re-anchors it through the same rule table as a created
            // spanner (keeping the graph and ledger consistent on delete).
            self.structures.insert(
                id,
                [&spanner.start, &spanner.end]
                    .into_iter()
                    .filter_map(|anchor| match anchor {
                        TimeAnchor::Event { id, .. } => Some(TypedObjectId::Event(*id)),
                        _ => None,
                    })
                    .collect(),
            );
        }
        // The remaining referent kinds of the re-anchoring rule table enter the
        // same index as slurs/ties/beams/spanners, keyed by their typed id and
        // listing the event references a tombstone must repair. Non-event
        // anchorings (region, measure, wall-clock, free) contribute no entry.
        for marker in &score.cross_cutting.markers {
            self.objects
                .insert(TypedObjectId::Marker(marker.id), ObjectState::Live);
            let refs = anchor_event_refs([&marker.anchor]);
            if !refs.is_empty() {
                self.structures
                    .insert(TypedObjectId::Marker(marker.id), refs);
            }
        }
        for annotation in &score.cross_cutting.analytical {
            self.objects.insert(
                TypedObjectId::AnalyticalAnnotation(annotation.id),
                ObjectState::Live,
            );
            let refs = annotation_anchor_event_refs(&annotation.anchor);
            if !refs.is_empty() {
                self.structures
                    .insert(TypedObjectId::AnalyticalAnnotation(annotation.id), refs);
            }
        }
        for comment in &score.cross_cutting.comments {
            self.objects
                .insert(TypedObjectId::Comment(comment.id), ObjectState::Live);
            let refs = annotation_anchor_event_refs(&comment.anchor);
            if !refs.is_empty() {
                self.structures
                    .insert(TypedObjectId::Comment(comment.id), refs);
            }
        }
        for gesture in &score.cross_cutting.graphic_gestures {
            self.objects
                .insert(TypedObjectId::GraphicGesture(gesture.id), ObjectState::Live);
            let refs = gesture_event_refs(&gesture.anchoring);
            if !refs.is_empty() {
                self.structures
                    .insert(TypedObjectId::GraphicGesture(gesture.id), refs);
            }
        }
        for repeat in &score.cross_cutting.repeats {
            self.objects
                .insert(TypedObjectId::RepeatStructure(repeat.id), ObjectState::Live);
            // Repeats participate in event re-anchoring across every anchor
            // site (rule table "Repeat structure / Anchor").
            let refs = anchor_event_refs(repeat.anchor_sites());
            if !refs.is_empty() {
                self.structures
                    .insert(TypedObjectId::RepeatStructure(repeat.id), refs);
            }
            // Genesis tranche G3b (contract pin 10.4): the carried value backs
            // the strand guard's repeat surface, which reads `anchor_sites()`
            // directly — `cross_cutting_modify_chain` cannot hold a repeat.
            self.repeat_values.insert(repeat.id, repeat.clone());
        }
        for lyric in &score.cross_cutting.lyrics {
            self.objects
                .insert(TypedObjectId::LyricLine(lyric.id), ObjectState::Live);
        }
        for chord in &score.cross_cutting.chord_symbols {
            self.objects
                .insert(TypedObjectId::ChordSymbol(chord.id), ObjectState::Live);
        }
        // The base score's explicit user-chosen per-pitch spellings seed the
        // respell chains, so undoing the first operational respell restores
        // the base attachment value rather than dropping it (the bookkeeping
        // `spellings` map still returns to key-absence — base state lives in
        // the graph, not the operational ledger).
        for attachment in &score.spelling_attachments {
            if attachment.layer.is_none() && matches!(attachment.source, SpellingSource::UserChosen)
            {
                if let (SpellingScope::Pitch(pitch), SpellingDirective::Explicit(spelling)) =
                    (&attachment.scope, &attachment.directive)
                {
                    self.respell_chain
                        .entry(*pitch)
                        .or_insert_with(WriteChain::new)
                        .seed(spelling.clone());
                }
            }
        }
        // Seed the transpose-owned attachment sets, so undoing the FIRST
        // transpose of a base-seeded pitch restores the base's attachments
        // rather than the ledger's key-absence.
        let mut by_pitch: BTreeMap<PitchId, Vec<SpellingAttachment>> = BTreeMap::new();
        for attachment in &score.spelling_attachments {
            if let Some(pitch) = Self::transpose_owned_attachment(attachment) {
                by_pitch.entry(pitch).or_default().push(attachment.clone());
            }
        }
        for (pitch, set) in by_pitch {
            self.engraved_spelling_chain
                .entry(pitch)
                .or_insert_with(WriteChain::new)
                .seed(set);
        }
    }

    /// The pitch whose spelling set `attachment` belongs to, if a
    /// `TransposeInterval` would rewrite it: engraved layer, pitch-scoped,
    /// explicit. Both the authored attachments it moves and the propagated one
    /// it writes.
    fn transpose_owned_attachment(attachment: &SpellingAttachment) -> Option<PitchId> {
        if attachment.layer.is_some() {
            return None;
        }
        let SpellingScope::Pitch(pitch) = &attachment.scope else {
            return None;
        };
        matches!(attachment.directive, SpellingDirective::Explicit(_)).then_some(*pitch)
    }

    /// The current engraved-layer explicit attachment set for `pitch`, in the
    /// graph's canonical order.
    fn graph_spelling_set(&self, pitch: PitchId) -> Vec<SpellingAttachment> {
        let Some(score) = self.graph.as_ref() else {
            return Vec::new();
        };
        score
            .spelling_attachments
            .iter()
            .filter(|a| Self::transpose_owned_attachment(a) == Some(pitch))
            .cloned()
            .collect()
    }

    /// Replaces `pitch`'s engraved-layer explicit attachment set with `set`,
    /// leaving every other attachment (other pitches, other layers) untouched
    /// and preserving the list's canonical order.
    fn graph_replace_spelling_set(&mut self, pitch: PitchId, set: &[SpellingAttachment]) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        score
            .spelling_attachments
            .retain(|a| Self::transpose_owned_attachment(a) != Some(pitch));
        score.spelling_attachments.extend(set.iter().cloned());
    }

    fn run(mut self) -> (MaterializedState, Option<Score>) {
        let singles = self.op_set.single_envelopes();
        let equivocated_all: BTreeSet<OperationId> =
            self.op_set.equivocated_ids().into_iter().collect();

        // 1. HLC monotonicity: exclude anomalous segments.
        let segments = detect_replica_anomalies(&singles);
        let mut excluded: BTreeSet<OperationId> = BTreeSet::new();
        for seg in &segments {
            excluded.extend(seg.excluded.iter().copied());
            self.record_anomaly(IntegrityAnomalyKind::ReplicaStreamQuarantined {
                replica: seg.replica,
                first_bad_counter: seg.first_bad_counter,
            });
        }

        // 1b. ResolveEquivocation promotion (operation_catalog
        // §"ResolveEquivocation"): a set-level, order-independent pre-pass.
        // Among the Single-slot, non-excluded resolves whose `target` is an
        // Equivocated slot and whose `chosen` names one of its candidates, the
        // resolve earliest in canonical order (smallest reduction tuple — the
        // same total HLC order `canonical_reduction_order` selects ready
        // operations by) governs. The chosen candidate envelope joins the
        // reducible set at its own canonical position — the slot reduces as if
        // it had always been Single — and no `OperationSlotEquivocated`
        // anomaly is recorded for it. The verdict is a pure function of the
        // slot map (never of arrival order), so every replica agrees. A
        // resolve that is itself equivocated occupies no Single slot and thus
        // never governs; a resolve in a quarantined segment is excluded from
        // reduction and likewise never governs.
        let mut governing: BTreeMap<OperationId, &OperationEnvelope> = BTreeMap::new();
        for &env in &singles {
            if excluded.contains(&env.id) {
                continue;
            }
            let OperationPayload::ResolveEquivocation(op) = &env.payload else {
                continue;
            };
            let Some(slot) = self.op_set.slot(op.target) else {
                continue;
            };
            if !slot.is_equivocated() || !slot.candidates().any(|c| c == op.chosen) {
                continue;
            }
            governing
                .entry(op.target)
                .and_modify(|current| {
                    if env.stamp.reduction_tuple() < current.stamp.reduction_tuple() {
                        *current = env;
                    }
                })
                .or_insert(env);
        }
        for (target, resolve) in &governing {
            let OperationPayload::ResolveEquivocation(op) = &resolve.payload else {
                unreachable!("only ResolveEquivocation envelopes govern a promotion");
            };
            let candidate = self
                .op_set
                .candidate(op.chosen)
                .expect("every candidate hash of an equivocated slot is retained in the store");
            self.promoted_singles.insert(*target, candidate);
            self.equivocation_resolutions
                .insert(*target, (resolve.id, op.chosen));
        }
        // The losing candidates remain only in the opset's diagnostic
        // candidate store; a resolved slot records no equivocation anomaly.
        let equivocated: BTreeSet<OperationId> = equivocated_all
            .into_iter()
            .filter(|id| !governing.contains_key(id))
            .collect();
        for id in &equivocated {
            self.record_anomaly(IntegrityAnomalyKind::OperationSlotEquivocated {
                operation_id: *id,
            });
        }

        // 2. Reducible candidates = Single slots minus excluded, plus the
        // promoted candidates (each at its own canonical position).
        let reducible: Vec<&OperationEnvelope> = singles
            .iter()
            .copied()
            .filter(|e| !excluded.contains(&e.id))
            .chain(self.promoted_singles.values().copied())
            .collect();
        let reducible_ids: BTreeSet<OperationId> = reducible.iter().map(|e| e.id).collect();
        let declared_transactions: BTreeSet<TransactionId> = singles
            .iter()
            .copied()
            .chain(self.promoted_singles.values().copied())
            .filter_map(|env| match &env.payload {
                OperationPayload::Primitive(OperationKind::DeclareTransaction(descriptor)) => {
                    Some(descriptor.id)
                }
                _ => None,
            })
            .collect();

        // 3. Missing-causal-predecessor rule → pending set (with reasons).
        let pending = compute_pending(
            &reducible,
            &reducible_ids,
            &equivocated,
            &excluded,
            &declared_transactions,
        );
        let active: Vec<&OperationEnvelope> = reducible
            .iter()
            .copied()
            .filter(|e| !pending.contains_key(&e.id))
            .collect();

        // 4. Voice-promotion pre-pass (order-independent assignment).
        self.compute_promotions(&active);

        // 5. Walk active ops in canonical reduction order; group transactions.
        let order = canonical_reduction_order(&active);
        let tx_members = transaction_members(&active);

        // 5a. System-derived counter collision check (Chapter 5 §"System-Derived
        // Counter Collisions"): on a collision, reduction does not continue past
        // the collision point, and neither colliding input set occupies the
        // collided counter. Held operations stay in the (grow-only) operation
        // set and surface in `pending` for external recovery.
        let mut held: BTreeMap<OperationId, PendingReason> = BTreeMap::new();
        if let Some((halt_index, at, earlier_owner)) = self.detect_system_collision(&order) {
            for env in &order[halt_index..] {
                held.insert(env.id, PendingReason::HaltedBySystemCollision { at });
            }
            if let Some(owner) = earlier_owner {
                held.insert(owner, PendingReason::HaltedBySystemCollision { at });
            }
            // Transitive closure: a transaction with a held member is wholly
            // held (atomicity), and an operation causally covering a held
            // operation is held behind it.
            loop {
                let mut changed = false;
                for env in &order {
                    if held.contains_key(&env.id) {
                        continue;
                    }
                    let tx_blocked = member_transaction(env)
                        .and_then(|tx| tx_members.get(&tx))
                        .and_then(|members| {
                            members
                                .iter()
                                .map(|m| m.id)
                                .filter(|id| held.contains_key(id))
                                .min()
                        });
                    let causal_blocked =
                        held.keys().copied().find(|h| env.causal_context.covers(*h));
                    if let Some(on) = tx_blocked.into_iter().chain(causal_blocked).min() {
                        held.insert(env.id, PendingReason::DependsOnPending { on });
                        changed = true;
                    }
                }
                if !changed {
                    break;
                }
            }
        }

        let mut processed: BTreeSet<OperationId> = BTreeSet::new();
        for env in &order {
            if processed.contains(&env.id) || held.contains_key(&env.id) {
                continue;
            }
            if let Some(tx) = member_transaction(env) {
                let members = tx_members.get(&tx).cloned().unwrap_or_default();
                self.reduce_transaction_block(tx, &members);
                processed.extend(members.iter().map(|m| m.id));
            } else {
                let effect = self.apply(env);
                self.effects.push((env.id, effect));
                processed.insert(env.id);
            }
        }

        let mut pending_vec: Vec<(OperationId, PendingReason)> =
            pending.into_iter().chain(held).collect();
        pending_vec.sort_by_key(|(id, _)| *id);

        // Genesis tranche G1 (`spec/CONTRACT_GENESIS_G1_INSTRUMENT.md` pin 9;
        // ruling §3 point 3): from-empty reduction is the first thing that
        // ever writes `identity`. Gated on `from_empty_base`, captured in
        // `new_onto` from the *pristine* base before any operation mutated
        // `graph` — `graph` itself is no longer empty by this point, so a
        // live re-comparison here would never fire. This keeps onto-reduction
        // against a populated base (every other caller, notably
        // `epiphany-editor-core`'s materialize-on-every-edit) byte-for-byte
        // unchanged; nothing in this packet's blast radius touches that
        // crate. Nothing between `new_onto` and here writes `identity`
        // itself, so `graph.identity`'s replica and seed are still the
        // pristine base's.
        if self.from_empty_base {
            if let Some(graph) = self.graph.as_ref() {
                let replica = graph.identity.replica_id;
                let seed = graph.identity.next_counter;
                let next_counter = self.derive_identity_cursor(replica, seed);
                self.graph
                    .as_mut()
                    .expect("checked Some above")
                    .identity
                    .next_counter = next_counter;
            }
        }

        let graph = self.graph.take();
        let state = MaterializedState {
            effects: self.effects,
            conflicts: self.conflicts,
            anomalies: self.anomalies.into_values().collect(),
            objects: self.objects,
            spellings: self.spellings,
            breaks: self.breaks,
            page_breaks: self.page_breaks,
            pending: pending_vec,
        };
        (state, graph)
    }

    /// Derives the from-empty identity cursor (ruling §3 point 3): `1 +
    /// max(counter)` over every id — an envelope's own [`OperationId`], or an
    /// entity id minted into the reduced graph — the reducing `replica`
    /// authored anywhere in the log, or the untouched `seed` when that
    /// replica authored none.
    ///
    /// `next_counter` is a *single* monotonic counter shared by every
    /// identifier kind (`IdentityContext::take_counter`), so this cannot be
    /// scoped to `Instrument` alone: any kind minted in the same log —
    /// `CreateStaff`'s `StaffId`, `InsertEvent`'s `EventId`, and so on —
    /// shares the same sequence, and a later mint from the returned identity
    /// must not re-issue a counter the log already used for *any* kind.
    fn derive_identity_cursor(&self, replica: ReplicaId, seed: u64) -> u64 {
        let mut max_counter: Option<u64> = None;
        let mut bump = |counter: u64| {
            max_counter = Some(max_counter.map_or(counter, |m| m.max(counter)));
        };
        // Every operation id ever accepted into this set, in any slot state
        // (Single, Equivocated, promoted or not): the set is keyed by
        // `OperationId`, so its key set is exactly "every id in the log" —
        // including pending/held/excluded envelopes, which still burned a
        // counter at authoring time even though this reduction did not apply
        // them.
        for (id, _) in self.op_set.slots() {
            if id.replica == replica {
                bump(id.counter);
            }
        }
        // Every entity id minted into the reduced graph, across every kind —
        // not read via a per-kind accessor, but generically from the object
        // universe every mint already populates. `TypedObjectId`'s canonical
        // form is a 2-byte discriminant then the 16-byte `(replica, counter)`
        // payload for every variant except `Registered` (an extension id with
        // no such convention, and so skipped here); reading it this way
        // avoids a new public replica/counter accessor on `TypedObjectId` in
        // `epiphany-core`, which is out of this packet's blast radius.
        for obj in self.objects.keys() {
            let bytes = obj.canonical_bytes();
            if bytes.len() == 18 {
                let id_replica = ReplicaId(u64::from_be_bytes(
                    bytes[2..10].try_into().expect("8 bytes"),
                ));
                if id_replica == replica {
                    let counter = u64::from_be_bytes(bytes[10..18].try_into().expect("8 bytes"));
                    bump(counter);
                }
            }
        }
        match max_counter {
            Some(m) => seed.max(m + 1),
            None => seed,
        }
    }

    fn record_anomaly(&mut self, kind: IntegrityAnomalyKind) {
        let a = IntegrityAnomaly::new(kind);
        self.anomalies.entry(a.id).or_insert(a);
    }

    fn env_of(&self, id: OperationId) -> Option<&'a OperationEnvelope> {
        // A slot promoted by a governing ResolveEquivocation reduces as if it
        // had always been Single with the chosen candidate.
        self.op_set
            .slot(id)
            .and_then(|s| s.single())
            .or_else(|| self.promoted_singles.get(&id).copied())
    }

    // --- Voice promotion pre-pass (Chapter 6 §6.10 InsertEvent). ------------

    fn compute_promotions(&mut self, active: &[&OperationEnvelope]) {
        // Bucket inserts by target voice. Bucketing by `op.voice` alone realizes
        // the spec's `(staff_instance, original_voice)` key: a VoiceId is
        // globally unique and (Invariant 5) belongs to exactly one staff
        // instance, so the voice id alone determines the pair. Promotion applies
        // only to concurrent operations whose half-open duration intervals overlap.
        let mut buckets: BTreeMap<VoiceId, Vec<&OperationEnvelope>> = BTreeMap::new();
        for env in active {
            if let OperationPayload::Primitive(OperationKind::InsertEvent(op)) = &env.payload {
                if self.graph_insert_precondition(op).is_err() {
                    continue;
                }
                buckets.entry(op.voice()).or_default().push(env);
            }
        }
        for (_, mut bucket) in buckets {
            if bucket.len() < 2 {
                continue;
            }
            // Retain non-overlapping operations in the original voice in
            // OperationId order. A concurrent collision with an already-kept
            // insert receives its own deterministic promoted voice.
            bucket.sort_by_key(|e| e.id);
            let mut original_voice = Vec::<&OperationEnvelope>::new();
            for env in bucket {
                let OperationPayload::Primitive(OperationKind::InsertEvent(op)) = &env.payload
                else {
                    continue;
                };
                let collision = original_voice.iter().copied().find(|kept| {
                    let OperationPayload::Primitive(OperationKind::InsertEvent(kept_op)) =
                        &kept.payload
                    else {
                        return false;
                    };
                    self.concurrent(env.id, kept.id) && insert_intervals_overlap(op, kept_op)
                });
                if let Some(winner) = collision {
                    let promoted =
                        derive_promoted_voice_id(op.staff_instance, op.voice(), winner.id, env.id);
                    self.promotion.insert(env.id, (promoted, winner.id));
                } else {
                    original_voice.push(env);
                }
            }
        }
    }

    // --- System-derived counter collision check (Chapter 5 §"System-Derived
    // Counter Collisions"). ---------------------------------------------------

    /// The system-derived identifiers an operation would admit into canonical
    /// state, each with the canonical inputs of its derivation: the promoted
    /// voice assigned by the promotion pre-pass, and any `SYSTEM_DERIVED`-
    /// namespace pitch carried by a minting payload (InsertEvent,
    /// InsertIdentifiedPitch). Non-minting references to system-derived ids —
    /// e.g. a ModifyEvent rewriting a live pitch's content in place — are
    /// deliberately not treated as mints (that is Invariant-11 territory, not a
    /// derivation collision).
    fn prospective_system_mints(
        &self,
        env: &OperationEnvelope,
    ) -> Vec<((ObjectKind, u64), SerializedCanonicalInputs)> {
        let mut mints = Vec::new();
        let OperationPayload::Primitive(kind) = &env.payload else {
            return mints;
        };
        match kind {
            OperationKind::InsertEvent(op) => {
                if let Some((promoted, winner)) = self.promotion.get(&env.id) {
                    mints.push((
                        (ObjectKind::Voice, promoted.counter()),
                        SerializedCanonicalInputs(promoted_voice_inputs(
                            op.staff_instance,
                            op.voice(),
                            *winner,
                            env.id,
                        )),
                    ));
                }
                let mut pitches = Vec::new();
                op.event.collect_identified_pitches(&mut pitches);
                for pitch in pitches {
                    if pitch.id.replica() == ReplicaId::SYSTEM_DERIVED {
                        mints.push((
                            (ObjectKind::Pitch, pitch.id.counter()),
                            SerializedCanonicalInputs(canonical_pitch_bytes(&pitch.pitch)),
                        ));
                    }
                }
            }
            OperationKind::InsertIdentifiedPitch(op)
                if op.pitch.id.replica() == ReplicaId::SYSTEM_DERIVED =>
            {
                mints.push((
                    (ObjectKind::Pitch, op.pitch.id.counter()),
                    SerializedCanonicalInputs(canonical_pitch_bytes(&op.pitch.pitch)),
                ));
            }
            _ => {}
        }
        mints
    }

    /// Walks the canonical order checking every prospective system-derived
    /// mint against the registry (base-seeded occupants plus earlier mints in
    /// the walk). On the first collision — the same `(kind, counter)` claimed
    /// by *different* canonical inputs — records the
    /// `SystemIdentifierCollision` anomaly and returns the halt point
    /// `(index, colliding op, earlier occupant op)`: reduction must not
    /// continue past the collision, and neither input set may occupy the
    /// collided counter (§"System-Derived Counter Collisions"). The earlier
    /// occupant is `None` when it was seeded from the base graph, which cannot
    /// be evicted by this reduction and is left to diagnostic recovery.
    ///
    /// The check is conservative: a claimed mint participates even if the
    /// operation would later fail an unrelated apply-time precondition —
    /// two input sets contending for one counter is a structural identity
    /// failure regardless of which contender ultimately materializes.
    fn detect_system_collision(
        &mut self,
        order: &[&OperationEnvelope],
    ) -> Option<(usize, OperationId, Option<OperationId>)> {
        for (index, env) in order.iter().enumerate() {
            for (key, inputs) in self.prospective_system_mints(env) {
                match self.system_mints.get(&key) {
                    None => {
                        self.system_mints.insert(key, (inputs, Some(env.id)));
                    }
                    Some((existing, _)) if existing.0 == inputs.0 => {
                        // The same derivation re-observed: not a collision.
                    }
                    Some((existing, owner)) => {
                        let owner = *owner;
                        let existing = existing.clone();
                        self.record_anomaly(IntegrityAnomalyKind::SystemIdentifierCollision {
                            kind: key.0,
                            colliding_counter: key.1,
                            input_set_a: existing,
                            input_set_b: inputs,
                        });
                        return Some((index, env.id, owner));
                    }
                }
            }
        }
        None
    }

    fn graph_insert_precondition(
        &self,
        op: &InsertEventOp,
    ) -> Result<(usize, usize, usize), PreconditionFailureReason> {
        let Some(score) = self.graph.as_ref() else {
            return Ok((0, 0, 0));
        };
        let location = graph_voice_location(score, op.voice())
            .ok_or(PreconditionFailureReason::VoiceMissing)?;
        let (region_index, instance_index, _) = location;
        let region = &score.canvas.regions[region_index];
        let instance = &region.staff_instances()[instance_index];
        if instance.id != op.staff_instance {
            return Err(PreconditionFailureReason::VoiceMissing);
        }
        if !matches!(region.time_model, epiphany_core::RegionTimeModel::Metric(_)) {
            return Err(PreconditionFailureReason::WrongRegionTimeModel);
        }
        let event_id = op.event_id();
        if score.events.contains(event_id)
            || score.tombstoned_events.contains(&event_id)
            || op.pitch_ids().iter().any(|pitch| {
                self.objects.contains_key(&TypedObjectId::Pitch(*pitch))
                    || score.tombstoned_pitches.contains(pitch)
            })
        {
            return Err(PreconditionFailureReason::TargetTombstoned);
        }
        Ok(location)
    }

    fn materialize_graph_insert(
        &mut self,
        env: &OperationEnvelope,
        op: &InsertEventOp,
        location: (usize, usize, usize),
        target_voice: VoiceId,
        promotion: Option<(VoiceId, OperationId)>,
    ) -> Result<(), PreconditionFailureReason> {
        let Some(score) = self.graph.as_mut() else {
            return Ok(());
        };
        let (region_index, instance_index, voice_index) = location;
        let event = graph_event_from_insert(op, target_voice);
        score
            .events
            .insert(event)
            .map_err(|_| PreconditionFailureReason::EventDurationInvalid)?;

        if let Some((promoted, winner)) = promotion {
            let instance = score.canvas.regions[region_index]
                .content
                .staff_instances_mut()
                .expect("the precondition found a staff-based instance")
                .get_mut(instance_index)
                .expect("the precondition found this instance");
            instance.voices.push(Voice {
                id: promoted,
                events: vec![op.event_id()],
                default_stem_direction: None,
                is_primary: false,
                origin: VoiceOrigin::SystemPromoted {
                    winning_operation: winner,
                    losing_operation: env.id,
                    original_voice: op.voice(),
                },
            });
        } else {
            let mut ordered = score.canvas.regions[region_index].staff_instances()[instance_index]
                .voices[voice_index]
                .events
                .clone();
            ordered.push(op.event_id());
            ordered.sort_by(|a, b| {
                let a_position = score.events.get(*a).map(Event::position);
                let b_position = score.events.get(*b).map(Event::position);
                match (a_position, b_position) {
                    (
                        Some(EventPosition::Musical(a_position)),
                        Some(EventPosition::Musical(b_position)),
                    ) => a_position.cmp(b_position).then_with(|| a.cmp(b)),
                    _ => a.cmp(b),
                }
            });
            score.canvas.regions[region_index]
                .content
                .staff_instances_mut()
                .expect("the precondition found a staff-based instance")[instance_index]
                .voices[voice_index]
                .events = ordered;
        }
        Ok(())
    }

    fn graph_delete_precondition(
        &self,
        op: &DeleteEventOp,
    ) -> Result<(), PreconditionFailureReason> {
        let Some(score) = self.graph.as_ref() else {
            return Ok(());
        };
        let event = score
            .events
            .get(op.event)
            .ok_or(PreconditionFailureReason::TargetMissing)?;
        let containing_tuplets: Vec<_> = score
            .cross_cutting
            .tuplets
            .iter()
            .filter(|tuplet| tuplet.members.contains(&op.event))
            .map(|tuplet| tuplet.id)
            .collect();
        match &op.tuplet_compensation {
            TupletCompensation::NotInTuplet if !containing_tuplets.is_empty() => {
                Err(PreconditionFailureReason::TupletCompensationInvalid)
            }
            TupletCompensation::NotInTuplet => Ok(()),
            TupletCompensation::ReplaceWithRest { rest } => {
                if score.events.contains(rest.id)
                    || score.tombstoned_events.contains(&rest.id)
                    || event.duration() != &rest.duration
                {
                    Err(PreconditionFailureReason::TupletCompensationInvalid)
                } else {
                    Ok(())
                }
            }
            // The prototype payload carries only ids, not the rewritten tuplet
            // values required to preserve invariant 16. Graph-aware reduction
            // refuses to fabricate those values.
            TupletCompensation::RewriteTuplets { .. } => {
                Err(PreconditionFailureReason::TupletCompensationInvalid)
            }
            TupletCompensation::CascadeDeleteTuplets { tuplets } => {
                let listed: BTreeSet<_> = tuplets.iter().copied().collect();
                let containing: BTreeSet<_> = containing_tuplets.into_iter().collect();
                if listed == containing && !listed.is_empty() {
                    Ok(())
                } else {
                    Err(PreconditionFailureReason::TupletCompensationInvalid)
                }
            }
        }
    }

    /// Removes the deleted event from the materialized graph and keeps it
    /// reference-clean. Returns the repair records for the re-anchoring this
    /// performs beyond the bookkeeping rules — the rule-table rows for the
    /// graph-only referent kinds (markers, cue events, comments, analytical
    /// annotations, graphic gestures) via [`Self::reanchor_event_referents`] —
    /// so the triggering operation's effect can record them (Chapter 6
    /// §Re-Anchoring: "Re-anchoring actions MUST be recorded as RepairRecord
    /// entries in the triggering operation's effect").
    fn materialize_graph_delete(
        &mut self,
        env: &OperationEnvelope,
        op: &DeleteEventOp,
    ) -> Vec<RepairRecord> {
        let Some(score) = self.graph.as_mut() else {
            return Vec::new();
        };
        let Some(event) = score.events.remove(op.event) else {
            return Vec::new();
        };
        let voice_id = event.voice();
        let location = graph_voice_location(score, voice_id);
        let region_id = location.map(|(region, _, _)| score.canvas.regions[region].id);
        // The referent side of the four-key "nearest" ordering, captured before
        // any mutation: the tombstoned event's containment and resolved
        // placement (positions are region-relative; exact rational time in
        // metric regions).
        let referent = ReferentContext {
            voice: voice_id,
            region: region_id,
            position: event.position().clone(),
            duration: event.duration().clone(),
        };
        let removed_event_index = location.and_then(|(region, instance, voice)| {
            score.canvas.regions[region].staff_instances()[instance].voices[voice]
                .events
                .iter()
                .position(|event| *event == op.event)
        });
        if let Some((region_index, instance_index, voice_index)) = location {
            score.canvas.regions[region_index]
                .content
                .staff_instances_mut()
                .expect("an event voice belongs to staff-based content")[instance_index]
                .voices[voice_index]
                .events
                .retain(|id| *id != op.event);
        }

        let mut identified = Vec::new();
        event.collect_identified_pitches(&mut identified);
        let deleted_pitches: Vec<PitchId> = identified.iter().map(|pitch| pitch.id).collect();
        score.tombstoned_events.insert(op.event);
        score
            .tombstoned_pitches
            .extend(deleted_pitches.iter().copied());

        match &op.tuplet_compensation {
            TupletCompensation::ReplaceWithRest { rest } => {
                let new_rest = rest.id;
                for tuplet in &mut score.cross_cutting.tuplets {
                    for member in &mut tuplet.members {
                        if *member == op.event {
                            *member = new_rest;
                        }
                    }
                }
                // The value-typed payload (v1) carries the replacement Rest; it
                // is placed at the deleted event's voice and position.
                let mut replacement = rest.clone();
                replacement.voice = voice_id;
                replacement.position = event.position().clone();
                score
                    .events
                    .insert(Event::Rest(replacement))
                    .expect("replacement-rest preconditions were checked");
                if let Some((region_index, instance_index, voice_index)) =
                    graph_voice_location(score, voice_id)
                {
                    let voice = &mut score.canvas.regions[region_index]
                        .content
                        .staff_instances_mut()
                        .expect("an event voice belongs to staff-based content")[instance_index]
                        .voices[voice_index];
                    if !voice.events.contains(&new_rest) {
                        let index = removed_event_index
                            .unwrap_or(voice.events.len())
                            .min(voice.events.len());
                        voice.events.insert(index, new_rest);
                    }
                }
            }
            TupletCompensation::CascadeDeleteTuplets { tuplets } => {
                let removed: BTreeSet<_> = tuplets.iter().copied().collect();
                score
                    .cross_cutting
                    .tuplets
                    .retain(|tuplet| !removed.contains(&tuplet.id));
                // A decomposition component records its tuplet by id; once that tuplet is
                // gone the reference would dangle (invariant 6, cross-cutting refs
                // resolve), so drop any attachment that names a removed tuplet. The
                // member it described is being tombstoned in the same cascade, so the
                // decomposition has nothing left to describe.
                score.decomposition_attachments.retain(|attachment| {
                    !attachment
                        .components
                        .iter()
                        .any(|component| component.tuplet.is_some_and(|t| removed.contains(&t)))
                });
            }
            TupletCompensation::NotInTuplet | TupletCompensation::RewriteTuplets { .. } => {}
        }

        // Keep the materialized graph reference-clean. The detailed repair
        // records remain in Chapter 6 state; these graph updates realize the
        // representative event-anchored structures Agent B models.
        score
            .cross_cutting
            .ties
            .retain(|tie| tie.start_event != op.event && tie.end_event != op.event);
        score.cross_cutting.beams.retain_mut(|beam| {
            beam.events.retain(|event| *event != op.event);
            beam.events.len() >= 2
        });
        // Slurs and spanners follow the bookkeeping re-anchoring rule: an
        // endpoint-deleted structure re-anchors to its surviving endpoint while
        // one survives, and cascade-deletes only when none does (Chapter 6 §6.5;
        // matching `reanchor_for_tombstone`, so the graph and the ledger agree on
        // the structure's existence). A re-anchored two-endpoint structure
        // collapses onto the survivor — degenerate but reference-clean (both
        // endpoints stay live); proximity-aware re-anchoring is deferred (P11-C5).
        let slurs = std::mem::take(&mut score.cross_cutting.slurs);
        let kept_slurs: Vec<_> = slurs
            .into_iter()
            .filter_map(|mut slur| {
                let start_hit = slur.start_event == op.event;
                let end_hit = slur.end_event == op.event;
                if !start_hit && !end_hit {
                    return Some(slur);
                }
                let survivor = if start_hit {
                    slur.end_event
                } else {
                    slur.start_event
                };
                if survivor != op.event && score.events.contains(survivor) {
                    slur.start_event = if start_hit {
                        survivor
                    } else {
                        slur.start_event
                    };
                    slur.end_event = if end_hit { survivor } else { slur.end_event };
                    Some(slur)
                } else {
                    None
                }
            })
            .collect();
        score.cross_cutting.slurs = kept_slurs;

        let spanners = std::mem::take(&mut score.cross_cutting.spanners);
        let kept_spanners: Vec<_> = spanners
            .into_iter()
            .filter_map(|mut spanner| {
                let start_hit =
                    matches!(spanner.start, TimeAnchor::Event { id, .. } if id == op.event);
                let end_hit = matches!(spanner.end, TimeAnchor::Event { id, .. } if id == op.event);
                if !start_hit && !end_hit {
                    return Some(spanner);
                }
                // The survivor is the *other* anchor's event, if it is an event
                // anchor on a live event; otherwise the spanner cascade-deletes.
                let other = if start_hit {
                    &spanner.end
                } else {
                    &spanner.start
                };
                let survivor = match other {
                    TimeAnchor::Event { id, .. }
                        if *id != op.event && score.events.contains(*id) =>
                    {
                        Some(*id)
                    }
                    _ => None,
                };
                let to = survivor?;
                if start_hit {
                    if let TimeAnchor::Event { id, .. } = &mut spanner.start {
                        *id = to;
                    }
                }
                if end_hit {
                    if let TimeAnchor::Event { id, .. } = &mut spanner.end {
                        *id = to;
                    }
                }
                Some(spanner)
            })
            .collect();
        score.cross_cutting.spanners = kept_spanners;

        // Repeat structures follow the same rule across EVERY anchor site
        // (start/end, jump targets, volta spans): each dead event anchor
        // re-anchors to the nearest surviving event anchor — the
        // lexicographically smallest, matching `nearest_survivor`, so the
        // graph and the ledger agree on both existence and target — and the
        // structure cascade-deletes only when no event anchor survives.
        let repeats = std::mem::take(&mut score.cross_cutting.repeats);
        let kept_repeats: Vec<_> = repeats
            .into_iter()
            .filter_map(|mut repeat| {
                let hit = repeat
                    .anchor_sites()
                    .into_iter()
                    .any(|a| matches!(a, TimeAnchor::Event { id, .. } if *id == op.event));
                if !hit {
                    return Some(repeat);
                }
                let survivor = repeat
                    .anchor_sites()
                    .into_iter()
                    .filter_map(|a| match a {
                        TimeAnchor::Event { id, .. }
                            if *id != op.event && score.events.contains(*id) =>
                        {
                            Some(*id)
                        }
                        _ => None,
                    })
                    .min()?;
                for site in repeat.anchor_sites_mut() {
                    if let TimeAnchor::Event { id, .. } = site {
                        if *id == op.event {
                            *id = survivor;
                        }
                    }
                }
                Some(repeat)
            })
            .collect();
        score.cross_cutting.repeats = kept_repeats;

        score.cross_cutting.lyrics.retain_mut(|line| {
            line.events.retain(|event| *event != op.event);
            !line.events.is_empty()
        });
        // The remaining rule-table rows — markers, cue events, comments,
        // analytical annotations, graphic gestures — are decided and applied
        // together (ledger record + graph mutation) once the event is out of
        // the graph, so the two can never disagree.
        self.reanchor_event_referents(env, op.event, &referent)
    }

    fn materialize_graph_tombstones(
        &mut self,
        env: &OperationEnvelope,
        targets: &[TypedObjectId],
    ) -> Vec<RepairRecord> {
        let mut repairs = Vec::new();
        let events: Vec<EventId> = targets
            .iter()
            .filter_map(|target| match target {
                TypedObjectId::Event(event) => Some(*event),
                _ => None,
            })
            .collect();
        for event in events {
            for placements in self.voice_occupancy.values_mut() {
                placements.retain(|(_, _, stored_event)| *stored_event != event);
            }
            self.voice_occupancy
                .retain(|_, placements| !placements.is_empty());
            repairs.extend(self.materialize_graph_delete(
                env,
                &DeleteEventOp {
                    event,
                    tuplet_compensation: TupletCompensation::NotInTuplet,
                },
            ));
        }

        let Some(score) = self.graph.as_mut() else {
            return repairs;
        };
        for target in targets {
            match target {
                TypedObjectId::Pitch(pitch) => {
                    score.tombstoned_pitches.insert(*pitch);
                }
                TypedObjectId::Voice(voice) => {
                    for region in &mut score.canvas.regions {
                        if let Some(instances) = region.content.staff_instances_mut() {
                            for instance in instances {
                                instance.voices.retain(|candidate| {
                                    candidate.id != *voice || !candidate.events.is_empty()
                                });
                            }
                        }
                    }
                }
                TypedObjectId::Slur(id) => {
                    score.cross_cutting.slurs.retain(|value| value.id != *id);
                }
                TypedObjectId::Tie(id) => {
                    score.cross_cutting.ties.retain(|value| value.id != *id);
                }
                TypedObjectId::Beam(id) => {
                    score.cross_cutting.beams.retain(|value| value.id != *id);
                }
                // Spanner was missing from this walk (an undone spanner mint
                // left a ghost value in the graph) — fixed alongside the
                // repeat arm; both mirror the slur/tie/beam removals.
                TypedObjectId::Spanner(id) => {
                    score.cross_cutting.spanners.retain(|value| value.id != *id);
                }
                TypedObjectId::RepeatStructure(id) => {
                    score.cross_cutting.repeats.retain(|value| value.id != *id);
                }
                // Phase-3 mints: a tombstoned staff / time signature leaves the
                // graph (the undo path preconditions no live reference remains).
                TypedObjectId::Staff(id) => {
                    score.staves.retain(|value| value.id != *id);
                }
                TypedObjectId::TimeSignature(id) => {
                    score.time_signatures.retain(|value| value.id != *id);
                }
                // Genesis tranche G3a mints, plus G1's `Instrument` (contract
                // `spec/CONTRACT_GENESIS_G3A_UNDO_REPAIR.md` pin A1): the
                // ledger tombstones these five kinds too, and the graph must
                // agree — mirroring the `Staff` / `TimeSignature` arms above.
                TypedObjectId::StaffGroup(id) => {
                    score.staff_groups.retain(|value| value.id != *id);
                }
                TypedObjectId::PartDefinition(id) => {
                    score.parts.retain(|value| value.id != *id);
                }
                TypedObjectId::AnalysisLayer(id) => {
                    score.analysis_layers.retain(|value| value.id != *id);
                }
                TypedObjectId::View(id) => {
                    score.views.retain(|value| value.id != *id);
                }
                TypedObjectId::Instrument(id) => {
                    score.instruments.retain(|value| value.id != *id);
                }
                // Genesis tranche G3b (contract pin 10.1): `Measure` is a
                // nested container child of `StaffInstance.measures`, not a
                // root vector, so this cannot be a bare `retain` over
                // `score` — it must reach the owning instance. `measure_values`
                // (pin 5) carries that parent id, so no search over every
                // region/instance is needed.
                TypedObjectId::Measure(id) => {
                    if let Some((instance, _)) = self.measure_values.get(id) {
                        let instance = *instance;
                        for region in &mut score.canvas.regions {
                            if let Some(instances) = region.content.staff_instances_mut() {
                                if let Some(inst) = instances.iter_mut().find(|i| i.id == instance)
                                {
                                    inst.measures.retain(|m| m.id != *id);
                                    break;
                                }
                            }
                        }
                    }
                }
                _ => {}
            }
        }
        repairs
    }

    fn materialize_graph_cross_cutting(
        &mut self,
        op: &CreateCrossCuttingOp,
    ) -> Result<(), PreconditionFailureReason> {
        let Some(score) = self.graph.as_mut() else {
            return Ok(());
        };
        // The value-typed payload (v1) carries the real structure with its rich
        // fields, so materialization clones it directly rather than rebuilding a
        // default from the reference-level projection.
        match &op.structure {
            CrossCuttingValue::Slur(slur) => score.cross_cutting.slurs.push(slur.clone()),
            CrossCuttingValue::Beam(beam) => {
                if beam.events.len() < 2 {
                    return Err(PreconditionFailureReason::TargetMissing);
                }
                score.cross_cutting.beams.push(beam.clone());
            }
            CrossCuttingValue::Tie(tie) => score.cross_cutting.ties.push(tie.clone()),
            CrossCuttingValue::Spanner(spanner) => {
                score.cross_cutting.spanners.push(spanner.clone())
            }
        }
        Ok(())
    }

    // --- Dispatch. ----------------------------------------------------------

    fn apply(&mut self, env: &OperationEnvelope) -> OperationEffect {
        match &env.payload {
            OperationPayload::Primitive(kind) => match kind {
                OperationKind::InsertEvent(op) => self.insert_event(env, op),
                OperationKind::DeleteEvent(op) => self.delete_event(env, op),
                OperationKind::RespellPitch(op) => self.respell_pitch(env, op),
                OperationKind::CreateCrossCutting(op) => self.create_cross_cutting(env, op),
                OperationKind::ChangeRegionTimeModel(op) => self.change_region_time_model(env, op),
                OperationKind::SetUserSystemBreak(op) => self.set_user_system_break(env, op),
                OperationKind::DeclareTransaction(desc) => {
                    self.descriptors.insert(desc.id, env.id);
                    OperationEffect::Applied
                }
                // Extension-defined primitive: opaque to the core; recorded as
                // applied (the extension realizes its own effect).
                OperationKind::Registered(_, _) => OperationEffect::Applied,
                OperationKind::ModifyEvent(op) => self.modify_event(env, op),
                OperationKind::Transpose(op) => self.transpose(env, op),
                OperationKind::TransposeInterval(op) => self.transpose_interval(env, op),
                OperationKind::InsertIdentifiedPitch(op) => self.insert_identified_pitch(env, op),
                OperationKind::DeleteIdentifiedPitch(op) => self.delete_identified_pitch(env, op),
                OperationKind::ModifyIdentifiedPitch(op) => self.modify_identified_pitch(env, op),
                OperationKind::DeleteCrossCutting(op) => self.delete_cross_cutting(env, op),
                OperationKind::ModifyCrossCutting(op) => self.modify_cross_cutting(env, op),
                OperationKind::CreateRegion(op) => self.create_region(env, op),
                OperationKind::DeleteRegion(op) => self.delete_region(env, op),
                OperationKind::CreateStaffInstance(op) => self.create_staff_instance(env, op),
                OperationKind::DeleteStaffInstance(op) => self.delete_staff_instance(env, op),
                OperationKind::CreateVoice(op) => self.create_voice(env, op),
                OperationKind::DeleteVoice(op) => self.delete_voice(env, op),
                OperationKind::SetMetadata(op) => self.set_metadata(env, op),
                OperationKind::SetMetricGrid(op) => self.set_metric_grid(env, op),
                OperationKind::SetUserPageBreak(op) => self.set_user_page_break(env, op),
                OperationKind::CreateStaff(op) => self.create_staff(env, op),
                OperationKind::SetTimeSignature(op) => self.set_time_signature(env, op),
                OperationKind::SetTempoSegment(op) => self.set_tempo_segment(env, op),
                OperationKind::SetStaffLayout(op) => self.set_staff_layout(env, op),
                OperationKind::CreateRepeatStructure(op) => self.create_repeat_structure(env, op),
                OperationKind::DeleteRepeatStructure(op) => self.delete_repeat_structure(env, op),
                OperationKind::CreateInstrument(op) => self.create_instrument(env, op),
                OperationKind::SetCanvasLayoutDefaults(op) => {
                    self.set_canvas_layout_defaults(env, op)
                }
                OperationKind::SetSpellingPrecedence(op) => self.set_spelling_precedence(env, op),
                OperationKind::SetTuningContext(op) => self.set_tuning_context(env, op),
                OperationKind::CreateStaffGroup(op) => self.create_staff_group(env, op),
                OperationKind::CreatePartDefinition(op) => self.create_part_definition(env, op),
                OperationKind::CreateAnalysisLayer(op) => self.create_analysis_layer(env, op),
                OperationKind::CreateView(op) => self.create_view(env, op),
                OperationKind::CreateMeasure(op) => self.create_measure(env, op),
            },
            OperationPayload::ResolveConflict(op) => self.resolve_conflict(env, op),
            OperationPayload::UndoTransaction(op) => self.undo_transaction(env, op),
            OperationPayload::ResolveEquivocation(op) => self.resolve_equivocation(env, op),
        }
    }

    // --- Per-kind reduction. ------------------------------------------------

    fn set_user_system_break(
        &mut self,
        env: &OperationEnvelope,
        op: &crate::payload::SetUserSystemBreakOp,
    ) -> OperationEffect {
        if let Some(effect) = self.layout_region_slot(op.region) {
            return effect;
        }
        if let Some(score) = self.graph.as_mut() {
            if let Some(region) = score.canvas.regions.iter_mut().find(|r| r.id == op.region) {
                if let Some(content) = region.content.staff_based_mut() {
                    apply_break_lww(&mut content.user_system_breaks, &op.anchor, op.present);
                }
            }
        }

        // The LWW bucketing key is the anchor's resolved musical position.
        let key = (op.region, op.resolved_position());
        self.breaks.insert(key.clone(), op.present);
        self.break_chain
            .entry(key)
            .or_insert_with(WriteChain::new)
            .record(env.id, env.transaction, (op.anchor.clone(), op.present));
        OperationEffect::Applied
    }

    // --- Group 4 (M2d): score settings (LWW field-overwrite). --------------
    //
    // SetMetadata is an *advisory* last-writer-wins field (operation_catalog
    // §set-user-system-break "LWW advisory"): the latest write in canonical order
    // silently wins, with no conflict — a clean concurrent metadata edit keeps the
    // state clean. SetMetricGrid is a structural field-overwrite: the resolved grid
    // lives in the graph and a concurrent differing grid records a
    // StructuralFieldCollision. SetUserPageBreak mirrors SetUserSystemBreak: a
    // canonical LWW advisory (page_breaks).
    //
    // SetMetricGrid / SetUserPageBreak target a region's staff-based slot, so they
    // share `layout_region_slot`: the region must be live *and* staff-based (a
    // FreeGraphic region has neither a metric grid nor a break list). That verdict
    // reads only the base-free indices, so reduce() and reduce_onto() agree on it.

    /// `Some(NoOp)` when `region` cannot carry a metric grid or user break — it is
    /// missing, tombstoned, or FreeGraphic; `None` when it has a staff-based slot.
    fn layout_region_slot(&self, region: RegionId) -> Option<OperationEffect> {
        let live = matches!(
            self.objects.get(&TypedObjectId::Region(region)),
            Some(ObjectState::Live)
        );
        if live && self.staff_based_regions.contains(&region) {
            None
        } else {
            Some(OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetMissing,
                },
            })
        }
    }

    fn set_metadata(&mut self, env: &OperationEnvelope, op: &SetMetadataOp) -> OperationEffect {
        // Advisory LWW: no conflict, no idempotence short-circuit. The resolved
        // value is the last write in canonical order, held in the graph. The
        // write chain backs value-restoring undo only.
        self.metadata_chain
            .record(env.id, env.transaction, op.metadata.clone());
        if let Some(score) = self.graph.as_mut() {
            score.metadata = op.metadata.clone();
        }
        OperationEffect::Applied
    }

    /// Genesis tranche G2a (`CONTRACT_GENESIS_G2A_SETTINGS.md` pin 5): copies
    /// `set_metadata` structurally — advisory LWW, no conflict, no idempotence
    /// short-circuit. A re-write of an identical value is a legitimate new
    /// write, not a no-op.
    fn set_canvas_layout_defaults(
        &mut self,
        env: &OperationEnvelope,
        op: &SetCanvasLayoutDefaultsOp,
    ) -> OperationEffect {
        self.canvas_layout_defaults_chain
            .record(env.id, env.transaction, op.layout_defaults);
        if let Some(score) = self.graph.as_mut() {
            score.canvas.layout_defaults = op.layout_defaults;
        }
        OperationEffect::Applied
    }

    /// Genesis tranche G2a (`CONTRACT_GENESIS_G2A_SETTINGS.md` pin 5): copies
    /// `set_metadata` structurally — advisory LWW, no conflict, no idempotence
    /// short-circuit. A re-write of an identical value is a legitimate new
    /// write, not a no-op.
    fn set_spelling_precedence(
        &mut self,
        env: &OperationEnvelope,
        op: &SetSpellingPrecedenceOp,
    ) -> OperationEffect {
        self.spelling_precedence_chain
            .record(env.id, env.transaction, op.precedence.clone());
        if let Some(score) = self.graph.as_mut() {
            score.spelling_precedence = op.precedence.clone();
        }
        OperationEffect::Applied
    }

    /// Genesis tranche G2b (`CONTRACT_GENESIS_G2B_TUNING.md` pin 5): copies
    /// `set_metadata` structurally — advisory LWW, no conflict, no
    /// idempotence short-circuit. Writes exactly the five subset fields onto
    /// `score.tuning_context` and **leaves `accidental_extensions`
    /// untouched** — the carried payload has no such field, and preserving
    /// whatever the graph already held is the ruling (contract §1).
    fn set_tuning_context(
        &mut self,
        env: &OperationEnvelope,
        op: &SetTuningContextOp,
    ) -> OperationEffect {
        self.tuning_context_chain
            .record(env.id, env.transaction, op.settings.clone());
        if let Some(score) = self.graph.as_mut() {
            score.tuning_context.default_pitch_space = op.settings.default_pitch_space.clone();
            score.tuning_context.default_tuning_system = op.settings.default_tuning_system.clone();
            score.tuning_context.reference = op.settings.reference.clone();
            score.tuning_context.smufl = op.settings.smufl;
            score.tuning_context.overrides = op.settings.overrides.clone();
            // accidental_extensions is intentionally not touched here.
        }
        OperationEffect::Applied
    }

    fn set_metric_grid(
        &mut self,
        env: &OperationEnvelope,
        op: &SetMetricGridOp,
    ) -> OperationEffect {
        if let Some(effect) = self.layout_region_slot(op.region) {
            return effect;
        }
        // A non-empty grid names a time signature per meter change; the graph
        // invariant (epiphany-core invariants.rs) rejects a grid that references an
        // undeclared signature, so reject it here rather than install an
        // invariant-violating grid. Time signatures are seeded from the base, so
        // this verdict is identical with or without a graph.
        if let Some(grid) = &op.grid {
            for change in &grid.meter_sequence {
                if !matches!(
                    self.objects
                        .get(&TypedObjectId::TimeSignature(change.time_signature)),
                    Some(ObjectState::Live)
                ) {
                    return OperationEffect::NoOp {
                        reason: NoOpReason::PreconditionFailedUnderReduction {
                            reason: PreconditionFailureReason::TargetMissing,
                        },
                    };
                }
            }
        }
        // Contract pin 9c.1: the RESULTING grid must not break invariant
        // 20's agreement or boundary clause for any live measure the change
        // reaches. Checked before any write (there is no mint in this
        // operation to leak, but the check precedes the write regardless,
        // for uniformity with `set_time_signature`).
        if let Some(effect) =
            self.check_grid_preserves_invariant20(op.region, Some(&op.grid), &BTreeMap::new(), None)
        {
            return effect;
        }
        let prev = self
            .metric_grid_chain
            .get(&op.region)
            .and_then(|chain| chain.last_write())
            .map(|write| (write.op, write.value.clone()));
        let effect = match prev {
            Some((prev_op, prev_grid)) if self.concurrent(env.id, prev_op) => {
                if prev_grid == op.grid {
                    return OperationEffect::NoOp {
                        reason: NoOpReason::AlreadyApplied,
                    };
                }
                let conflict = ConflictRecord::new(
                    ConflictKind::StructuralFieldCollision {
                        winner: env.id,
                        loser: prev_op,
                        field: FieldPath("metric_grid".to_string()),
                    },
                    vec![env.id, prev_op],
                    vec![TypedObjectId::Region(op.region)],
                );
                let cid = conflict.id;
                self.conflicts.insert(conflict);
                OperationEffect::Conflicted { conflict: cid }
            }
            _ => OperationEffect::Applied,
        };
        self.metric_grid_chain
            .entry(op.region)
            .or_insert_with(WriteChain::new)
            .record(env.id, env.transaction, op.grid.clone());
        self.graph_set_metric_grid(op.region, &op.grid);
        effect
    }

    fn graph_set_metric_grid(&mut self, region: RegionId, grid: &Option<MetricGrid>) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        if let Some(region) = score.canvas.regions.iter_mut().find(|r| r.id == region) {
            if let Some(content) = region.content.staff_based_mut() {
                content.default_metric_grid = grid.clone();
            }
        }
    }

    fn set_user_page_break(
        &mut self,
        env: &OperationEnvelope,
        op: &SetUserPageBreakOp,
    ) -> OperationEffect {
        if let Some(effect) = self.layout_region_slot(op.region) {
            return effect;
        }
        if let Some(score) = self.graph.as_mut() {
            if let Some(region) = score.canvas.regions.iter_mut().find(|r| r.id == op.region) {
                if let Some(content) = region.content.staff_based_mut() {
                    apply_break_lww(&mut content.user_page_breaks, &op.anchor, op.present);
                }
            }
        }
        let key = (op.region, op.resolved_position());
        self.page_breaks.insert(key.clone(), op.present);
        self.page_break_chain
            .entry(key)
            .or_insert_with(WriteChain::new)
            .record(env.id, env.transaction, (op.anchor.clone(), op.present));
        OperationEffect::Applied
    }

    fn insert_event(&mut self, env: &OperationEnvelope, op: &InsertEventOp) -> OperationEffect {
        // The reduction keys are read from the carried event value (v1).
        let event_id = op.event_id();
        let orig_voice = op.voice();
        let op_position = op.musical_position();
        let op_duration = op.musical_duration();
        if !op_duration.is_positive() {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::EventDurationInvalid,
                },
            };
        }
        let ev_obj = TypedObjectId::Event(event_id);
        match self.objects.get(&ev_obj) {
            Some(ObjectState::Live) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::AlreadyApplied,
                }
            }
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::TargetTombstoned,
                }
            }
            None => {}
        }
        let graph_location = match self.graph_insert_precondition(op) {
            Ok(location) => location,
            Err(reason) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction { reason },
                }
            }
        };
        // Pitch-id freshness in base-free reduction: a carried pitch id that
        // already exists in canonical state (live or tombstoned) is not fresh.
        // The graph-aware precondition above already enforces this (with the
        // same reason), so this only fires when no graph is present — it keeps
        // the two reduction APIs in agreement on the same operation set.
        if op
            .pitch_ids()
            .iter()
            .any(|pitch| self.objects.contains_key(&TypedObjectId::Pitch(*pitch)))
        {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetTombstoned,
                },
            };
        }
        let voice_obj = TypedObjectId::Voice(orig_voice);
        match self.objects.get(&voice_obj) {
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::VoiceMissing,
                    },
                }
            }
            Some(ObjectState::Live) => {}
            None => {
                // Implicit voice creation on first use (prototype convention).
                self.objects.insert(voice_obj, ObjectState::Live);
                self.minted_by.insert(voice_obj, env.id);
                // Track it under its staff instance for the container empty-check.
                self.instance_voices
                    .entry(op.staff_instance)
                    .or_default()
                    .insert(orig_voice);
            }
        }

        let promotion = self.promotion.get(&env.id).copied();
        let target_voice = promotion.map(|(voice, _)| voice).unwrap_or(orig_voice);
        if self
            .voice_occupancy
            .get(&target_voice)
            .is_some_and(|events| {
                events.iter().any(|(position, duration, _)| {
                    intervals_overlap(position, duration, &op_position, &op_duration)
                })
            })
        {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::EventDurationInvalid,
                },
            };
        }

        if let Err(reason) =
            self.materialize_graph_insert(env, op, graph_location, target_voice, promotion)
        {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction { reason },
            };
        }

        let mut repairs = Vec::new();
        if let Some((promoted, _)) = promotion {
            let pv = TypedObjectId::Voice(promoted);
            self.objects.entry(pv).or_insert(ObjectState::Live);
            self.minted_by.entry(pv).or_insert(env.id);
            self.note_minted(env, pv);
            repairs.push(RepairRecord {
                kind: RepairKind::VoicePromoted {
                    from: orig_voice,
                    to: promoted,
                },
                target: pv,
            });
        }

        self.objects.insert(ev_obj, ObjectState::Live);
        self.minted_by.insert(ev_obj, env.id);
        self.note_minted(env, ev_obj);
        // Seed the write chains with the minted values (the same value the
        // graph materializes), so a later modify's chain-predecessor is the
        // inserted state in graph-free and graph-aware reduction alike.
        self.event_modify_chain
            .entry(event_id)
            .or_insert_with(WriteChain::new)
            .seed(graph_event_from_insert(op, target_voice));
        let mut carried: Vec<&epiphany_core::IdentifiedPitch> = Vec::new();
        op.event.collect_identified_pitches(&mut carried);
        for ip in &carried {
            self.pitch_modify_chain
                .entry(ip.id)
                .or_insert_with(WriteChain::new)
                .seed(ip.pitch.clone());
        }
        let mut pitches = Vec::new();
        for p in op.pitch_ids() {
            let p_obj = TypedObjectId::Pitch(p);
            self.objects.insert(p_obj, ObjectState::Live);
            self.minted_by.insert(p_obj, env.id);
            self.note_minted(env, p_obj);
            pitches.push(p);
        }
        self.event_pitches.insert(event_id, pitches);
        self.voice_occupancy.entry(target_voice).or_default().push((
            op_position,
            op_duration,
            event_id,
        ));

        if repairs.is_empty() {
            OperationEffect::Applied
        } else {
            OperationEffect::AppliedWithRepair { repairs }
        }
    }

    fn delete_event(&mut self, env: &OperationEnvelope, op: &DeleteEventOp) -> OperationEffect {
        let ev_obj = TypedObjectId::Event(op.event);
        match self.objects.get(&ev_obj) {
            None => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::TargetMissing,
                    },
                }
            }
            Some(ObjectState::Tombstoned { .. }) => {
                // Concurrent same-target deletes are idempotent.
                return OperationEffect::NoOp {
                    reason: NoOpReason::AlreadyApplied,
                };
            }
            Some(ObjectState::Live) => {}
        }
        if let Err(reason) = self.graph_delete_precondition(op) {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction { reason },
            };
        }

        let deleted_placement = self.voice_occupancy.iter().find_map(|(voice, events)| {
            events
                .iter()
                .find(|(_, _, event)| *event == op.event)
                .map(|(position, duration, _)| (*voice, position.clone(), duration.clone()))
        });
        // The tombstoned referent's voice, for the containment-proximity key of
        // the re-anchoring reasons below: the occupancy index (base-free) with
        // the graph as fallback for non-metric events. Captured before the
        // graph delete removes the event.
        let referent_voice = deleted_placement
            .as_ref()
            .map(|(voice, _, _)| *voice)
            .or_else(|| {
                self.graph
                    .as_ref()
                    .and_then(|score| score.events.get(op.event))
                    .map(Event::voice)
            });
        // Tombstone the event in `objects` BEFORE the graph delete (P13-D2).
        // `materialize_graph_delete` re-anchors the deleted event's referents,
        // and a cue among them cascades — running `reanchor_for_tombstone` over
        // the cue's own referents. A structure anchored on {this event,
        // cue-of-this-event} must see this event as already dead there, or it
        // would re-anchor onto it (recording `Reanchored{to: X}`) only to
        // cascade when X's tombstone lands a line later — a contradictory
        // same-effect trail. Tombstoning first matches `cascade_cue` and the
        // undo path, which already tombstone before their graph delete.
        let minter = self.minted_by.get(&ev_obj).copied().unwrap_or(env.id);
        self.objects.insert(
            ev_obj,
            ObjectState::Tombstoned {
                deleted_by: env.id,
                minted_by: minter,
            },
        );
        let graph_repairs = self.materialize_graph_delete(env, op);
        for events in self.voice_occupancy.values_mut() {
            events.retain(|(_, _, event)| *event != op.event);
        }
        self.voice_occupancy.retain(|_, events| !events.is_empty());
        let mut repairs = graph_repairs;

        // Tombstone contained pitches.
        if let Some(pitches) = self.event_pitches.get(&op.event).cloned() {
            for p in pitches {
                let p_obj = TypedObjectId::Pitch(p);
                let pm = self.minted_by.get(&p_obj).copied().unwrap_or(env.id);
                self.objects.insert(
                    p_obj,
                    ObjectState::Tombstoned {
                        deleted_by: env.id,
                        minted_by: pm,
                    },
                );
            }
        }

        // Tuplet compensation.
        match &op.tuplet_compensation {
            TupletCompensation::NotInTuplet => {}
            TupletCompensation::ReplaceWithRest { rest } => {
                let new_rest = rest.id;
                let rest_duration = match &rest.duration {
                    EventDuration::Musical(d) => d.clone(),
                    EventDuration::WallClock(_) | EventDuration::Indeterminate(_) => {
                        MusicalDuration::zero()
                    }
                };
                let rest_obj = TypedObjectId::Event(new_rest);
                self.objects.insert(rest_obj, ObjectState::Live);
                self.minted_by.insert(rest_obj, env.id);
                self.note_minted(env, rest_obj);
                self.event_pitches.insert(new_rest, Vec::new());
                if let Some((voice, position, _)) = &deleted_placement {
                    self.voice_occupancy.entry(*voice).or_default().push((
                        position.clone(),
                        rest_duration,
                        new_rest,
                    ));
                }
                repairs.push(RepairRecord {
                    kind: RepairKind::TupletCompensated {
                        compensation_kind: TupletCompensationKind::ReplaceWithRest,
                    },
                    target: rest_obj,
                });
            }
            TupletCompensation::RewriteTuplets { tuplets } => {
                if let Some(first) = tuplets.first() {
                    repairs.push(RepairRecord {
                        kind: RepairKind::TupletCompensated {
                            compensation_kind: TupletCompensationKind::RewriteTuplets,
                        },
                        target: TypedObjectId::Tuplet(*first),
                    });
                }
            }
            TupletCompensation::CascadeDeleteTuplets { tuplets } => {
                for t in tuplets {
                    let t_obj = TypedObjectId::Tuplet(*t);
                    let tm = self.minted_by.get(&t_obj).copied().unwrap_or(env.id);
                    self.objects.insert(
                        t_obj,
                        ObjectState::Tombstoned {
                            deleted_by: env.id,
                            minted_by: tm,
                        },
                    );
                    repairs.push(RepairRecord {
                        kind: RepairKind::TupletCompensated {
                            compensation_kind: TupletCompensationKind::CascadeDeleteTuplets,
                        },
                        target: t_obj,
                    });
                }
            }
        }

        // Re-anchor cross-cutting structures referencing the tombstoned event.
        self.reanchor_for_tombstone(env, ev_obj, &mut repairs, referent_voice);

        if repairs.is_empty() {
            OperationEffect::Applied
        } else {
            OperationEffect::AppliedWithRepair { repairs }
        }
    }

    fn respell_pitch(&mut self, env: &OperationEnvelope, op: &RespellPitchOp) -> OperationEffect {
        let p_obj = TypedObjectId::Pitch(op.pitch);
        match self.objects.get(&p_obj) {
            None => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::TargetMissing,
                    },
                }
            }
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::TargetTombstoned,
                }
            }
            Some(ObjectState::Live) => {}
        }

        let prev_op = self
            .respell_chain
            .get(&op.pitch)
            .and_then(|chain| chain.last_write())
            .map(|write| write.op);
        match prev_op {
            None => {
                self.materialize_respell(env, op);
                OperationEffect::Applied
            }
            Some(prev_op) => {
                let prev_spelling = self.spellings.get(&op.pitch).cloned();
                let concurrent = self.concurrent(env.id, prev_op);
                if concurrent {
                    if prev_spelling.as_ref() == Some(&op.spelling) {
                        // Identical concurrent respelling: idempotent.
                        OperationEffect::NoOp {
                            reason: NoOpReason::AlreadyApplied,
                        }
                    } else {
                        // Differing concurrent respelling: this op is later in
                        // canonical order, so it wins and materializes; the
                        // earlier op is recorded as the loser. (Prototype
                        // convention: the winner carries the Conflicted effect;
                        // see DECISIONS.md.)
                        self.materialize_respell(env, op);
                        let conflict = ConflictRecord::new(
                            ConflictKind::StructuralFieldCollision {
                                winner: env.id,
                                loser: prev_op,
                                field: FieldPath("spelling".to_string()),
                            },
                            vec![env.id, prev_op],
                            vec![p_obj],
                        );
                        let cid = conflict.id;
                        self.conflicts.insert(conflict);
                        OperationEffect::Conflicted { conflict: cid }
                    }
                } else {
                    // Causally-ordered re-respell: intentional overwrite.
                    self.materialize_respell(env, op);
                    OperationEffect::Applied
                }
            }
        }
    }

    /// Records a winning respell: the canonical bookkeeping spelling, the LWW
    /// marker, and — for graph-aware reduction — an explicit user-chosen
    /// [`SpellingAttachment`] so the spelling/decomposition pre-passes (Agent H's
    /// `derive_annotations`) resolve the override with manual-override precedence.
    /// Without the graph attachment a reduced `RespellPitch` would be visible only
    /// in `MaterializedState.spellings` and lost before annotation derivation.
    fn materialize_respell(&mut self, env: &OperationEnvelope, op: &RespellPitchOp) {
        self.spellings.insert(op.pitch, op.spelling.clone());
        self.respell_chain
            .entry(op.pitch)
            .or_insert_with(WriteChain::new)
            .record(env.id, env.transaction, op.spelling.clone());
        self.graph_respell_pitch(op.pitch, &op.spelling);
        // A respell changes the graph attachment set, so it is a writer on
        // `engraved_spelling_chain` too (P13-S3). Without this, a transpose
        // undone after a respell would erase it, and a respell landing after a
        // transposed transaction would be silently wiped by that undo instead
        // of superseding it.
        self.record_engraved_spellings(env, op.pitch);
    }

    /// Records `pitch`'s current graph attachment set as a write on
    /// [`Self::engraved_spelling_chain`]. A no-op under base-free reduction,
    /// which has no graph attachments to own — so base-free canonical bytes do
    /// not move.
    fn record_engraved_spellings(&mut self, env: &OperationEnvelope, pitch: PitchId) {
        if self.graph.is_none() {
            return;
        }
        let set = self.graph_spelling_set(pitch);
        self.engraved_spelling_chain
            .entry(pitch)
            .or_insert_with(WriteChain::new)
            .record(env.id, env.transaction, set);
    }

    fn graph_respell_pitch(&mut self, pitch: PitchId, spelling: &PitchSpelling) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        // Upsert the user-chosen explicit override (one per pitch), keeping the
        // attachment list's canonical order stable for the resolver's tie-break.
        if let Some(existing) = score.spelling_attachments.iter_mut().find(|a| {
            a.layer.is_none()
                && matches!(a.source, SpellingSource::UserChosen)
                && matches!(&a.scope, SpellingScope::Pitch(p) if *p == pitch)
                && matches!(a.directive, SpellingDirective::Explicit(_))
        }) {
            existing.directive = SpellingDirective::Explicit(spelling.clone());
        } else {
            score.spelling_attachments.push(SpellingAttachment {
                scope: SpellingScope::Pitch(pitch),
                directive: SpellingDirective::Explicit(spelling.clone()),
                source: SpellingSource::UserChosen,
                priority: 0,
                layer: None,
            });
        }
    }

    fn create_cross_cutting(
        &mut self,
        env: &OperationEnvelope,
        op: &CreateCrossCuttingOp,
    ) -> OperationEffect {
        let sid = op.structure.id();
        let endpoints = op.structure.endpoints();
        match self.objects.get(&sid) {
            Some(ObjectState::Live) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::AlreadyApplied,
                }
            }
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::TargetTombstoned,
                }
            }
            None => {}
        }
        // Every anchored object must exist (live) — events for the
        // event-anchored kinds, and a spanner's region/measure anchor targets
        // too, so a spanner anchored to a missing region/measure is rejected
        // rather than minted dangling (P13-D3). Deterministic across both
        // reduction modes: the base seed registers regions and measures in
        // `objects` (as the repeat mint precondition relies on).
        for e in &op.structure.anchor_object_refs() {
            if !matches!(self.objects.get(e), Some(ObjectState::Live)) {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::TargetMissing,
                    },
                };
            }
        }
        if let Err(reason) = self.materialize_graph_cross_cutting(op) {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction { reason },
            };
        }
        self.objects.insert(sid, ObjectState::Live);
        self.minted_by.insert(sid, env.id);
        self.note_minted(env, sid);
        // Seed the write chain with the minted value, so a later modify's
        // chain-predecessor is the created state.
        self.cross_cutting_modify_chain
            .entry(sid)
            .or_insert_with(WriteChain::new)
            .seed(op.structure.clone());
        self.structures.insert(sid, endpoints);
        OperationEffect::Applied
    }

    fn delete_cross_cutting(
        &mut self,
        env: &OperationEnvelope,
        op: &DeleteCrossCuttingOp,
    ) -> OperationEffect {
        let sid = op.structure;
        // DeleteCrossCutting names a cross-cutting structure only; refuse to
        // tombstone any other object kind through this path.
        if !matches!(
            sid,
            TypedObjectId::Tie(_)
                | TypedObjectId::Slur(_)
                | TypedObjectId::Beam(_)
                | TypedObjectId::Spanner(_)
        ) {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetMissing,
                },
            };
        }
        let minted_by = match self.objects.get(&sid) {
            None => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::TargetMissing,
                    },
                }
            }
            // Concurrent same-target deletes are idempotent (delete-wins).
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::AlreadyApplied,
                }
            }
            Some(ObjectState::Live) => self.minted_by.get(&sid).copied().unwrap_or(env.id),
        };
        self.objects.insert(
            sid,
            ObjectState::Tombstoned {
                deleted_by: env.id,
                minted_by,
            },
        );
        // Drop the transient endpoint/LWW indices so a later event tombstone's
        // re-anchoring pass never re-processes the deleted structure. The write
        // chain goes with it: a delete is not inverted (P11-C8), so a
        // tombstoned structure's chain can never be restored.
        self.structures.remove(&sid);
        self.cross_cutting_modify_chain.remove(&sid);
        self.graph_delete_cross_cutting(sid);
        OperationEffect::Applied
    }

    fn create_repeat_structure(
        &mut self,
        env: &OperationEnvelope,
        op: &CreateRepeatStructureOp,
    ) -> OperationEffect {
        let sid = TypedObjectId::RepeatStructure(op.repeat.id);
        match self.objects.get(&sid) {
            // Set-union: a repeat create of a live id reads AlreadyApplied
            // without value comparison (the cross-cutting discipline; the
            // RecreateContentMismatch scope stays CreateStaff + carried
            // TimeSignature).
            Some(ObjectState::Live) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::AlreadyApplied,
                }
            }
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::TargetTombstoned,
                }
            }
            None => {}
        }
        // Every OBJECT-referencing anchor site must resolve live — start/end,
        // the kind's jump targets, each volta's span; events, measures, AND
        // regions (operation_catalog §"Repeat Structures": the mint must
        // leave the graph satisfying the reference-resolution invariants,
        // which check all three anchor kinds — an event-only check would
        // mint a dangling repeat off a missing region/measure anchor).
        for referenced in anchor_object_refs(op.repeat.anchor_sites()) {
            if !matches!(self.objects.get(&referenced), Some(ObjectState::Live)) {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::TargetMissing,
                    },
                };
            }
        }
        if let Some(score) = self.graph.as_mut() {
            score.cross_cutting.repeats.push(op.repeat.clone());
        }
        self.objects.insert(sid, ObjectState::Live);
        self.minted_by.insert(sid, env.id);
        self.note_minted(env, sid);
        // Register the EVENT refs into the referent index so event tombstones
        // repair the structure per the rule table (no write chain: there is
        // no ModifyRepeatStructure at this revision). Measure/region anchors
        // stay unindexed, as for spanners — non-event referent tombstones
        // are the filed P13-D3 class.
        let endpoints = anchor_event_refs(op.repeat.anchor_sites());
        if !endpoints.is_empty() {
            self.structures.insert(sid, endpoints);
        }
        // Genesis tranche G3b (contract pin 10.4): carry the value so the
        // strand guard's repeat surface can read `anchor_sites()` — there is
        // no write chain a repeat could be recorded into.
        self.repeat_values.insert(op.repeat.id, op.repeat.clone());
        OperationEffect::Applied
    }

    fn delete_repeat_structure(
        &mut self,
        env: &OperationEnvelope,
        op: &DeleteRepeatStructureOp,
    ) -> OperationEffect {
        let sid = TypedObjectId::RepeatStructure(op.repeat);
        let minted_by = match self.objects.get(&sid) {
            None => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::TargetMissing,
                    },
                }
            }
            // Concurrent same-target deletes are idempotent (delete-wins).
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::AlreadyApplied,
                }
            }
            Some(ObjectState::Live) => self.minted_by.get(&sid).copied().unwrap_or(env.id),
        };
        self.objects.insert(
            sid,
            ObjectState::Tombstoned {
                deleted_by: env.id,
                minted_by,
            },
        );
        // Drop the referent-index entry so a later event tombstone's
        // re-anchoring pass never re-processes the deleted structure.
        self.structures.remove(&sid);
        if let Some(score) = self.graph.as_mut() {
            score.cross_cutting.repeats.retain(|r| r.id != op.repeat);
        }
        OperationEffect::Applied
    }

    fn modify_cross_cutting(
        &mut self,
        env: &OperationEnvelope,
        op: &ModifyCrossCuttingOp,
    ) -> OperationEffect {
        let sid = op.id();
        match self.objects.get(&sid) {
            None => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::TargetMissing,
                    },
                }
            }
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::TargetTombstoned,
                }
            }
            Some(ObjectState::Live) => {}
        }
        // A beam must keep at least two events (mirrors CreateCrossCutting); the
        // new endpoints must all be live.
        if let CrossCuttingValue::Beam(beam) = &op.structure {
            if beam.events.len() < 2 {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::TargetMissing,
                    },
                };
            }
        }
        // Every anchored object of the NEW value must be live — events for the
        // event-anchored kinds, and a spanner's region/measure anchor targets
        // too (P13-D3, modify sibling): otherwise a live event-anchored spanner
        // could be modified onto a missing region/measure — whose empty
        // `endpoints()` slipped the check — and written into the graph past the
        // core invariant that validates spanner anchors at all three kinds.
        // Mirrors `create_cross_cutting`; `endpoints()` still feeds the
        // event-only referent index below.
        let endpoints = op.structure.endpoints();
        for e in &op.structure.anchor_object_refs() {
            if !matches!(self.objects.get(e), Some(ObjectState::Live)) {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::TargetMissing,
                    },
                };
            }
        }
        // LWW field-overwrite, mirroring modify_event: the resolved value lives in
        // the graph; MaterializedState records only the effect and, on a
        // concurrent differing write, a StructuralFieldCollision.
        let prev = self
            .cross_cutting_modify_chain
            .get(&sid)
            .and_then(|chain| chain.last_write())
            .map(|write| (write.op, write.value.clone()));
        let effect = match prev {
            Some((prev_op, prev_value)) if self.concurrent(env.id, prev_op) => {
                if prev_value == op.structure {
                    return OperationEffect::NoOp {
                        reason: NoOpReason::AlreadyApplied,
                    };
                }
                let conflict = ConflictRecord::new(
                    ConflictKind::StructuralFieldCollision {
                        winner: env.id,
                        loser: prev_op,
                        field: FieldPath("cross_cutting".to_string()),
                    },
                    vec![env.id, prev_op],
                    vec![sid],
                );
                let cid = conflict.id;
                self.conflicts.insert(conflict);
                OperationEffect::Conflicted { conflict: cid }
            }
            _ => OperationEffect::Applied,
        };
        self.cross_cutting_modify_chain
            .entry(sid)
            .or_insert_with(WriteChain::new)
            .record(env.id, env.transaction, op.structure.clone());
        self.structures.insert(sid, endpoints);
        self.graph_modify_cross_cutting(&op.structure);
        effect
    }

    fn graph_delete_cross_cutting(&mut self, sid: TypedObjectId) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        match sid {
            TypedObjectId::Slur(id) => score.cross_cutting.slurs.retain(|v| v.id != id),
            TypedObjectId::Tie(id) => score.cross_cutting.ties.retain(|v| v.id != id),
            TypedObjectId::Beam(id) => score.cross_cutting.beams.retain(|v| v.id != id),
            TypedObjectId::Spanner(id) => score.cross_cutting.spanners.retain(|v| v.id != id),
            _ => {}
        }
    }

    fn graph_modify_cross_cutting(&mut self, value: &CrossCuttingValue) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        // Replace the structure in place by id (identity is preserved across a
        // modify). A structure that is Live in bookkeeping but absent from the
        // graph (e.g. one a DeleteEvent re-anchor removed from the graph while
        // bookkeeping kept it Live) is left as-is; the modify is still recorded.
        match value {
            CrossCuttingValue::Slur(slur) => {
                if let Some(existing) = score
                    .cross_cutting
                    .slurs
                    .iter_mut()
                    .find(|v| v.id == slur.id)
                {
                    *existing = slur.clone();
                }
            }
            CrossCuttingValue::Tie(tie) => {
                if let Some(existing) = score.cross_cutting.ties.iter_mut().find(|v| v.id == tie.id)
                {
                    *existing = tie.clone();
                }
            }
            CrossCuttingValue::Beam(beam) => {
                if let Some(existing) = score
                    .cross_cutting
                    .beams
                    .iter_mut()
                    .find(|v| v.id == beam.id)
                {
                    *existing = beam.clone();
                }
            }
            CrossCuttingValue::Spanner(spanner) => {
                if let Some(existing) = score
                    .cross_cutting
                    .spanners
                    .iter_mut()
                    .find(|v| v.id == spanner.id)
                {
                    *existing = spanner.clone();
                }
            }
        }
    }

    // --- Group 3 (M2c): structural container CRUD. -------------------------
    //
    // Creates mint an empty container (set-union creation; the authoring contract
    // is that the carried value is empty, so only its own object is minted).
    // Deletes are empty-only delete-wins: a precondition NoOp unless the
    // container has no live children. Child liveness is read from
    // `region_instances` / `instance_voices` (and `voice_occupancy` for a voice's
    // events), so the ledger projection and the graph agree on the result.

    fn mint_container(&mut self, env: &OperationEnvelope, obj: TypedObjectId) {
        self.objects.insert(obj, ObjectState::Live);
        self.minted_by.insert(obj, env.id);
        self.note_minted(env, obj);
    }

    /// `Some(effect)` when `obj` cannot be freshly minted (already live or
    /// tombstoned); `None` when it is fresh and the create may proceed.
    fn mint_precondition(&self, obj: TypedObjectId) -> Option<OperationEffect> {
        match self.objects.get(&obj) {
            Some(ObjectState::Live) => Some(OperationEffect::NoOp {
                reason: NoOpReason::AlreadyApplied,
            }),
            Some(ObjectState::Tombstoned { .. }) => Some(OperationEffect::NoOp {
                reason: NoOpReason::TargetTombstoned,
            }),
            None => None,
        }
    }

    fn create_region(&mut self, env: &OperationEnvelope, op: &CreateRegionOp) -> OperationEffect {
        let robj = TypedObjectId::Region(op.region_id());
        if let Some(effect) = self.mint_precondition(robj) {
            return effect;
        }
        // A create mints an *empty* container: its child objects are minted (or
        // base-seeded) separately. A carried value bearing any typed child object
        // — a staff instance, a barline-alignment group, or a graphic object, each
        // a distinct TypedObjectId the reducer does not mint here — would import an
        // unminted object into the graph, so it is rejected (Catalog §Structural
        // Containers).
        if !op.region.content.staff_instances().is_empty()
            || !op.region.content.barline_alignment_groups().is_empty()
            || !op.region.content.graphic_objects().is_empty()
        {
            return container_not_empty();
        }
        self.graph_create_region(&op.region);
        self.mint_container(env, robj);
        self.region_instances.entry(op.region_id()).or_default();
        if let Some(content) = op.region.content.staff_based() {
            self.staff_based_regions.insert(op.region_id());
            // Seed the region's layout/metric write chains from the carried
            // content (empty of typed children, but it may carry a grid or
            // break advisories), so a later overwrite's chain-predecessor is
            // the created state.
            self.metric_grid_chain
                .entry(op.region_id())
                .or_insert_with(WriteChain::new)
                .seed(content.default_metric_grid.clone());
            if let Some(grid) = &content.default_metric_grid {
                for change in &grid.meter_sequence {
                    self.meter_change_chain
                        .entry((op.region_id(), resolved_anchor_position(&change.anchor)))
                        .or_insert_with(WriteChain::new)
                        .seed(Some(change.clone()));
                }
            }
            for anchor in &content.user_system_breaks {
                self.break_chain
                    .entry((op.region_id(), resolved_anchor_position(anchor)))
                    .or_insert_with(WriteChain::new)
                    .seed((anchor.clone(), true));
            }
            for anchor in &content.user_page_breaks {
                self.page_break_chain
                    .entry((op.region_id(), resolved_anchor_position(anchor)))
                    .or_insert_with(WriteChain::new)
                    .seed((anchor.clone(), true));
            }
        }
        if let Some(local) = &op.region.local_tempo_map {
            for segment in &local.segments {
                self.tempo_segment_chain
                    .entry((
                        Some(op.region_id()),
                        resolved_anchor_position(&segment.start),
                    ))
                    .or_insert_with(WriteChain::new)
                    .seed(Some(segment.clone()));
            }
        }
        OperationEffect::Applied
    }

    fn create_staff_instance(
        &mut self,
        env: &OperationEnvelope,
        op: &CreateStaffInstanceOp,
    ) -> OperationEffect {
        if !matches!(
            self.objects.get(&TypedObjectId::Region(op.region)),
            Some(ObjectState::Live)
        ) {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetMissing,
                },
            };
        }
        let iobj = TypedObjectId::StaffInstance(op.instance_id());
        if let Some(effect) = self.mint_precondition(iobj) {
            return effect;
        }
        // Reject a carried staff instance bearing any typed child object — a voice
        // or a measure (the two object collections it can hold).
        if !op.instance.voices.is_empty() || !op.instance.measures.is_empty() {
            return container_not_empty();
        }
        // With staves mintable (operation_catalog §CreateStaff), the instance's
        // referenced global Staff must be live — the mint must leave the graph
        // satisfying reference resolution. Graph-aware only (like the insert
        // preconditions): base-free reduction has no staff universe to check
        // against, and the base-seeded scenarios satisfy this vacuously.
        if self.graph.is_some()
            && !matches!(
                self.objects.get(&TypedObjectId::Staff(op.instance.staff)),
                Some(ObjectState::Live)
            )
        {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetMissing,
                },
            };
        }
        self.graph_create_staff_instance(op.region, &op.instance);
        self.mint_container(env, iobj);
        self.region_instances
            .entry(op.region)
            .or_default()
            .insert(op.instance_id());
        self.instance_voices.entry(op.instance_id()).or_default();
        self.instance_staff
            .insert(op.instance_id(), op.instance.staff);
        // Genesis tranche G3b (contract pin 6c, disposition A): record the
        // minted instance's local grid override (or its absence) — this is
        // the ONLY site that ever writes `local_metric_grid`, so the ledger's
        // single write happens here.
        self.instance_grid
            .insert(op.instance_id(), op.instance.local_metric_grid.clone());
        // Seed the layout-advisory chain with the minted instance's fields, so
        // a later SetStaffLayout's chain-predecessor is the created state.
        self.staff_layout_chain
            .entry(op.instance_id())
            .or_insert_with(WriteChain::new)
            .seed((
                op.instance.instrument_override,
                op.instance.staff_lines_override.clone(),
                op.instance.visible,
            ));
        OperationEffect::Applied
    }

    fn create_voice(&mut self, env: &OperationEnvelope, op: &CreateVoiceOp) -> OperationEffect {
        if !matches!(
            self.objects
                .get(&TypedObjectId::StaffInstance(op.staff_instance)),
            Some(ObjectState::Live)
        ) {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetMissing,
                },
            };
        }
        let vobj = TypedObjectId::Voice(op.voice_id());
        if let Some(effect) = self.mint_precondition(vobj) {
            return effect;
        }
        if !op.voice.events.is_empty() {
            return container_not_empty();
        }
        self.graph_create_voice(op.staff_instance, &op.voice);
        self.mint_container(env, vobj);
        self.instance_voices
            .entry(op.staff_instance)
            .or_default()
            .insert(op.voice_id());
        OperationEffect::Applied
    }

    // --- Phase-3 first tranche (operation_catalog §CreateStaff, §"Meter and
    // Tempo Overwrites", §SetStaffLayout). ------------------------------------

    /// Set-union creation of a global `Staff` on the score root
    /// (operation_catalog §CreateStaff): fresh id mints; a byte-identical
    /// re-carry is idempotent; a differing value under a live id is a
    /// precondition no-op. Graph-aware reduction additionally preconditions
    /// that the referenced instrument is live and, when `group` is present,
    /// that the staff group resolves.
    fn create_staff(&mut self, env: &OperationEnvelope, op: &CreateStaffOp) -> OperationEffect {
        let sobj = TypedObjectId::Staff(op.staff_id());
        match self.objects.get(&sobj) {
            Some(ObjectState::Live) => {
                let identical = self
                    .staff_values
                    .get(&op.staff_id())
                    .is_some_and(|known| known == &op.staff);
                return if identical {
                    OperationEffect::NoOp {
                        reason: NoOpReason::AlreadyApplied,
                    }
                } else {
                    OperationEffect::NoOp {
                        reason: NoOpReason::PreconditionFailedUnderReduction {
                            reason: PreconditionFailureReason::RecreateContentMismatch,
                        },
                    }
                };
            }
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::TargetTombstoned,
                }
            }
            None => {}
        }
        // Reference-resolution preconditions are graph-aware (like the insert
        // preconditions): base-free reduction has no instrument/group universe
        // to check against.
        if self.graph.is_some() {
            if !matches!(
                self.objects
                    .get(&TypedObjectId::Instrument(op.staff.instrument)),
                Some(ObjectState::Live)
            ) {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::TargetMissing,
                    },
                };
            }
            if let Some(group) = op.staff.group {
                if !matches!(
                    self.objects.get(&TypedObjectId::StaffGroup(group)),
                    Some(ObjectState::Live)
                ) {
                    return OperationEffect::NoOp {
                        reason: NoOpReason::PreconditionFailedUnderReduction {
                            reason: PreconditionFailureReason::TargetMissing,
                        },
                    };
                }
            }
        }
        if let Some(score) = self.graph.as_mut() {
            score.staves.push(op.staff.clone());
        }
        self.mint_container(env, sobj);
        self.staff_values.insert(op.staff_id(), op.staff.clone());
        OperationEffect::Applied
    }

    // --- Genesis tranche G1 (`spec/CONTRACT_GENESIS_G1_INSTRUMENT.md`). -------

    /// Set-union creation of an `Instrument` on the score root
    /// (operation_catalog §CreateInstrument): fresh id mints; a
    /// byte-identical re-carry is idempotent; a differing value under a live
    /// id is a precondition no-op — exactly `create_staff`'s discipline
    /// (contract pin 6). Unlike `create_staff`, there is no graph-aware
    /// reference-resolution block: `Instrument` holds no outbound entity
    /// references (contract preamble), so this operation needs no referential
    /// preconditions at all.
    fn create_instrument(
        &mut self,
        env: &OperationEnvelope,
        op: &CreateInstrumentOp,
    ) -> OperationEffect {
        let iobj = TypedObjectId::Instrument(op.instrument_id());
        match self.objects.get(&iobj) {
            Some(ObjectState::Live) => {
                let identical = self
                    .instrument_values
                    .get(&op.instrument_id())
                    .is_some_and(|known| known == &op.instrument);
                return if identical {
                    OperationEffect::NoOp {
                        reason: NoOpReason::AlreadyApplied,
                    }
                } else {
                    OperationEffect::NoOp {
                        reason: NoOpReason::PreconditionFailedUnderReduction {
                            reason: PreconditionFailureReason::RecreateContentMismatch,
                        },
                    }
                };
            }
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::TargetTombstoned,
                }
            }
            None => {}
        }
        if let Some(score) = self.graph.as_mut() {
            score.instruments.push(op.instrument.clone());
        }
        self.mint_container(env, iobj);
        self.instrument_values
            .insert(op.instrument_id(), op.instrument.clone());
        OperationEffect::Applied
    }

    // --- Genesis tranche G3a (`spec/CONTRACT_GENESIS_G3A_ENTITIES.md`): the
    // four remaining root-level `Score` entity mints. All four ride
    // `create_staff`'s set-union mint discipline exactly (contract pin 4):
    // fresh id mints; byte-identical re-carry is idempotent; a differing
    // value under a live id is a precondition no-op
    // (`RecreateContentMismatch`); a tombstoned id is `TargetTombstoned`.
    // Referential preconditions are graph-aware only — base-free reduction
    // has no universe to check against. -------------------------------------

    /// Set-union creation of a global `StaffGroup` on the score root
    /// (operation_catalog §CreateStaffGroup). Graph-aware reduction
    /// preconditions every carried member resolves to a live `Staff`. Per
    /// §1.1 (disposition B), `members` is stored exactly as carried and
    /// neither maintained nor trusted thereafter — `Staff.group` is the sole
    /// authority for membership.
    fn create_staff_group(
        &mut self,
        env: &OperationEnvelope,
        op: &CreateStaffGroupOp,
    ) -> OperationEffect {
        let gobj = TypedObjectId::StaffGroup(op.staff_group_id());
        match self.objects.get(&gobj) {
            Some(ObjectState::Live) => {
                let identical = self
                    .staff_group_values
                    .get(&op.staff_group_id())
                    .is_some_and(|known| known == &op.group);
                return if identical {
                    OperationEffect::NoOp {
                        reason: NoOpReason::AlreadyApplied,
                    }
                } else {
                    OperationEffect::NoOp {
                        reason: NoOpReason::PreconditionFailedUnderReduction {
                            reason: PreconditionFailureReason::RecreateContentMismatch,
                        },
                    }
                };
            }
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::TargetTombstoned,
                }
            }
            None => {}
        }
        if self.graph.is_some() {
            for member in &op.group.members {
                if !matches!(
                    self.objects.get(&TypedObjectId::Staff(*member)),
                    Some(ObjectState::Live)
                ) {
                    return OperationEffect::NoOp {
                        reason: NoOpReason::PreconditionFailedUnderReduction {
                            reason: PreconditionFailureReason::TargetMissing,
                        },
                    };
                }
            }
        }
        if let Some(score) = self.graph.as_mut() {
            score.staff_groups.push(op.group.clone());
        }
        self.mint_container(env, gobj);
        self.staff_group_values
            .insert(op.staff_group_id(), op.group.clone());
        OperationEffect::Applied
    }

    /// Set-union creation of a `PartDefinition` on the score root
    /// (operation_catalog §CreatePartDefinition). Graph-aware reduction
    /// preconditions every carried staff resolves to a live `Staff`.
    fn create_part_definition(
        &mut self,
        env: &OperationEnvelope,
        op: &CreatePartDefinitionOp,
    ) -> OperationEffect {
        let pobj = TypedObjectId::PartDefinition(op.part_definition_id());
        match self.objects.get(&pobj) {
            Some(ObjectState::Live) => {
                let identical = self
                    .part_definition_values
                    .get(&op.part_definition_id())
                    .is_some_and(|known| known == &op.part);
                return if identical {
                    OperationEffect::NoOp {
                        reason: NoOpReason::AlreadyApplied,
                    }
                } else {
                    OperationEffect::NoOp {
                        reason: NoOpReason::PreconditionFailedUnderReduction {
                            reason: PreconditionFailureReason::RecreateContentMismatch,
                        },
                    }
                };
            }
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::TargetTombstoned,
                }
            }
            None => {}
        }
        if self.graph.is_some() {
            for staff in &op.part.staves {
                if !matches!(
                    self.objects.get(&TypedObjectId::Staff(*staff)),
                    Some(ObjectState::Live)
                ) {
                    return OperationEffect::NoOp {
                        reason: NoOpReason::PreconditionFailedUnderReduction {
                            reason: PreconditionFailureReason::TargetMissing,
                        },
                    };
                }
            }
        }
        if let Some(score) = self.graph.as_mut() {
            score.parts.push(op.part.clone());
        }
        self.mint_container(env, pobj);
        self.part_definition_values
            .insert(op.part_definition_id(), op.part.clone());
        OperationEffect::Applied
    }

    /// Set-union creation of an `AnalysisLayer` on the score root
    /// (operation_catalog §CreateAnalysisLayer). `AnalysisLayer` holds no
    /// outbound entity reference, so — exactly like `CreateInstrument` —
    /// there is no graph-aware reference-resolution block.
    fn create_analysis_layer(
        &mut self,
        env: &OperationEnvelope,
        op: &CreateAnalysisLayerOp,
    ) -> OperationEffect {
        let lobj = TypedObjectId::AnalysisLayer(op.analysis_layer_id());
        match self.objects.get(&lobj) {
            Some(ObjectState::Live) => {
                let identical = self
                    .analysis_layer_values
                    .get(&op.analysis_layer_id())
                    .is_some_and(|known| known == &op.layer);
                return if identical {
                    OperationEffect::NoOp {
                        reason: NoOpReason::AlreadyApplied,
                    }
                } else {
                    OperationEffect::NoOp {
                        reason: NoOpReason::PreconditionFailedUnderReduction {
                            reason: PreconditionFailureReason::RecreateContentMismatch,
                        },
                    }
                };
            }
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::TargetTombstoned,
                }
            }
            None => {}
        }
        if let Some(score) = self.graph.as_mut() {
            score.analysis_layers.push(op.layer.clone());
        }
        self.mint_container(env, lobj);
        self.analysis_layer_values
            .insert(op.analysis_layer_id(), op.layer.clone());
        OperationEffect::Applied
    }

    /// Set-union creation of a `ViewDefinition` on the score root
    /// (operation_catalog §CreateView). Graph-aware reduction preconditions
    /// every carried active layer resolves to a live `AnalysisLayer`.
    fn create_view(&mut self, env: &OperationEnvelope, op: &CreateViewOp) -> OperationEffect {
        let vobj = TypedObjectId::View(op.view_id());
        match self.objects.get(&vobj) {
            Some(ObjectState::Live) => {
                let identical = self
                    .view_values
                    .get(&op.view_id())
                    .is_some_and(|known| known == &op.view);
                return if identical {
                    OperationEffect::NoOp {
                        reason: NoOpReason::AlreadyApplied,
                    }
                } else {
                    OperationEffect::NoOp {
                        reason: NoOpReason::PreconditionFailedUnderReduction {
                            reason: PreconditionFailureReason::RecreateContentMismatch,
                        },
                    }
                };
            }
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::TargetTombstoned,
                }
            }
            None => {}
        }
        if self.graph.is_some() {
            for layer in &op.view.active_layers {
                if !matches!(
                    self.objects.get(&TypedObjectId::AnalysisLayer(*layer)),
                    Some(ObjectState::Live)
                ) {
                    return OperationEffect::NoOp {
                        reason: NoOpReason::PreconditionFailedUnderReduction {
                            reason: PreconditionFailureReason::TargetMissing,
                        },
                    };
                }
            }
        }
        if let Some(score) = self.graph.as_mut() {
            score.views.push(op.view.clone());
        }
        self.mint_container(env, vobj);
        self.view_values.insert(op.view_id(), op.view.clone());
        OperationEffect::Applied
    }

    // --- Genesis tranche G3b (`spec/CONTRACT_GENESIS_G3B_MEASURE.md`): the
    // final rung of the genesis ladder. `Measure` is a nested container
    // child, so `create_measure` rides `CreateStaffInstance`'s parent-
    // carrying mint shape (contract pin 4), not the nine root-level mints'
    // bare-value shape above. The predicates below (pins 6/6b/6c) are shared,
    // reusable functions — graph invariant 20 (packet 2) reuses every one of
    // them; nothing here is inlined into `create_measure`. ---------------

    /// The region enclosing `instance`, from reducer state alone (never
    /// `self.graph`) — so it resolves identically in graph-aware and
    /// base-free reduction (contract pin 6c, M30b): `region_instances` is
    /// maintained in both modes (by `create_region`/`create_staff_instance`
    /// and by `seed_from_graph`).
    fn region_of_instance(&self, instance: StaffInstanceId) -> Option<RegionId> {
        self.region_instances
            .iter()
            .find(|(_, instances)| instances.contains(&instance))
            .map(|(region, _)| *region)
    }

    /// Pin 6: two `AnchorOffset`s are comparable iff they are the same clock,
    /// or at least one is `Zero` — read as the additive identity of whichever
    /// clock it is compared against. `Musical` against `WallClock` is never
    /// comparable (the deferred wall-clock/musical reconciliation).
    fn comparable_offset_order(a: &AnchorOffset, b: &AnchorOffset) -> Option<Ordering> {
        match (a, b) {
            (AnchorOffset::Musical(x), AnchorOffset::Musical(y)) => Some(x.cmp(y)),
            (AnchorOffset::WallClock(x), AnchorOffset::WallClock(y)) => Some(x.cmp(y)),
            (AnchorOffset::Zero, AnchorOffset::Zero) => Some(Ordering::Equal),
            (AnchorOffset::Zero, AnchorOffset::Musical(y)) => Some(MusicalDuration::zero().cmp(y)),
            (AnchorOffset::Musical(x), AnchorOffset::Zero) => Some(x.cmp(&MusicalDuration::zero())),
            (AnchorOffset::Zero, AnchorOffset::WallClock(y)) => Some(WallClockDuration(0).cmp(y)),
            (AnchorOffset::WallClock(x), AnchorOffset::Zero) => Some(x.cmp(&WallClockDuration(0))),
            (AnchorOffset::Musical(_), AnchorOffset::WallClock(_))
            | (AnchorOffset::WallClock(_), AnchorOffset::Musical(_)) => None,
        }
    }

    /// c3's "vector index" ordering between two DISTINCT measures, both
    /// anchored via `Measure{pos: Start, off: Zero}` (contract pin 6, c3):
    /// their relative position within the SAME `StaffInstance.measures`, or
    /// `None` if they are not both found in one instance's live measures.
    ///
    /// Graph-aware mode reads the actual `Vec` (ground truth). Base-free mode
    /// has no graph at all — but base-free reduction has no *base* either, so
    /// every live measure of an instance was minted by a `CreateMeasure`
    /// processed in canonical order, and `minted_by`'s `OperationId` ordering
    /// IS the append order; no separate order ledger is needed (contract §2
    /// row 5 lists exactly `measure_values`/`instance_grid`, not a third).
    fn measure_vector_order(&self, a: MeasureId, b: MeasureId) -> Option<Ordering> {
        if let Some(score) = &self.graph {
            for region in &score.canvas.regions {
                for instance in region.staff_instances() {
                    let pos_a = instance.measures.iter().position(|m| m.id == a);
                    let pos_b = instance.measures.iter().position(|m| m.id == b);
                    if let (Some(pa), Some(pb)) = (pos_a, pos_b) {
                        return Some(pa.cmp(&pb));
                    }
                }
            }
            None
        } else {
            // Repair (spec/CONTRACT_GENESIS_G3B_MEASURE.md pin 6 c3, review
            // fix): c3 requires both measures in the SAME
            // `StaffInstance.measures` — the graph-aware branch above
            // enforces this implicitly (it only returns from within one
            // instance's Vec), so the base-free branch must check it
            // explicitly via `measure_values`'s carried parent id.
            let (parent_a, _) = self.measure_values.get(&a)?;
            let (parent_b, _) = self.measure_values.get(&b)?;
            if parent_a != parent_b {
                return None;
            }
            // Both measures must be LIVE — a retained-but-tombstoned entry
            // (pin 10.4's retention discipline) must not contribute to the
            // ordering.
            if !matches!(
                self.objects.get(&TypedObjectId::Measure(a)),
                Some(ObjectState::Live)
            ) || !matches!(
                self.objects.get(&TypedObjectId::Measure(b)),
                Some(ObjectState::Live)
            ) {
                return None;
            }
            // Order by the minters' canonical reduction-order stamp tuple —
            // NOT by `OperationId`'s own `Ord`, which is `(replica,
            // counter)` authoring identity (ids.rs:409), not reduction
            // order. This is the same tuple `chain_recency` compares.
            let oa = self.minted_by.get(&TypedObjectId::Measure(a))?;
            let ob = self.minted_by.get(&TypedObjectId::Measure(b))?;
            let ta = self.env_of(*oa)?.stamp.reduction_tuple();
            let tb = self.env_of(*ob)?.stamp.reduction_tuple();
            Some(ta.cmp(&tb))
        }
    }

    /// Pin 6: the comparable relation over `TimeAnchor`s, EXACTLY the five
    /// shapes c1–c5. Everything else is NOT comparable, and no other
    /// relation may be invented — pin 6's prohibition. The boundary selector
    /// (`MeasurePosition`/`RegionEdge`) must be IDENTICAL; it is never
    /// ordered (draft 3's `Start < End` was unsound and is not reproduced
    /// here).
    fn anchors_comparable_order(&self, a: &TimeAnchor, b: &TimeAnchor) -> Option<Ordering> {
        match (a, b) {
            // c1: same Event id.
            (
                TimeAnchor::Event { id: ia, offset: oa },
                TimeAnchor::Event { id: ib, offset: ob },
            ) if ia == ib => Self::comparable_offset_order(oa, ob),
            // c2/c3: Measure anchors.
            (
                TimeAnchor::Measure {
                    id: ia,
                    position: pa,
                    offset: oa,
                },
                TimeAnchor::Measure {
                    id: ib,
                    position: pb,
                    offset: ob,
                },
            ) => {
                if pa != pb {
                    return None;
                }
                if ia == ib {
                    // c2: same id and same pos.
                    return Self::comparable_offset_order(oa, ob);
                }
                // c3: distinct ids, restricted to pos: Start, off: Zero (load-
                // bearing — a nonzero offset or an `End` position can carry a
                // point past its neighbour, so the index no longer bounds
                // it).
                if *pa != MeasurePosition::Start
                    || !matches!(oa, AnchorOffset::Zero)
                    || !matches!(ob, AnchorOffset::Zero)
                {
                    return None;
                }
                self.measure_vector_order(*ia, *ib)
            }
            // c4: same Region id and same edge.
            (
                TimeAnchor::Region {
                    id: ia,
                    edge: ea,
                    offset: oa,
                },
                TimeAnchor::Region {
                    id: ib,
                    edge: eb,
                    offset: ob,
                },
            ) if ia == ib && ea == eb => Self::comparable_offset_order(oa, ob),
            // c5: WallClock, no referent id.
            (TimeAnchor::WallClock { time: ta }, TimeAnchor::WallClock { time: tb }) => {
                Some(ta.cmp(tb))
            }
            // Never Event<->Measure, never Measure<->Region, never two Events
            // with different ids, never Musical against WallClock, and never
            // across differing pos/edge selectors.
            _ => None,
        }
    }

    /// Pin 6b: the musical delta `b - a`, computable ONLY in shape c1, c2, or
    /// c4 with BOTH offsets in the `Musical` clock (or `Zero`, normalized to
    /// `Musical(0)`), and only when the boundary selector is identical. c3
    /// supplies no delta at all (a vector index gives order, never distance).
    /// `WallClock` deltas are not musical durations and are never returned.
    fn anchor_musical_delta(&self, a: &TimeAnchor, b: &TimeAnchor) -> Option<MusicalDuration> {
        fn musical(o: &AnchorOffset) -> Option<MusicalDuration> {
            match o {
                AnchorOffset::Musical(d) => Some(d.clone()),
                AnchorOffset::Zero => Some(MusicalDuration::zero()),
                AnchorOffset::WallClock(_) => None,
            }
        }
        match (a, b) {
            (
                TimeAnchor::Event { id: ia, offset: oa },
                TimeAnchor::Event { id: ib, offset: ob },
            ) if ia == ib => Some(musical(ob)? - musical(oa)?),
            (
                TimeAnchor::Measure {
                    id: ia,
                    position: pa,
                    offset: oa,
                },
                TimeAnchor::Measure {
                    id: ib,
                    position: pb,
                    offset: ob,
                },
            ) if ia == ib && pa == pb => Some(musical(ob)? - musical(oa)?),
            (
                TimeAnchor::Region {
                    id: ia,
                    edge: ea,
                    offset: oa,
                },
                TimeAnchor::Region {
                    id: ib,
                    edge: eb,
                    offset: ob,
                },
            ) if ia == ib && ea == eb => Some(musical(ob)? - musical(oa)?),
            _ => None,
        }
    }

    /// The outcome of finding the governing element of a partially-ordered
    /// set under [`Self::anchors_comparable_order`] (contract pin 6c steps
    /// 0–3) — shared by the effective-grid oracle's governing meter change
    /// AND `CreateMeasure`'s "current last measure" (an append-only sequence
    /// poses exactly the same "find the unique maximum" problem).
    fn unique_maximum<'x, T: Copy>(
        &self,
        candidates: impl IntoIterator<Item = (T, &'x TimeAnchor)>,
    ) -> GoverningElement<T> {
        let items: Vec<(T, &TimeAnchor)> = candidates.into_iter().collect();
        if items.is_empty() {
            return GoverningElement::None;
        }
        let mut maximal: Vec<T> = Vec::new();
        for (key, anchor) in &items {
            let dominated = items.iter().any(|(_, other)| {
                self.anchors_comparable_order(other, anchor) == Some(Ordering::Greater)
            });
            if !dominated {
                maximal.push(*key);
            }
        }
        if maximal.len() == 1 {
            GoverningElement::Unique(maximal[0])
        } else {
            GoverningElement::Indeterminate
        }
    }

    /// Pin 6c steps 0–3: the governing element among `candidates` relative to
    /// `reference` (e.g. a meter change's signature relative to a measure's
    /// start). **Step 0 comes before any candidate set**: if ANY candidate's
    /// anchor is incomparable to `reference`, the whole selection is
    /// indeterminate — even when the not-after-filtered set would have been
    /// empty (an incomparable change is unplaced, not absent, and it might
    /// have governed).
    fn governing_by_anchor<'x, T: Copy>(
        &self,
        reference: &TimeAnchor,
        candidates: impl IntoIterator<Item = (T, &'x TimeAnchor)>,
    ) -> GoverningElement<T> {
        let mut not_after: Vec<(T, &TimeAnchor)> = Vec::new();
        for (key, anchor) in candidates {
            match self.anchors_comparable_order(anchor, reference) {
                None => return GoverningElement::Indeterminate,
                Some(Ordering::Greater) => {}
                Some(_) => not_after.push((key, anchor)),
            }
        }
        self.unique_maximum(not_after)
    }

    /// Pin 6c, disposition A: the effective metric grid for a staff
    /// instance — its own local override when present, else the enclosing
    /// region's whole-grid write layered with per-key meter-change writes,
    /// in canonical write order (the whole-grid chain first, then the
    /// per-key overlay — a later per-key write overrides an earlier
    /// whole-grid write, and a later whole-grid write supersedes an earlier
    /// per-key write). Consults ONLY `self.instance_grid`,
    /// `self.metric_grid_chain`, and `self.meter_change_chain` — never
    /// `self.graph` — so graph-aware and base-free reduction run the
    /// IDENTICAL reconstruction (pin 6c, M30b).
    ///
    /// `grid_override`/`meter_change_overrides` let a caller ask "what would
    /// the grid be under this PROSPECTIVE write", substituting a value the
    /// corresponding chain does not (yet) hold — used to evaluate an
    /// in-flight undo restoration without mutating the chains (pin 6c,
    /// M31a). `None` (respectively, an absent key) means "no prospective
    /// override; consult the chain".
    fn effective_grid(
        &self,
        instance: StaffInstanceId,
        region: Option<RegionId>,
        grid_override: Option<&Option<MetricGrid>>,
        meter_change_overrides: &BTreeMap<MusicalPosition, Option<MeterChange>>,
    ) -> Vec<MeterChange> {
        if let Some(Some(local)) = self.instance_grid.get(&instance) {
            return local.meter_sequence.clone();
        }

        let whole_chain = region.and_then(|region| self.metric_grid_chain.get(&region));
        let whole_recency = self.chain_recency(whole_chain, grid_override.is_some());
        let whole_value: Option<MetricGrid> = match grid_override {
            Some(over) => over.clone(),
            None => whole_chain
                .and_then(|chain| chain.current())
                .cloned()
                .flatten(),
        };
        let mut sequence: Vec<MeterChange> =
            whole_value.map(|g| g.meter_sequence).unwrap_or_default();

        // Every key either chain could speak to: positions the whole grid
        // itself names, every per-key chain entry for this region, and any
        // prospective per-key override.
        let mut keys: BTreeSet<MusicalPosition> = sequence
            .iter()
            .map(|c| resolved_anchor_position(&c.anchor))
            .collect();
        if let Some(region) = region {
            keys.extend(
                self.meter_change_chain
                    .keys()
                    .filter(|(r, _)| *r == region)
                    .map(|(_, pos)| pos.clone()),
            );
        }
        keys.extend(meter_change_overrides.keys().cloned());

        // Canonical write-order interleaving (pin 6c, M30c): at each key,
        // whichever chain wrote MORE RECENTLY governs. A later whole-grid
        // write supersedes an earlier per-key change at that position (so
        // the whole grid's own content there stands, and any stale per-key
        // value is ignored); a later per-key write overlays the whole grid.
        // `metric_grid_chain` and `meter_change_chain` are independent —
        // `set_metric_grid` never touches `meter_change_chain` — so this
        // cannot be shortcut to "whole grid, then always overlay per-key".
        for key in keys {
            let per_key_chain =
                region.and_then(|region| self.meter_change_chain.get(&(region, key.clone())));
            let per_key_is_prospective = meter_change_overrides.contains_key(&key);
            let per_key_recency = self.chain_recency(per_key_chain, per_key_is_prospective);

            // Repair (spec/CONTRACT_GENESIS_G3B_MEASURE.md pin 6c, review
            // fix): `Recency::Prospective` is a unit variant, so two
            // simultaneous prospective restorations (a whole-grid
            // restoration and a per-key restoration under the same undo)
            // compare EQUAL, and a strict `>` would hand governance to the
            // whole grid even though restoration actually applies the
            // per-key write AFTER the whole grid, under the same undo
            // operation id. Ratified tie-break: on EQUAL NON-`Base` recency,
            // the per-key write governs — this is not limited to the
            // prospective family. Two REAL writes tied under the same
            // recorded op id resolve the identical way: once an undo
            // actually commits, `apply_restorations` records every
            // restoration it applies — the whole-grid one and the per-key
            // one alike — under that SAME undo's operation id, so their
            // `Recency::Write(..)` tuples are equal too, and the rule must
            // still hand governance to the per-key write.
            // Do NOT widen this to a plain `>=`: when both sides are
            // `Recency::Base` the per-key chain has no write, so `value`
            // below resolves to `None` and the overlay would DELETE the
            // whole grid's entry at this key — a regression.
            if per_key_recency > whole_recency
                || (per_key_recency == whole_recency && per_key_recency != Recency::Base)
            {
                let value: Option<MeterChange> = if per_key_is_prospective {
                    meter_change_overrides.get(&key).cloned().flatten()
                } else {
                    per_key_chain
                        .and_then(|chain| chain.current())
                        .cloned()
                        .flatten()
                };
                sequence.retain(|c| resolved_anchor_position(&c.anchor) != key);
                if let Some(change) = value {
                    sequence.push(change);
                }
            }
            // Else: the whole grid's own content at this position (already
            // reflected in `sequence`, or absent) governs — the per-key
            // write, if any, predates it and is superseded.
        }
        sequence
    }

    /// The write-recency of a chain's last write, for comparing which of two
    /// INDEPENDENT chains wrote more recently in canonical order (pin 6c,
    /// M30c) — `(physical, logical, replica, counter)`, the same tuple
    /// `canonical_reduction_order` sorts by. A chain with no recorded write
    /// (only a seeded base, or absent) is [`Recency::Base`], which sorts
    /// before every real write; `prospective` (an in-flight, not-yet-applied
    /// restoration, pin 6c M31a) always sorts last.
    fn chain_recency<V: Clone>(&self, chain: Option<&WriteChain<V>>, prospective: bool) -> Recency {
        if prospective {
            return Recency::Prospective;
        }
        match chain.and_then(|c| c.last_write()) {
            Some(write) => self
                .env_of(write.op)
                .map(|env| Recency::Write(env.stamp.reduction_tuple()))
                .unwrap_or(Recency::Base),
            None => Recency::Base,
        }
    }

    /// Pin 6c: the effective grid's governing time signature at `start`,
    /// from an already-reconstructed `sequence` ([`Self::effective_grid`]).
    fn governing_time_signature(
        &self,
        sequence: &[MeterChange],
        start: &TimeAnchor,
    ) -> GoverningElement<TimeSignatureId> {
        self.governing_by_anchor(
            start,
            sequence.iter().map(|c| (c.time_signature, &c.anchor)),
        )
    }

    /// All LIVE measures of `instance`, from `measure_values` filtered
    /// through `self.objects` (a retained-but-tombstoned entry must not
    /// contribute — contract pin 10.4's retention discipline, applied here to
    /// the ordering computation too).
    fn live_measure_starts(&self, instance: StaffInstanceId) -> Vec<(MeasureId, &TimeAnchor)> {
        self.measure_values
            .iter()
            .filter_map(|(id, (parent, measure))| {
                if *parent != instance {
                    return None;
                }
                if !matches!(
                    self.objects.get(&TypedObjectId::Measure(*id)),
                    Some(ObjectState::Live)
                ) {
                    return None;
                }
                Some((*id, &measure.start))
            })
            .collect()
    }

    /// All LIVE measures of `instance`, in append order — the graph's own
    /// `Vec` order graph-aware, or (base-free) sorted by
    /// [`Self::measure_vector_order`]'s minted-stamp-tuple comparison, which
    /// IS the append order for a mint-only, append-only family (contract pin
    /// 9c). Shared by `CreateMeasure`'s "current last measure" walk's
    /// sibling checks and by the preservation checks below, which must
    /// evaluate every EXISTING live measure of an instance, not merely the
    /// last one — a whole-grid or per-key rewrite can break agreement or
    /// boundary consistency for ANY of them.
    fn measures_of_instance_in_order(&self, instance: StaffInstanceId) -> Vec<Measure> {
        let mut list: Vec<(MeasureId, Measure)> = self
            .measure_values
            .iter()
            .filter(|(id, (parent, _))| {
                *parent == instance
                    && matches!(
                        self.objects.get(&TypedObjectId::Measure(**id)),
                        Some(ObjectState::Live)
                    )
            })
            .map(|(id, (_, m))| (*id, m.clone()))
            .collect();
        list.sort_by(|a, b| {
            self.measure_vector_order(a.0, b.0)
                .unwrap_or(Ordering::Equal)
        });
        list.into_iter().map(|(_, m)| m).collect()
    }

    /// Contract pin 9c: mirrors invariant 20's own two-clause definition
    /// (agreement, boundary) over `sequence` — the RESULTING effective grid
    /// a prospective write or an undo restoration set would install — for
    /// every live measure of `instance`, in append order. Shared by both
    /// grid setters' forward-path preservation checks (pin 9c.1) and by undo
    /// restoration-safety evaluation (pin 9c.3, both undo policies), so a
    /// single implementation — not three near-duplicates — defines "does
    /// this grid preserve invariant 20". `None` when clean.
    /// `prospective_signature` lets a caller whose write mints a BRAND-NEW
    /// `TimeSignature` (as part of the SAME operation) supply its value for
    /// this check to consult — the check MUST run before the mint (pin
    /// 9c.2 / M45), so `self.time_signature_values` does not yet carry it.
    /// `None` for callers with nothing new to add (`SetMetricGrid`, whose
    /// own precondition already requires every referenced signature to
    /// pre-exist; undo restoration, which only ever reinstalls
    /// already-known signatures).
    fn invariant20_violation(
        &self,
        instance: StaffInstanceId,
        sequence: &[MeterChange],
        prospective_signature: Option<&TimeSignature>,
    ) -> Option<PreconditionFailureReason> {
        let duration_of = |sig: TimeSignatureId| -> Option<MusicalDuration> {
            if let Some(p) = prospective_signature {
                if p.id == sig {
                    return Some(p.measure_duration().clone());
                }
            }
            self.time_signature_values
                .get(&sig)
                .map(|ts| ts.measure_duration().clone())
        };
        let resolves = |sig: TimeSignatureId| -> bool {
            matches!(
                self.objects.get(&TypedObjectId::TimeSignature(sig)),
                Some(ObjectState::Live)
            ) || prospective_signature.is_some_and(|p| p.id == sig)
        };
        let measures = self.measures_of_instance_in_order(instance);
        for (i, m) in measures.iter().enumerate() {
            // Agreement clause: ONLY a resolving `Some(id)` (pin 9b) — an
            // unresolving reference is invariant 10's business, and `None`
            // avoids only this clause, not the boundary clause below.
            if let Some(sig) = m.time_signature {
                if resolves(sig) {
                    match self.governing_time_signature(sequence, &m.start) {
                        GoverningElement::Unique(active) if active != sig => {
                            return Some(PreconditionFailureReason::MeasureMeterMismatch);
                        }
                        GoverningElement::Unique(_) | GoverningElement::None => {}
                        GoverningElement::Indeterminate => {
                            return Some(PreconditionFailureReason::MeasureOrderUnverifiable);
                        }
                    }
                }
            }
            // Boundary clause: vacuous for the first measure (no
            // predecessor — pickup/anacrusis deferral, P13-S19).
            if i == 0 {
                continue;
            }
            let prev = &measures[i - 1];
            match self.governing_time_signature(sequence, &prev.start) {
                GoverningElement::Unique(sig) => {
                    let expected = duration_of(sig);
                    match (self.anchor_musical_delta(&prev.start, &m.start), expected) {
                        (Some(delta), Some(expected)) if delta == expected => {}
                        (Some(_), Some(_)) => {
                            return Some(PreconditionFailureReason::MeasureMeterMismatch);
                        }
                        _ => return Some(PreconditionFailureReason::MeasureOrderUnverifiable),
                    }
                }
                GoverningElement::None => {}
                GoverningElement::Indeterminate => {
                    return Some(PreconditionFailureReason::MeasureOrderUnverifiable);
                }
            }
        }
        None
    }

    /// Contract pin 9c.1: refuses `SetMetricGrid`/`SetTimeSignature` when
    /// the RESULTING grid (`grid_override` for a whole-grid write, or
    /// `meter_change_overrides` for a per-key write) would violate
    /// invariant 20's agreement or boundary clause for any live measure of
    /// any staff instance of `region` the change reaches. An instance
    /// carrying its own local override is unaffected: `effective_grid`
    /// ignores these override params once a local override governs, so
    /// checking it here is harmless (it just re-derives the same clean
    /// local grid). MUST be called before any mint (pin 9c.2 / M45).
    fn check_grid_preserves_invariant20(
        &self,
        region: RegionId,
        grid_override: Option<&Option<MetricGrid>>,
        meter_change_overrides: &BTreeMap<MusicalPosition, Option<MeterChange>>,
        prospective_signature: Option<&TimeSignature>,
    ) -> Option<OperationEffect> {
        let instances = self
            .region_instances
            .get(&region)
            .cloned()
            .unwrap_or_default();
        for instance in instances {
            let sequence = self.effective_grid(
                instance,
                Some(region),
                grid_override,
                meter_change_overrides,
            );
            if let Some(reason) =
                self.invariant20_violation(instance, &sequence, prospective_signature)
            {
                return Some(OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction { reason },
                });
            }
        }
        None
    }

    /// Contract pin 9c.3: whether the effective grid of `region`, with
    /// `whole`/`per_key`'s prospective overrides (if any) applied, would
    /// leave invariant 20 clean for every live measure of every instance of
    /// that region — the single-region primitive both the `StrictInverse`
    /// aggregate check and `BestEffort`'s canonical-order greedy fold over.
    fn region_grid_clean(
        &self,
        region: RegionId,
        whole: &BTreeMap<RegionId, Option<MetricGrid>>,
        per_key: &BTreeMap<RegionId, BTreeMap<MusicalPosition, Option<MeterChange>>>,
    ) -> bool {
        let grid_override = whole.get(&region);
        let empty = BTreeMap::new();
        let meter_change_overrides = per_key.get(&region).unwrap_or(&empty);
        let instances = self
            .region_instances
            .get(&region)
            .cloned()
            .unwrap_or_default();
        for instance in instances {
            let sequence = self.effective_grid(
                instance,
                Some(region),
                grid_override,
                meter_change_overrides,
            );
            if self
                .invariant20_violation(instance, &sequence, None)
                .is_some()
            {
                return false;
            }
        }
        true
    }

    /// Contract pin 9c.3, `StrictInverse`/`Cascade`: whether the WHOLE
    /// restoration set, applied together, would violate invariant 20 for
    /// any region it touches — evaluated in AGGREGATE (never
    /// per-restoration): individually-unsafe restorations can be jointly
    /// safe, and individually-safe ones can be jointly unsafe.
    fn aggregate_restorations_violate_invariant20(
        &self,
        restorations: &[ValueRestoration],
    ) -> bool {
        let mut whole: BTreeMap<RegionId, Option<MetricGrid>> = BTreeMap::new();
        let mut per_key: BTreeMap<RegionId, BTreeMap<MusicalPosition, Option<MeterChange>>> =
            BTreeMap::new();
        for r in restorations {
            match r {
                ValueRestoration::MetricGrid { region, value } => {
                    whole.insert(*region, value.clone());
                }
                ValueRestoration::MeterChange {
                    region,
                    position,
                    value,
                } => {
                    per_key
                        .entry(*region)
                        .or_default()
                        .insert(position.clone(), value.clone());
                }
                _ => {}
            }
        }
        let mut regions: BTreeSet<RegionId> = whole.keys().copied().collect();
        regions.extend(per_key.keys().copied());
        regions
            .into_iter()
            .any(|region| !self.region_grid_clean(region, &whole, &per_key))
    }

    /// Contract pin 9c.3, `BestEffort`: the canonical-order greedy — walks
    /// `restorations` in `collect_restorations`' existing (canonical,
    /// BTreeMap-keyed) order, admitting each grid/meter-change restoration
    /// whose addition keeps the ACCUMULATED prospective state
    /// invariant-20-clean, skipping the rest. Non-grid restorations (event,
    /// pitch, cross-cutting, …) are unaffected by invariant 20 and are
    /// always admitted. "Maximal" means maximal under this deterministic
    /// rule, not set-theoretically maximum: the greedy never backtracks to
    /// try a different admission order, and the true maximum subset is not
    /// uniquely defined.
    fn select_invariant20_safe_restorations(
        &self,
        restorations: Vec<ValueRestoration>,
    ) -> Vec<ValueRestoration> {
        let mut admitted_whole: BTreeMap<RegionId, Option<MetricGrid>> = BTreeMap::new();
        let mut admitted_per_key: BTreeMap<
            RegionId,
            BTreeMap<MusicalPosition, Option<MeterChange>>,
        > = BTreeMap::new();
        let mut out = Vec::new();
        for restoration in restorations {
            match &restoration {
                ValueRestoration::MetricGrid { region, value } => {
                    let saved = admitted_whole.insert(*region, value.clone());
                    if self.region_grid_clean(*region, &admitted_whole, &admitted_per_key) {
                        out.push(restoration);
                    } else {
                        match saved {
                            Some(prev) => {
                                admitted_whole.insert(*region, prev);
                            }
                            None => {
                                admitted_whole.remove(region);
                            }
                        }
                    }
                }
                ValueRestoration::MeterChange {
                    region,
                    position,
                    value,
                } => {
                    let entry = admitted_per_key.entry(*region).or_default();
                    let saved = entry.insert(position.clone(), value.clone());
                    if self.region_grid_clean(*region, &admitted_whole, &admitted_per_key) {
                        out.push(restoration);
                    } else {
                        let entry = admitted_per_key
                            .get_mut(region)
                            .expect("just inserted above");
                        match saved {
                            Some(prev) => {
                                entry.insert(position.clone(), prev);
                            }
                            None => {
                                entry.remove(position);
                            }
                        }
                    }
                }
                _ => out.push(restoration),
            }
        }
        out
    }

    fn graph_create_measure(&mut self, instance: StaffInstanceId, measure: &Measure) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        for region in &mut score.canvas.regions {
            if let Some(instances) = region.content.staff_instances_mut() {
                if let Some(inst) = instances.iter_mut().find(|i| i.id == instance) {
                    inst.measures.push(measure.clone());
                    return;
                }
            }
        }
    }

    /// Append-only set-union creation of a `Measure` onto a live
    /// `StaffInstance` (operation_catalog §CreateMeasure, contract pins
    /// 4/5/8/9). Fresh id mints; a byte-identical re-carry under the SAME
    /// parent is idempotent; a differing value, OR the same value under a
    /// DIFFERENT parent (pin 5 — the parent is part of identity), is a
    /// precondition no-op; a tombstoned id refuses.
    fn create_measure(&mut self, env: &OperationEnvelope, op: &CreateMeasureOp) -> OperationEffect {
        fn unverifiable() -> OperationEffect {
            OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::MeasureOrderUnverifiable,
                },
            }
        }

        // Pin 8.1: the parent StaffInstance must be live — ungated (both
        // graph-aware and base-free reduction; a mint into a non-existent
        // parent has nowhere to go even base-free).
        if !matches!(
            self.objects.get(&TypedObjectId::StaffInstance(op.instance)),
            Some(ObjectState::Live)
        ) {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetMissing,
                },
            };
        }

        let mobj = TypedObjectId::Measure(op.measure_id());
        match self.objects.get(&mobj) {
            Some(ObjectState::Live) => {
                let identical = self
                    .measure_values
                    .get(&op.measure_id())
                    .is_some_and(|(parent, known)| *parent == op.instance && known == &op.measure);
                return if identical {
                    OperationEffect::NoOp {
                        reason: NoOpReason::AlreadyApplied,
                    }
                } else {
                    OperationEffect::NoOp {
                        reason: NoOpReason::PreconditionFailedUnderReduction {
                            reason: PreconditionFailureReason::RecreateContentMismatch,
                        },
                    }
                };
            }
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::TargetTombstoned,
                }
            }
            None => {}
        }

        // Pins 8.2/8.3: reference-resolution preconditions are graph-aware
        // only (base-free reduction has no universe to check against).
        if self.graph.is_some() {
            if let Some(sig) = op.measure.time_signature {
                if !matches!(
                    self.objects.get(&TypedObjectId::TimeSignature(sig)),
                    Some(ObjectState::Live)
                ) {
                    return OperationEffect::NoOp {
                        reason: NoOpReason::PreconditionFailedUnderReduction {
                            reason: PreconditionFailureReason::TargetMissing,
                        },
                    };
                }
            }
            let start_resolves = match &op.measure.start {
                TimeAnchor::Event { id, .. } => matches!(
                    self.objects.get(&TypedObjectId::Event(*id)),
                    Some(ObjectState::Live)
                ),
                TimeAnchor::Measure { id, .. } => matches!(
                    self.objects.get(&TypedObjectId::Measure(*id)),
                    Some(ObjectState::Live)
                ),
                TimeAnchor::Region { id, .. } => matches!(
                    self.objects.get(&TypedObjectId::Region(*id)),
                    Some(ObjectState::Live)
                ),
                TimeAnchor::WallClock { .. } => true,
            };
            if !start_resolves {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::TargetMissing,
                    },
                };
            }
        }

        let region = self.region_of_instance(op.instance);

        // Pin 9 clauses 1 & 3: the current last live measure of this
        // instance — vacuous for the first measure (pin 9's pickup
        // deferral, P13-S19).
        let predecessor: Option<TimeAnchor> =
            match self.unique_maximum(self.live_measure_starts(op.instance)) {
                GoverningElement::None => None,
                GoverningElement::Unique(id) => self
                    .measure_values
                    .get(&id)
                    .map(|(_, measure)| measure.start.clone()),
                GoverningElement::Indeterminate => return unverifiable(),
            };

        // Pin 9 clause 1: ordering.
        if let Some(prev_start) = &predecessor {
            match self.anchors_comparable_order(&op.measure.start, prev_start) {
                None => return unverifiable(),
                Some(Ordering::Greater) => {}
                Some(_) => {
                    return OperationEffect::NoOp {
                        reason: NoOpReason::PreconditionFailedUnderReduction {
                            reason: PreconditionFailureReason::MeasureOutOfOrder,
                        },
                    };
                }
            }
        }

        // Pin 9 clause 2: agreement — ONLY when `time_signature` is `Some`
        // (pin 9b: `None` avoids only this clause, not clause 3).
        let sequence = self.effective_grid(op.instance, region, None, &BTreeMap::new());
        if let Some(sig) = op.measure.time_signature {
            match self.governing_time_signature(&sequence, &op.measure.start) {
                GoverningElement::Unique(active) if active == sig => {}
                GoverningElement::Unique(_) => {
                    return OperationEffect::NoOp {
                        reason: NoOpReason::PreconditionFailedUnderReduction {
                            reason: PreconditionFailureReason::MeasureMeterMismatch,
                        },
                    };
                }
                // Pin 6c case 1 / pin 7: no active signature governs this
                // start — agreement is vacuous, not a violation. Fall
                // through (no refusal).
                GoverningElement::None => {}
                GoverningElement::Indeterminate => return unverifiable(),
            }
        }

        // Pin 9 clause 3: boundary distance — vacuous for the first measure.
        // `None` (no active signature governs the previous start) and
        // `Indeterminate` (selection cannot be resolved) are NOT the same
        // outcome: pin 6c case 1 makes `None` an abstention (allow the
        // mint), while `Indeterminate` still fails closed with
        // `MeasureOrderUnverifiable` (pin 7). Collapsing them was the bug.
        if let Some(prev_start) = &predecessor {
            match self.governing_time_signature(&sequence, prev_start) {
                GoverningElement::Unique(sig) => {
                    let expected = self
                        .time_signature_values
                        .get(&sig)
                        .map(|ts| ts.measure_duration().clone());
                    match (
                        self.anchor_musical_delta(prev_start, &op.measure.start),
                        expected,
                    ) {
                        (Some(delta), Some(expected)) if delta == expected => {}
                        (Some(_), Some(_)) => {
                            return OperationEffect::NoOp {
                                reason: NoOpReason::PreconditionFailedUnderReduction {
                                    reason: PreconditionFailureReason::MeasureMeterMismatch,
                                },
                            };
                        }
                        _ => return unverifiable(),
                    }
                }
                // Pin 6c case 1 / pin 7: no active signature governs the
                // previous measure's start — boundary consistency abstains.
                // Not a violation; allow the mint.
                GoverningElement::None => {}
                GoverningElement::Indeterminate => return unverifiable(),
            }
        }

        self.graph_create_measure(op.instance, &op.measure);
        self.mint_container(env, mobj);
        self.measure_values
            .insert(op.measure_id(), (op.instance, op.measure.clone()));
        OperationEffect::Applied
    }

    /// Set-union mint of a `TimeSignature` carried by a `SetTimeSignature`
    /// (operation_catalog §"Meter and Tempo Overwrites"): fresh id mints;
    /// byte-identical re-carry is idempotent; a differing value under a live
    /// id — or a tombstoned id — refuses the whole operation.
    fn mint_time_signature(
        &mut self,
        env: &OperationEnvelope,
        signature: &TimeSignature,
    ) -> Result<(), OperationEffect> {
        let obj = TypedObjectId::TimeSignature(signature.id);
        match self.objects.get(&obj) {
            Some(ObjectState::Live) => {
                let identical = self
                    .time_signature_values
                    .get(&signature.id)
                    .is_some_and(|known| known == signature);
                if identical {
                    Ok(())
                } else {
                    Err(OperationEffect::NoOp {
                        reason: NoOpReason::PreconditionFailedUnderReduction {
                            reason: PreconditionFailureReason::RecreateContentMismatch,
                        },
                    })
                }
            }
            Some(ObjectState::Tombstoned { .. }) => Err(OperationEffect::NoOp {
                reason: NoOpReason::TargetTombstoned,
            }),
            None => {
                self.mint_container(env, obj);
                self.time_signature_values
                    .insert(signature.id, signature.clone());
                if let Some(score) = self.graph.as_mut() {
                    if !score.time_signatures.iter().any(|t| t.id == signature.id) {
                        score.time_signatures.push(signature.clone());
                    }
                }
                Ok(())
            }
        }
    }

    /// Sets, replaces, or removes the single meter change at the anchor's
    /// resolved position in the region's default metric grid — an LWW
    /// structural overwrite keyed by `(region, resolved position)`
    /// (operation_catalog §"Meter and Tempo Overwrites"). The carried
    /// signature's beat-group sum is validated at construction and at decode,
    /// so a malformed value never reaches this reduction.
    fn set_time_signature(
        &mut self,
        env: &OperationEnvelope,
        op: &SetTimeSignatureOp,
    ) -> OperationEffect {
        if let Some(effect) = self.layout_region_slot(op.region) {
            return effect;
        }
        // Contract pin 9c.2/M45: EVERY invariant check must precede any
        // mint. `written`'s signature id is a field read off `op` itself —
        // no mint needed to know it — so the prospective invariant-20
        // preservation check (pin 9c.1) can and must run BEFORE
        // `mint_time_signature` below. A refusal here leaves no residue: no
        // fresh `TimeSignature` was ever minted for it to leak from
        // `objects`, `time_signature_values`, or the graph.
        let key = (op.region, op.resolved_position());
        let written: Option<MeterChange> =
            op.time_signature.as_ref().map(|signature| MeterChange {
                anchor: op.anchor.clone(),
                time_signature: signature.id,
            });
        let mut prospective_overrides = BTreeMap::new();
        prospective_overrides.insert(key.1.clone(), written.clone());
        if let Some(effect) = self.check_grid_preserves_invariant20(
            op.region,
            None,
            &prospective_overrides,
            op.time_signature.as_ref(),
        ) {
            return effect;
        }
        if let Some(signature) = &op.time_signature {
            if let Err(effect) = self.mint_time_signature(env, signature) {
                return effect;
            }
        }
        let prev = self
            .meter_change_chain
            .get(&key)
            .and_then(|chain| chain.last_write())
            .map(|write| (write.op, write.value.clone()));
        let effect = match prev {
            Some((prev_op, prev_value)) if self.concurrent(env.id, prev_op) => {
                if prev_value == written {
                    return OperationEffect::NoOp {
                        reason: NoOpReason::AlreadyApplied,
                    };
                }
                let conflict = ConflictRecord::new(
                    ConflictKind::StructuralFieldCollision {
                        winner: env.id,
                        loser: prev_op,
                        field: FieldPath("meter_sequence".to_string()),
                    },
                    vec![env.id, prev_op],
                    vec![TypedObjectId::Region(op.region)],
                );
                let cid = conflict.id;
                self.conflicts.insert(conflict);
                OperationEffect::Conflicted { conflict: cid }
            }
            _ => OperationEffect::Applied,
        };
        self.meter_change_chain
            .entry(key.clone())
            .or_insert_with(WriteChain::new)
            .record(env.id, env.transaction, written.clone());
        self.graph_apply_meter_change(op.region, &key.1, &written);
        effect
    }

    /// Applies a meter-change overwrite (or removal) to the region's default
    /// metric grid, keeping the sequence ordered by resolved position. A set
    /// on a region whose grid is `None` creates the grid; a removal that
    /// empties the sequence normalizes the slot back to `None` unless a
    /// whole-grid write (or the base) holds a grid value independently.
    fn graph_apply_meter_change(
        &mut self,
        region: RegionId,
        position: &MusicalPosition,
        change: &Option<MeterChange>,
    ) {
        let baseline_grid = self
            .metric_grid_chain
            .get(&region)
            .and_then(|chain| chain.current())
            .is_some_and(|grid| grid.is_some());
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        let Some(region) = score.canvas.regions.iter_mut().find(|r| r.id == region) else {
            return;
        };
        let Some(content) = region.content.staff_based_mut() else {
            return;
        };
        match change {
            Some(meter) => {
                let grid = content
                    .default_metric_grid
                    .get_or_insert_with(MetricGrid::default);
                grid.meter_sequence
                    .retain(|existing| resolved_anchor_position(&existing.anchor) != *position);
                let index = grid
                    .meter_sequence
                    .iter()
                    .position(|existing| resolved_anchor_position(&existing.anchor) > *position)
                    .unwrap_or(grid.meter_sequence.len());
                grid.meter_sequence.insert(index, meter.clone());
            }
            None => {
                if let Some(grid) = content.default_metric_grid.as_mut() {
                    grid.meter_sequence
                        .retain(|existing| resolved_anchor_position(&existing.anchor) != *position);
                    if grid.meter_sequence.is_empty() && !baseline_grid {
                        content.default_metric_grid = None;
                    }
                }
            }
        }
    }

    /// Whether the scope's *resulting* tempo map is well-formed with `written`
    /// installed at `key` (operation_catalog §"Meter and Tempo Overwrites"):
    /// the carried segment's own start equals the operation's key, every
    /// segment's shape carries its end data, and resolved ends neither precede
    /// their own start nor overlap the next segment. Read purely from the
    /// tempo chains' current values (which seed from the base map), so
    /// graph-free and graph-aware reduction agree wherever both represent the
    /// scope.
    fn prospective_tempo_write_well_formed(
        &self,
        key: &(Option<RegionId>, MusicalPosition),
        written: &TempoSegment,
    ) -> bool {
        if resolved_anchor_position(&written.start) != key.1 {
            return false;
        }
        let mut segments: Vec<(MusicalPosition, &TempoSegment)> = Vec::new();
        for ((scope, position), chain) in &self.tempo_segment_chain {
            if scope != &key.0 || *position == key.1 {
                continue;
            }
            if let Some(Some(segment)) = chain.current() {
                segments.push((position.clone(), segment));
            }
        }
        segments.push((key.1.clone(), written));
        segments.sort_by(|(a, _), (b, _)| a.cmp(b));
        for (index, (position, segment)) in segments.iter().enumerate() {
            if !tempo_segment_shape_well_formed(segment) {
                return false;
            }
            if let Some(end) = &segment.end {
                let resolved_end = resolved_anchor_position(end);
                if resolved_end < *position {
                    return false;
                }
                if let Some((next_position, _)) = segments.get(index + 1) {
                    if resolved_end > *next_position {
                        return false;
                    }
                }
            }
        }
        true
    }

    /// Sets, replaces, or removes the single tempo segment starting at the
    /// resolved position in the scoped tempo map — an LWW structural overwrite
    /// keyed by `(scope, resolved start)` (operation_catalog §"Meter and Tempo
    /// Overwrites"). A write that would malform the resulting map is refused
    /// (`TempoMapMalformed`).
    fn set_tempo_segment(
        &mut self,
        env: &OperationEnvelope,
        op: &SetTempoSegmentOp,
    ) -> OperationEffect {
        if let Some(region) = op.region {
            if !matches!(
                self.objects.get(&TypedObjectId::Region(region)),
                Some(ObjectState::Live)
            ) {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::TargetMissing,
                    },
                };
            }
        }
        let key = (op.region, op.resolved_start());
        if let Some(segment) = &op.segment {
            if !self.prospective_tempo_write_well_formed(&key, segment) {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::TempoMapMalformed,
                    },
                };
            }
        }
        let prev = self
            .tempo_segment_chain
            .get(&key)
            .and_then(|chain| chain.last_write())
            .map(|write| (write.op, write.value.clone()));
        let effect = match prev {
            Some((prev_op, prev_value)) if self.concurrent(env.id, prev_op) => {
                if prev_value == op.segment {
                    return OperationEffect::NoOp {
                        reason: NoOpReason::AlreadyApplied,
                    };
                }
                let affected = match op.region {
                    Some(region) => vec![TypedObjectId::Region(region)],
                    None => vec![],
                };
                let conflict = ConflictRecord::new(
                    ConflictKind::StructuralFieldCollision {
                        winner: env.id,
                        loser: prev_op,
                        field: FieldPath("tempo_segments".to_string()),
                    },
                    vec![env.id, prev_op],
                    affected,
                );
                let cid = conflict.id;
                self.conflicts.insert(conflict);
                OperationEffect::Conflicted { conflict: cid }
            }
            _ => OperationEffect::Applied,
        };
        self.tempo_segment_chain
            .entry(key.clone())
            .or_insert_with(WriteChain::new)
            .record(env.id, env.transaction, op.segment.clone());
        self.graph_apply_tempo_segment(op.region, &key.1, &op.segment);
        effect
    }

    /// Applies a tempo-segment overwrite (or removal) to the scoped map. A set
    /// on a region with no local map creates one; an empty, `initial`-less
    /// local map left behind by a removal normalizes back to `None` (an empty
    /// local map would shadow the score map instead of falling back to it).
    fn graph_apply_tempo_segment(
        &mut self,
        scope: Option<RegionId>,
        position: &MusicalPosition,
        segment: &Option<TempoSegment>,
    ) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        match scope {
            None => edit_tempo_map_segments(&mut score.tempo_map, position, segment),
            Some(region_id) => {
                let Some(region) = score.canvas.regions.iter_mut().find(|r| r.id == region_id)
                else {
                    return;
                };
                if segment.is_some() && region.local_tempo_map.is_none() {
                    region.local_tempo_map = Some(TempoMap::default());
                }
                if let Some(map) = region.local_tempo_map.as_mut() {
                    edit_tempo_map_segments(map, position, segment);
                }
                if region
                    .local_tempo_map
                    .as_ref()
                    .is_some_and(|map| map.initial.is_none() && map.segments.is_empty())
                {
                    region.local_tempo_map = None;
                }
            }
        }
    }

    /// Overwrites a staff instance's three inline layout advisories as a unit
    /// — an LWW *advisory* keyed by `staff_instance` (operation_catalog
    /// §SetStaffLayout): no conflicts; the latest write in canonical order
    /// wins. A present `instrument_override` must resolve to a live instrument
    /// under graph-aware reduction.
    fn set_staff_layout(
        &mut self,
        env: &OperationEnvelope,
        op: &SetStaffLayoutOp,
    ) -> OperationEffect {
        match self
            .objects
            .get(&TypedObjectId::StaffInstance(op.staff_instance))
        {
            None => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::TargetMissing,
                    },
                }
            }
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::TargetTombstoned,
                }
            }
            Some(ObjectState::Live) => {}
        }
        if self.graph.is_some() {
            if let Some(instrument) = op.instrument_override {
                if !matches!(
                    self.objects.get(&TypedObjectId::Instrument(instrument)),
                    Some(ObjectState::Live)
                ) {
                    return OperationEffect::NoOp {
                        reason: NoOpReason::PreconditionFailedUnderReduction {
                            reason: PreconditionFailureReason::TargetMissing,
                        },
                    };
                }
            }
        }
        let value: StaffLayoutValue = (
            op.instrument_override,
            op.staff_lines_override.clone(),
            op.visible,
        );
        self.staff_layout_chain
            .entry(op.staff_instance)
            .or_insert_with(WriteChain::new)
            .record(env.id, env.transaction, value.clone());
        self.graph_set_staff_layout(op.staff_instance, &value);
        OperationEffect::Applied
    }

    fn graph_set_staff_layout(&mut self, instance_id: StaffInstanceId, value: &StaffLayoutValue) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        for region in &mut score.canvas.regions {
            if let Some(instances) = region.content.staff_instances_mut() {
                if let Some(instance) = instances.iter_mut().find(|i| i.id == instance_id) {
                    instance.instrument_override = value.0;
                    instance.staff_lines_override = value.1.clone();
                    instance.visible = value.2;
                    return;
                }
            }
        }
    }

    /// `Some(effect)` when `obj` cannot be deleted (missing, idempotent
    /// re-delete, or non-empty); `None` with the resolved minter when the
    /// empty-only delete may proceed.
    fn delete_precondition(
        &self,
        obj: TypedObjectId,
        env: &OperationEnvelope,
        has_live_children: bool,
    ) -> Result<OperationId, OperationEffect> {
        match self.objects.get(&obj) {
            None => Err(OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetMissing,
                },
            }),
            Some(ObjectState::Tombstoned { .. }) => Err(OperationEffect::NoOp {
                reason: NoOpReason::AlreadyApplied,
            }),
            Some(ObjectState::Live) if has_live_children => Err(OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::ContainerNotEmpty,
                },
            }),
            Some(ObjectState::Live) => Ok(self.minted_by.get(&obj).copied().unwrap_or(env.id)),
        }
    }

    fn delete_region(&mut self, env: &OperationEnvelope, op: &DeleteRegionOp) -> OperationEffect {
        let robj = TypedObjectId::Region(op.region);
        let has_instances = self
            .region_instances
            .get(&op.region)
            .is_some_and(|s| !s.is_empty());
        let minted_by = match self.delete_precondition(robj, env, has_instances) {
            Ok(minter) => minter,
            Err(effect) => return effect,
        };
        self.objects.insert(
            robj,
            ObjectState::Tombstoned {
                deleted_by: env.id,
                minted_by,
            },
        );
        self.region_instances.remove(&op.region);
        self.staff_based_regions.remove(&op.region);
        self.graph_delete_region(op.region);
        OperationEffect::Applied
    }

    fn delete_staff_instance(
        &mut self,
        env: &OperationEnvelope,
        op: &DeleteStaffInstanceOp,
    ) -> OperationEffect {
        let iobj = TypedObjectId::StaffInstance(op.staff_instance);
        let has_voices = self
            .instance_voices
            .get(&op.staff_instance)
            .is_some_and(|s| !s.is_empty());
        let minted_by = match self.delete_precondition(iobj, env, has_voices) {
            Ok(minter) => minter,
            Err(effect) => return effect,
        };
        self.objects.insert(
            iobj,
            ObjectState::Tombstoned {
                deleted_by: env.id,
                minted_by,
            },
        );
        self.instance_voices.remove(&op.staff_instance);
        for set in self.region_instances.values_mut() {
            set.remove(&op.staff_instance);
        }
        self.graph_delete_staff_instance(op.staff_instance);
        OperationEffect::Applied
    }

    fn delete_voice(&mut self, env: &OperationEnvelope, op: &DeleteVoiceOp) -> OperationEffect {
        let vobj = TypedObjectId::Voice(op.voice);
        let has_events = self
            .voice_occupancy
            .get(&op.voice)
            .is_some_and(|e| !e.is_empty());
        let minted_by = match self.delete_precondition(vobj, env, has_events) {
            Ok(minter) => minter,
            Err(effect) => return effect,
        };
        self.objects.insert(
            vobj,
            ObjectState::Tombstoned {
                deleted_by: env.id,
                minted_by,
            },
        );
        self.voice_occupancy.remove(&op.voice);
        for set in self.instance_voices.values_mut() {
            set.remove(&op.voice);
        }
        self.graph_delete_voice(op.voice);
        OperationEffect::Applied
    }

    // --- Group 3 graph mutations (reduce_onto only; no-op when graph is None). --

    fn graph_create_region(&mut self, region: &epiphany_core::Region) {
        if let Some(score) = self.graph.as_mut() {
            score.canvas.regions.push(region.clone());
        }
    }

    fn graph_create_staff_instance(&mut self, region: RegionId, instance: &StaffInstance) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        if let Some(region) = score.canvas.regions.iter_mut().find(|r| r.id == region) {
            let staff = instance.staff;
            if let Some(instances) = region.content.staff_instances_mut() {
                instances.push(instance.clone());
            }
            // Keep the region's staff extent listing exactly its manifested
            // staves (Chapter 5 RegionExtents).
            if !region.staff_extent.staves.contains(&staff) {
                region.staff_extent.staves.push(staff);
            }
        }
    }

    fn graph_create_voice(&mut self, staff_instance: StaffInstanceId, voice: &Voice) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        for region in &mut score.canvas.regions {
            if let Some(instances) = region.content.staff_instances_mut() {
                if let Some(instance) = instances.iter_mut().find(|i| i.id == staff_instance) {
                    instance.voices.push(voice.clone());
                    return;
                }
            }
        }
    }

    fn graph_delete_region(&mut self, region: RegionId) {
        if let Some(score) = self.graph.as_mut() {
            score.canvas.regions.retain(|r| r.id != region);
        }
    }

    fn graph_delete_staff_instance(&mut self, staff_instance: StaffInstanceId) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        for region in &mut score.canvas.regions {
            let Some(instances) = region.content.staff_instances_mut() else {
                continue;
            };
            let Some(removed_staff) = instances
                .iter()
                .find(|i| i.id == staff_instance)
                .map(|i| i.staff)
            else {
                continue;
            };
            instances.retain(|i| i.id != staff_instance);
            // Drop the staff from the extent if no remaining instance manifests
            // it (Chapter 5 RegionExtents).
            let still_used = instances.iter().any(|i| i.staff == removed_staff);
            if !still_used {
                region.staff_extent.staves.retain(|s| *s != removed_staff);
            }
        }
    }

    fn graph_delete_voice(&mut self, voice: VoiceId) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        for region in &mut score.canvas.regions {
            if let Some(instances) = region.content.staff_instances_mut() {
                for instance in instances {
                    instance.voices.retain(|v| v.id != voice);
                }
            }
        }
    }

    fn change_region_time_model(
        &mut self,
        env: &OperationEnvelope,
        op: &crate::payload::ChangeRegionTimeModelOp,
    ) -> OperationEffect {
        if let Some(winner) = self.region_migrator.get(&op.region).copied() {
            // Concurrent same-target migrations conflict. A causally-later
            // migration is an intentional second structural change and is
            // evaluated against the graph produced by the first.
            if !self.concurrent(env.id, winner) {
                self.migrated_regions.insert(op.region);
            } else {
                let conflict = ConflictRecord::new(
                    ConflictKind::StructuralFieldCollision {
                        winner,
                        loser: env.id,
                        field: FieldPath("time_model".to_string()),
                    },
                    vec![env.id, winner],
                    vec![TypedObjectId::Region(op.region)],
                );
                let cid = conflict.id;
                self.conflicts.insert(conflict);
                return OperationEffect::Conflicted { conflict: cid };
            }
        }
        let mut incompatible_events: BTreeSet<EventId> =
            op.declared_incompatible.iter().copied().collect();
        let mut graph_region_index = None;
        if let Some(score) = self.graph.as_ref() {
            let Some(region_index) = score
                .canvas
                .regions
                .iter()
                .position(|region| region.id == op.region)
            else {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::TargetMissing,
                    },
                };
            };
            graph_region_index = Some(region_index);
            let region = &score.canvas.regions[region_index];
            let event_ids: Vec<EventId> = region
                .staff_instances()
                .iter()
                .flat_map(|instance| &instance.voices)
                .flat_map(|voice| voice.events.iter().copied())
                .collect();

            for event_id in &event_ids {
                let Some(event) = score.events.get(*event_id) else {
                    incompatible_events.insert(*event_id);
                    continue;
                };
                let compatible = match &op.new_time_model {
                    RegionTimeModel::Metric(_) => matches!(
                        (event.position(), event.duration()),
                        (EventPosition::Musical(_), EventDuration::Musical(_))
                    ),
                    RegionTimeModel::Proportional(_) => matches!(
                        (event.position(), event.duration()),
                        (EventPosition::WallClock(_), EventDuration::WallClock(_))
                    ),
                    RegionTimeModel::Aleatoric(_) => true,
                };
                if !compatible {
                    incompatible_events.insert(*event_id);
                }
            }

            if let crate::payload::PositionRemapping::Reassign(remapping) = &op.remapping {
                let mapped: BTreeSet<EventId> = remapping.iter().map(|(event, _)| *event).collect();
                incompatible_events.extend(
                    event_ids
                        .iter()
                        .filter(|event| !mapped.contains(event))
                        .copied(),
                );
                if matches!(op.new_time_model, RegionTimeModel::Proportional(_)) {
                    // Reassign carries musical positions in the current
                    // prototype schema, so it cannot satisfy a proportional
                    // region's wall-clock coordinate discipline.
                    incompatible_events.extend(event_ids);
                }
            }
        }

        if !incompatible_events.is_empty() {
            let incompatible: Vec<TypedObjectId> = incompatible_events
                .into_iter()
                .map(TypedObjectId::Event)
                .collect();
            let mut affected = vec![TypedObjectId::Region(op.region)];
            affected.extend(incompatible.iter().copied());
            let conflict = ConflictRecord::new(
                ConflictKind::TimeModelMigrationFailure {
                    region: op.region,
                    incompatible_events: incompatible,
                },
                vec![env.id],
                affected,
            );
            let cid = conflict.id;
            self.conflicts.insert(conflict);
            return OperationEffect::Conflicted { conflict: cid };
        }

        if let Some(region_index) = graph_region_index {
            let score = self
                .graph
                .as_mut()
                .expect("a graph region index implies graph-aware reduction");
            if let crate::payload::PositionRemapping::Reassign(remapping) = &op.remapping {
                for (event, position) in remapping {
                    if let Some(value) = score.events.get_mut(*event) {
                        value.set_position(EventPosition::Musical(position.clone()));
                    }
                    for placements in self.voice_occupancy.values_mut() {
                        if let Some((stored_position, _, _)) = placements
                            .iter_mut()
                            .find(|(_, _, stored_event)| stored_event == event)
                        {
                            *stored_position = position.clone();
                        }
                    }
                }
            }
            // The value-typed payload (v1) carries the real target model, so the
            // region adopts it directly rather than rebuilding a default from a
            // discriminator tag.
            let region = &mut score.canvas.regions[region_index];
            region.time_model = op.new_time_model.clone();
        }
        self.migrated_regions.insert(op.region);
        self.region_migrator.insert(op.region, env.id);
        OperationEffect::Applied
    }

    fn resolve_conflict(
        &mut self,
        env: &OperationEnvelope,
        op: &crate::payload::ResolveConflictPayload,
    ) -> OperationEffect {
        use crate::conflict::ConflictResolutionState as RS;
        let existing_state = self
            .conflicts
            .get_mut(op.target)
            .map(|r| r.resolution_state);
        match existing_state {
            None => OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetMissing,
                },
            },
            Some(RS::Unresolved) => {
                if let Some(rec) = self.conflicts.get_mut(op.target) {
                    // ResolutionAction::Dismiss selects the Dismissed state;
                    // every other action selects Resolved with that action
                    // applied (Pass 11, item 2.5).
                    rec.resolution_state = match op.action {
                        ResolutionAction::Dismiss => RS::Dismissed { by: env.id },
                        action => RS::Resolved { by: env.id, action },
                    };
                }
                OperationEffect::Applied
            }
            Some(RS::Resolved { by, action }) => {
                if action == op.action {
                    OperationEffect::NoOp {
                        reason: NoOpReason::AlreadyApplied,
                    }
                } else {
                    // Differing concurrent resolution → meta-conflict. The
                    // earlier resolve stands (its action materialized), so it
                    // is the record's winner; this op is the loser, and both
                    // resolvers are named as causes ("at least two for a true
                    // conflict", Chapter 6 §Conflict Records). A conflict
                    // record has no TypedObjectId, so `affected_objects`
                    // cannot name the contested conflict and stays empty.
                    let conflict = ConflictRecord::new(
                        ConflictKind::StructuralFieldCollision {
                            winner: by,
                            loser: env.id,
                            field: FieldPath("conflict_resolution".to_string()),
                        },
                        vec![by, env.id],
                        vec![],
                    );
                    let cid = conflict.id;
                    self.conflicts.insert(conflict);
                    OperationEffect::Conflicted { conflict: cid }
                }
            }
            Some(RS::Dismissed { .. }) => OperationEffect::NoOp {
                reason: NoOpReason::AlreadyApplied,
            },
        }
    }

    /// The recorded effect of a `ResolveEquivocation` (operation_catalog
    /// §"ResolveEquivocation"). The slot promotion itself happened in the
    /// set-level pre-pass ([`Reducer::run`] step 1b); this only records the
    /// per-resolve verdict, mirroring [`Reducer::resolve_conflict`]'s
    /// discipline: the governing (earliest-in-canonical-order) resolve is
    /// `Applied`; a later resolve naming the same candidate reduces
    /// idempotently; a later valid resolve naming a differing candidate is a
    /// `StructuralFieldCollision` meta-conflict on `equivocation_resolution`.
    /// A resolve whose target is not an equivocated slot, or whose chosen is
    /// not among the slot's candidates, is a precondition no-op
    /// (`TargetMissing` — the named target/candidate pair does not exist).
    fn resolve_equivocation(
        &mut self,
        env: &OperationEnvelope,
        op: &crate::payload::ResolveEquivocationPayload,
    ) -> OperationEffect {
        let precondition_noop = OperationEffect::NoOp {
            reason: NoOpReason::PreconditionFailedUnderReduction {
                reason: PreconditionFailureReason::TargetMissing,
            },
        };
        match self.equivocation_resolutions.get(&op.target) {
            // No governing resolve exists for the target: it is absent, holds
            // a Single slot, or is equivocated with no valid resolve — in
            // every case this resolve's precondition ("an Equivocated slot for
            // `target` with `chosen` among its candidates") failed, or it
            // would have governed.
            None => precondition_noop,
            Some((winner, chosen)) => {
                if env.id == *winner {
                    OperationEffect::Applied
                } else if op.chosen == *chosen {
                    // A later resolve naming the same candidate: idempotent.
                    OperationEffect::NoOp {
                        reason: NoOpReason::AlreadyApplied,
                    }
                } else if !self
                    .op_set
                    .slot(op.target)
                    .is_some_and(|slot| slot.candidates().any(|c| c == op.chosen))
                {
                    // A differing `chosen` that never named a real candidate
                    // is a failed precondition, not a contested resolution.
                    precondition_noop
                } else {
                    // Two valid resolves naming differing candidates: the
                    // governing (earlier) resolve stands as the record's
                    // winner; this op is the loser, both named as causes. A
                    // slot is not a TypedObjectId, so `affected_objects`
                    // stays empty (the ResolveConflict discipline).
                    let conflict = ConflictRecord::new(
                        ConflictKind::StructuralFieldCollision {
                            winner: *winner,
                            loser: env.id,
                            field: FieldPath("equivocation_resolution".to_string()),
                        },
                        vec![*winner, env.id],
                        vec![],
                    );
                    let cid = conflict.id;
                    self.conflicts.insert(conflict);
                    OperationEffect::Conflicted { conflict: cid }
                }
            }
        }
    }

    /// Forward compensating undo (operation_catalog §UndoTransaction): the
    /// minted-object tombstoning pass plus, per this revision, the
    /// value-restoration pass over every LWW write chain the target
    /// transaction wrote. `StrictInverse` refuses the whole undo if *either*
    /// part fails; `BestEffort` compensates what it cleanly can. A fully
    /// clean compensation is `Applied`; `AppliedWithRepair` carries only the
    /// tombstone repairs from minted objects.
    fn undo_transaction(
        &mut self,
        env: &OperationEnvelope,
        op: &UndoTransactionPayload,
    ) -> OperationEffect {
        let targets = self.tx_minted.get(&op.target).cloned().unwrap_or_default();
        let (restorations, superseded) = self.collect_restorations(op.target, &targets);
        if targets.is_empty() && restorations.is_empty() && superseded.is_empty() {
            // The transaction minted nothing and overwrote nothing this
            // reduction knows of (unknown, rolled back, or all its written
            // keys are gone): nothing to compensate.
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetMissing,
                },
            };
        }
        match op.policy {
            UndoPolicy::StrictInverse | UndoPolicy::Cascade => {
                // A minted target already tombstoned: strict undo conflicts
                // (the pre-existing minted-object discipline).
                if let Some(stuck) = targets
                    .iter()
                    .find(|t| !matches!(self.objects.get(t), Some(ObjectState::Live)))
                    .copied()
                {
                    let conflict = ConflictRecord::new(
                        ConflictKind::TombstonedTarget {
                            target: stuck,
                            operation: env.id,
                        },
                        vec![env.id],
                        vec![stuck],
                    );
                    let cid = conflict.id;
                    self.conflicts.insert(conflict);
                    return OperationEffect::Conflicted { conflict: cid };
                }
                // A minted staff still manifested by a live instance, or a
                // minted time signature still referenced by a surviving meter
                // change: tombstoning it would strand the reference
                // (operation_catalog §CreateStaff undo semantics).
                if let Some((blocked, referencer)) = targets
                    .iter()
                    .find_map(|t| self.undo_strand_block(t, &targets, &restorations))
                {
                    let conflict = ConflictRecord::new(
                        ConflictKind::TransactionConflict {
                            transaction: op.target,
                            failed_members: vec![env.id],
                        },
                        vec![env.id],
                        vec![blocked, referencer],
                    );
                    let cid = conflict.id;
                    self.conflicts.insert(conflict);
                    return OperationEffect::Conflicted { conflict: cid };
                }
                // A written key superseded by a later writer: strict undo
                // refuses the whole compensation, naming the undo and the
                // (canonically first) superseding writer.
                if let Some(by) = superseded.first().copied() {
                    let conflict = ConflictRecord::new(
                        ConflictKind::TransactionConflict {
                            transaction: op.target,
                            failed_members: vec![env.id],
                        },
                        vec![env.id, by],
                        vec![],
                    );
                    let cid = conflict.id;
                    self.conflicts.insert(conflict);
                    return OperationEffect::Conflicted { conflict: cid };
                }
                // Contract pin 9c.3, `StrictInverse`/`Cascade`: the WHOLE
                // restoration set, evaluated TOGETHER — never
                // per-restoration — must leave invariant 20 clean. A
                // restoration reinstating a prior grid or meter change
                // breaks agreement/boundary exactly as a forward write
                // does.
                if self.aggregate_restorations_violate_invariant20(&restorations) {
                    let conflict = ConflictRecord::new(
                        ConflictKind::TransactionConflict {
                            transaction: op.target,
                            failed_members: vec![env.id],
                        },
                        vec![env.id],
                        vec![],
                    );
                    let cid = conflict.id;
                    self.conflicts.insert(conflict);
                    return OperationEffect::Conflicted { conflict: cid };
                }
                let repairs = self.tombstone_undo_targets(env, &targets);
                self.apply_restorations(env, restorations);
                if repairs.is_empty() {
                    OperationEffect::Applied
                } else {
                    OperationEffect::AppliedWithRepair { repairs }
                }
            }
            UndoPolicy::BestEffort => {
                // Tombstone the still-live, non-stranding mints; restore the
                // still-last-written keys; skip the rest.
                let tombstonable: Vec<TypedObjectId> = targets
                    .iter()
                    .filter(|t| matches!(self.objects.get(t), Some(ObjectState::Live)))
                    .filter(|t| self.undo_strand_block(t, &targets, &restorations).is_none())
                    .copied()
                    .collect();
                let repairs = self.tombstone_undo_targets(env, &tombstonable);
                // Contract pin 9c.3, `BestEffort`: the canonical-order
                // greedy applies the MAXIMAL safe subset of grid/meter-
                // change restorations (never a naive per-restoration
                // filter evaluated independently of the others already
                // admitted) — see `select_invariant20_safe_restorations`.
                let safe_restorations = self.select_invariant20_safe_restorations(restorations);
                self.apply_restorations(env, safe_restorations);
                if repairs.is_empty() {
                    OperationEffect::Applied
                } else {
                    OperationEffect::AppliedWithRepair { repairs }
                }
            }
        }
    }

    /// Tombstones the minted objects of an undone transaction and materializes
    /// the graph-side removals, returning the `CascadeDeleted` repair records.
    fn tombstone_undo_targets(
        &mut self,
        env: &OperationEnvelope,
        targets: &[TypedObjectId],
    ) -> Vec<RepairRecord> {
        let mut repairs = Vec::new();
        // Each tombstoned event's voice, captured BEFORE the graph tombstone
        // removes it from `voice_occupancy` — the containment-proximity key for
        // the re-anchoring reasons below (mirrors `delete_event`).
        let event_voices: Vec<(TypedObjectId, Option<VoiceId>)> = targets
            .iter()
            .filter(|t| matches!(t, TypedObjectId::Event(_)))
            .map(|t| {
                let TypedObjectId::Event(id) = t else {
                    unreachable!()
                };
                let voice = self
                    .voice_occupancy
                    .iter()
                    .find_map(|(voice, events)| {
                        events.iter().find(|(_, _, e)| e == id).map(|_| *voice)
                    })
                    .or_else(|| {
                        self.graph
                            .as_ref()
                            .and_then(|score| score.events.get(*id))
                            .map(Event::voice)
                    });
                (*t, voice)
            })
            .collect();
        for t in targets {
            let minter = self.minted_by.get(t).copied().unwrap_or(env.id);
            self.objects.insert(
                *t,
                ObjectState::Tombstoned {
                    deleted_by: env.id,
                    minted_by: minter,
                },
            );
            repairs.push(RepairRecord {
                kind: RepairKind::CascadeDeleted,
                target: *t,
            });
        }
        repairs.extend(self.materialize_graph_tombstones(env, targets));
        // P13-D1: mirror the graph re-anchoring in the LEDGER. The graph side
        // (`materialize_graph_delete`, run above) silently re-anchors or
        // cascade-deletes a structure whose anchor event was undo-tombstoned,
        // on the standing assumption that `reanchor_for_tombstone` records the
        // repair and updates `objects`. The direct-delete path pairs the two;
        // the undo path historically ran only the graph half, leaving an
        // orphaned structure Live in `objects` with no RepairRecord — a Ch6
        // same-step-recording MUST unmet for undo-driven tombstones. Running
        // the ledger half here brings the two into agreement (the same
        // `min`-survivor rule, so graph and ledger converge on existence and
        // target). Every target is already tombstoned in `objects` above, so
        // `surviving_endpoints` sees the full undo, and the liveness guard in
        // `reanchor_for_tombstone` skips the target-structures themselves.
        for (ev, voice) in event_voices {
            self.reanchor_for_tombstone(env, ev, &mut repairs, voice);
        }
        repairs
    }

    /// Genesis tranche G3b (contract pin 10.5): whether the OWNER of an
    /// owned strand-guard surface licenses that surface to block — it must
    /// be `Live` and not itself one of the undone transaction's own
    /// `targets` (a same-transaction teardown strands nothing, since the
    /// owner is going away too). Shared by all seven owned rows of the
    /// `Measure` guard's surfaces (six always-owned classes plus
    /// region-scoped tempo segments), so mutations M61 (drop the `targets`
    /// conjunct) and M62 (drop the `Live` conjunct) each target this ONE
    /// function rather than seven separate call sites.
    fn owner_licenses_block(&self, owner: TypedObjectId, targets: &[TypedObjectId]) -> bool {
        !targets.contains(&owner) && matches!(self.objects.get(&owner), Some(ObjectState::Live))
    }

    /// `Some((blocked, referencer))` when tombstoning `target` under undo
    /// would strand a live reference: a minted `Staff` still manifested by a
    /// live staff instance (operation_catalog §CreateStaff), a minted
    /// `TimeSignature` still referenced by a meter change that survives the
    /// restoration pass, a minted `StaffGroup` still named by a live
    /// `Staff.group`, a minted `AnalysisLayer` still named by a live
    /// `ViewDefinition.active_layers`, or a minted `Instrument` still named by
    /// a live `Staff.instrument` (contract
    /// `spec/CONTRACT_GENESIS_G3A_UNDO_REPAIR.md` pin A2). References held by
    /// objects the same undo tombstones do not block.
    fn undo_strand_block(
        &self,
        target: &TypedObjectId,
        targets: &[TypedObjectId],
        restorations: &[ValueRestoration],
    ) -> Option<(TypedObjectId, TypedObjectId)> {
        match target {
            TypedObjectId::Staff(staff) => {
                self.instance_staff
                    .iter()
                    .find_map(|(instance, manifested)| {
                        let iobj = TypedObjectId::StaffInstance(*instance);
                        (manifested == staff
                            && !targets.contains(&iobj)
                            && matches!(self.objects.get(&iobj), Some(ObjectState::Live)))
                        .then_some((*target, iobj))
                    })
            }
            TypedObjectId::TimeSignature(id) => {
                self.meter_change_chain
                    .iter()
                    .find_map(|((region, position), chain)| {
                        // The prospective post-undo value at this key: the
                        // restoration's value where one applies, else the
                        // chain's current value.
                        let prospective: Option<MeterChange> = restorations
                            .iter()
                            .find_map(|restoration| match restoration {
                                ValueRestoration::MeterChange {
                                    region: r,
                                    position: p,
                                    value,
                                } if r == region && p == position => Some(value.clone()),
                                _ => None,
                            })
                            .unwrap_or_else(|| chain.current().cloned().flatten());
                        prospective.and_then(|meter| {
                            (meter.time_signature == *id)
                                .then_some((*target, TypedObjectId::Region(*region)))
                        })
                    })
                    // Contract pin 9c.3 / `spec/CONTRACT_GENESIS_G3B_MEASURE.md`
                    // §0 "six boundary crossings" #1 / M48: this hole exists
                    // TODAY, before G3b — a minted `TimeSignature` still named
                    // by a live `Measure.time_signature` was not checked.
                    // `measure_values` is an immutable value map (no modify
                    // operation ever rewrites a live measure's declared
                    // signature), so no restoration-awareness applies here —
                    // ungated exactly like the StaffGroup/AnalysisLayer/
                    // Instrument guards below.
                    .or_else(|| {
                        self.measure_values
                            .iter()
                            .find_map(|(measure_id, (_, measure))| {
                                let mobj = TypedObjectId::Measure(*measure_id);
                                (measure.time_signature == Some(*id)
                                    && !targets.contains(&mobj)
                                    && matches!(self.objects.get(&mobj), Some(ObjectState::Live)))
                                .then_some((*target, mobj))
                            })
                    })
            }
            // Genesis tranche G3a undo repair (pins A2-A6): these three
            // guards read the carried-value maps, not `self.graph`, and are
            // deliberately ungated (pin A3) — the ledger knows a live staff
            // or view names this referent regardless of graph presence.
            // `restorations` is not consulted (pin A6): none of
            // `Staff.group`, `Staff.instrument`, or
            // `ViewDefinition.active_layers` has a modify operation, so there
            // is no write chain whose restoration could change the
            // prospective post-undo value.
            TypedObjectId::StaffGroup(group) => {
                self.staff_values.iter().find_map(|(staff_id, staff)| {
                    let sobj = TypedObjectId::Staff(*staff_id);
                    (staff.group == Some(*group)
                        && !targets.contains(&sobj)
                        && matches!(self.objects.get(&sobj), Some(ObjectState::Live)))
                    .then_some((*target, sobj))
                })
            }
            TypedObjectId::AnalysisLayer(layer) => {
                self.view_values.iter().find_map(|(view_id, view)| {
                    let vobj = TypedObjectId::View(*view_id);
                    (view.active_layers.contains(layer)
                        && !targets.contains(&vobj)
                        && matches!(self.objects.get(&vobj), Some(ObjectState::Live)))
                    .then_some((*target, vobj))
                })
            }
            TypedObjectId::Instrument(instrument) => {
                self.staff_values.iter().find_map(|(staff_id, staff)| {
                    let sobj = TypedObjectId::Staff(*staff_id);
                    (staff.instrument == *instrument
                        && !targets.contains(&sobj)
                        && matches!(self.objects.get(&sobj), Some(ObjectState::Live)))
                    .then_some((*target, sobj))
                })
            }
            // Genesis tranche G3b (`spec/CONTRACT_GENESIS_G3B_MEASURE.md` pin
            // 10.2/10.5): the Measure strand guard, across all SEVEN inbound
            // surface classes. This CANNOT be written against `self.structures`
            // — that index is event-only by construction (the base-seed walk
            // filters through `anchor_event_refs`, which drops every
            // `Measure`/`Region`/`WallClock` anchor; see its "Non-event
            // anchorings ... contribute no entry" comment above). Six of the
            // seven surfaces are always OWNED (the referencing object must be
            // `Live` and not itself one of `targets`); the seventh
            // (score-level `tempo_segment_chain` entries, keyed `None`) is
            // genuinely ownerless and blocks on the reference itself. Five
            // surfaces are real `WriteChain`s and so are restoration-aware —
            // the prospective *post-undo* value governs, mirroring the
            // `TimeSignature` arm above; `repeat_values` and `measure_values`
            // are immutable value maps (N/A for restoration — nothing ever
            // rewrites a live repeat's or measure's anchors in place).
            TypedObjectId::Measure(_) => {
                // 1. Spanner (`cross_cutting_modify_chain`) — restoration-aware,
                // owned by the cross-cutting structure itself.
                self.cross_cutting_modify_chain
                    .iter()
                    .find_map(|(sid, chain)| {
                        let names = prospective_references_target(
                            restorations,
                            |restoration| match restoration {
                                ValueRestoration::CrossCutting { id: rid, value } if rid == sid => {
                                    Some(value.clone())
                                }
                                _ => None,
                            },
                            chain.current().cloned(),
                            |value: &CrossCuttingValue| value.anchor_object_refs().contains(target),
                        );
                        (names && self.owner_licenses_block(*sid, targets))
                            .then_some((*target, *sid))
                    })
                    // 2. Repeat (`repeat_values`) — immutable value map, N/A
                    // for restoration; owned by the repeat structure.
                    .or_else(|| {
                        self.repeat_values.iter().find_map(|(rid, repeat)| {
                            let robj = TypedObjectId::RepeatStructure(*rid);
                            let names = anchor_object_refs(repeat.anchor_sites()).contains(target);
                            (names && self.owner_licenses_block(robj, targets))
                                .then_some((*target, robj))
                        })
                    })
                    // 3. Another measure's `start` (`measure_values`) —
                    // immutable value map, N/A for restoration; owned by that
                    // measure.
                    .or_else(|| {
                        self.measure_values.iter().find_map(|(mid, (_, measure))| {
                            let mobj = TypedObjectId::Measure(*mid);
                            let names = anchor_object_refs([&measure.start]).contains(target);
                            (names && self.owner_licenses_block(mobj, targets))
                                .then_some((*target, mobj))
                        })
                    })
                    // 4. Meter change (`meter_change_chain`) — restoration-
                    // aware, owned by the enclosing region.
                    .or_else(|| {
                        self.meter_change_chain
                            .iter()
                            .find_map(|((region, position), chain)| {
                                let names = prospective_references_target(
                                    restorations,
                                    |restoration| match restoration {
                                        ValueRestoration::MeterChange {
                                            region: r,
                                            position: p,
                                            value,
                                        } if r == region && p == position => Some(value.clone()),
                                        _ => None,
                                    },
                                    chain.current().cloned().flatten(),
                                    |meter: &MeterChange| {
                                        anchor_object_refs([&meter.anchor]).contains(target)
                                    },
                                );
                                let robj = TypedObjectId::Region(*region);
                                (names && self.owner_licenses_block(robj, targets))
                                    .then_some((*target, robj))
                            })
                    })
                    // 5. System break (`break_chain`) — restoration-aware,
                    // owned by the enclosing region. `present == false` means
                    // no break is actually asserted at this key (mirroring
                    // `MeterChange`'s `None` meaning "no active change"), so
                    // it does not block even if the withdrawn anchor named
                    // the measure.
                    .or_else(|| {
                        self.break_chain
                            .iter()
                            .find_map(|((region, position), chain)| {
                                let names = prospective_references_target(
                                    restorations,
                                    |restoration| match restoration {
                                        ValueRestoration::SystemBreak {
                                            region: r,
                                            position: p,
                                            predecessor,
                                        } if r == region && p == position => {
                                            Some(predecessor.clone().map(Predecessor::into_value))
                                        }
                                        _ => None,
                                    },
                                    chain.current().cloned(),
                                    |(anchor, present): &(TimeAnchor, bool)| {
                                        *present && anchor_object_refs([anchor]).contains(target)
                                    },
                                );
                                let robj = TypedObjectId::Region(*region);
                                (names && self.owner_licenses_block(robj, targets))
                                    .then_some((*target, robj))
                            })
                    })
                    // 6. Page break (`page_break_chain`) — same shape as (5).
                    .or_else(|| {
                        self.page_break_chain
                            .iter()
                            .find_map(|((region, position), chain)| {
                                let names = prospective_references_target(
                                    restorations,
                                    |restoration| match restoration {
                                        ValueRestoration::PageBreak {
                                            region: r,
                                            position: p,
                                            predecessor,
                                        } if r == region && p == position => {
                                            Some(predecessor.clone().map(Predecessor::into_value))
                                        }
                                        _ => None,
                                    },
                                    chain.current().cloned(),
                                    |(anchor, present): &(TimeAnchor, bool)| {
                                        *present && anchor_object_refs([anchor]).contains(target)
                                    },
                                );
                                let robj = TypedObjectId::Region(*region);
                                (names && self.owner_licenses_block(robj, targets))
                                    .then_some((*target, robj))
                            })
                    })
                    // 7. Tempo segment (`tempo_segment_chain`) — restoration-
                    // aware, checked at BOTH anchor sites (`start` and
                    // `end`). Keyed `(Option<RegionId>, MusicalPosition)`:
                    // `Some(region)` is owned exactly like the other six;
                    // `None` is score-level and genuinely ownerless — there is
                    // no object to test liveness against, so the guard blocks
                    // on the prospective reference itself. That prospective
                    // computation (restoration override, else chain-current)
                    // already IS the "exempt a write belonging to the undone
                    // transaction" rule: if `tx` last-wrote this key, its
                    // restoration (chain-predecessor) governs instead of the
                    // about-to-be-superseded current value.
                    .or_else(|| {
                        self.tempo_segment_chain
                            .iter()
                            .find_map(|((scope, position), chain)| {
                                let names = prospective_references_target(
                                    restorations,
                                    |restoration| match restoration {
                                        ValueRestoration::TempoSegment {
                                            region: r,
                                            position: p,
                                            value,
                                        } if r == scope && p == position => Some(value.clone()),
                                        _ => None,
                                    },
                                    chain.current().cloned().flatten(),
                                    |segment: &TempoSegment| {
                                        let mut sites: Vec<&TimeAnchor> = vec![&segment.start];
                                        if let Some(end) = &segment.end {
                                            sites.push(end);
                                        }
                                        anchor_object_refs(sites).contains(target)
                                    },
                                );
                                match scope {
                                    Some(region) => {
                                        let robj = TypedObjectId::Region(*region);
                                        (names && self.owner_licenses_block(robj, targets))
                                            .then_some((*target, robj))
                                    }
                                    None => names.then_some((*target, *target)),
                                }
                            })
                    })
            }
            _ => None,
        }
    }

    /// Walks every write chain and collects, for the target transaction: the
    /// keys still last-written by it (with their chain-predecessor
    /// restorations) and the operations that superseded its other writes
    /// (sorted, deduplicated). Keys whose owning object is tombstoned — or is
    /// itself one of the transaction's mints, about to be tombstoned by this
    /// undo — are skipped entirely: there is no live slot to restore.
    fn collect_restorations(
        &self,
        tx: TransactionId,
        targets: &[TypedObjectId],
    ) -> (Vec<ValueRestoration>, Vec<OperationId>) {
        let mut restorations = Vec::new();
        let mut superseded: Vec<OperationId> = Vec::new();
        // A `TransposeInterval` writes a pitch's value and its engraved spelling
        // set as one act, so they undo as one unit (P13-S3). If either half was
        // superseded, neither is restored: `BestEffort` must not put the pitch
        // back while leaving a spelling written for the pitch it used to be.
        // (`StrictInverse` refuses outright on any supersession, so this only
        // bites for `BestEffort`.)
        let mut superseded_pitches: std::collections::BTreeSet<PitchId> =
            std::collections::BTreeSet::new();
        let slot_live = |obj: TypedObjectId| {
            matches!(self.objects.get(&obj), Some(ObjectState::Live)) && !targets.contains(&obj)
        };

        for (event, chain) in &self.event_modify_chain {
            if !slot_live(TypedObjectId::Event(*event)) {
                continue;
            }
            match chain.undo_verdict(tx) {
                ChainUndoVerdict::NotWritten => {}
                ChainUndoVerdict::Superseded { by } => superseded.push(by),
                ChainUndoVerdict::Restore(predecessor) => {
                    restorations.push(ValueRestoration::Event {
                        event: *event,
                        value: predecessor.map(Predecessor::into_value),
                    })
                }
            }
        }
        for (pitch, chain) in &self.pitch_modify_chain {
            if !slot_live(TypedObjectId::Pitch(*pitch)) {
                continue;
            }
            match chain.undo_verdict(tx) {
                ChainUndoVerdict::NotWritten => {}
                ChainUndoVerdict::Superseded { by } => {
                    superseded.push(by);
                    superseded_pitches.insert(*pitch);
                }
                ChainUndoVerdict::Restore(predecessor) => {
                    restorations.push(ValueRestoration::Pitch {
                        pitch: *pitch,
                        value: predecessor.map(Predecessor::into_value),
                    })
                }
            }
        }
        for (pitch, chain) in &self.respell_chain {
            if !slot_live(TypedObjectId::Pitch(*pitch)) {
                continue;
            }
            match chain.undo_verdict(tx) {
                ChainUndoVerdict::NotWritten => {}
                ChainUndoVerdict::Superseded { by } => superseded.push(by),
                ChainUndoVerdict::Restore(predecessor) => {
                    restorations.push(ValueRestoration::Spelling {
                        pitch: *pitch,
                        predecessor,
                    })
                }
            }
        }
        for (pitch, chain) in &self.engraved_spelling_chain {
            if !slot_live(TypedObjectId::Pitch(*pitch)) {
                continue;
            }
            match chain.undo_verdict(tx) {
                ChainUndoVerdict::NotWritten => {}
                ChainUndoVerdict::Superseded { by } => {
                    superseded.push(by);
                    superseded_pitches.insert(*pitch);
                }
                ChainUndoVerdict::Restore(predecessor) => {
                    restorations.push(ValueRestoration::EngravedSpellings {
                        pitch: *pitch,
                        predecessor,
                    })
                }
            }
        }

        for (id, chain) in &self.cross_cutting_modify_chain {
            if !slot_live(*id) {
                continue;
            }
            match chain.undo_verdict(tx) {
                ChainUndoVerdict::NotWritten => {}
                ChainUndoVerdict::Superseded { by } => superseded.push(by),
                ChainUndoVerdict::Restore(predecessor) => {
                    restorations.push(ValueRestoration::CrossCutting {
                        id: *id,
                        value: predecessor.map(Predecessor::into_value),
                    })
                }
            }
        }
        match self.metadata_chain.undo_verdict(tx) {
            ChainUndoVerdict::NotWritten => {}
            ChainUndoVerdict::Superseded { by } => superseded.push(by),
            ChainUndoVerdict::Restore(predecessor) => {
                restorations.push(ValueRestoration::Metadata {
                    value: predecessor.map(Predecessor::into_value),
                })
            }
        }
        // Genesis tranche G2a (contract pin 7): mirror `metadata_chain` for
        // the two new score-singleton settings chains.
        match self.canvas_layout_defaults_chain.undo_verdict(tx) {
            ChainUndoVerdict::NotWritten => {}
            ChainUndoVerdict::Superseded { by } => superseded.push(by),
            ChainUndoVerdict::Restore(predecessor) => {
                restorations.push(ValueRestoration::CanvasLayoutDefaults {
                    value: predecessor.map(Predecessor::into_value),
                })
            }
        }
        match self.spelling_precedence_chain.undo_verdict(tx) {
            ChainUndoVerdict::NotWritten => {}
            ChainUndoVerdict::Superseded { by } => superseded.push(by),
            ChainUndoVerdict::Restore(predecessor) => {
                restorations.push(ValueRestoration::SpellingPrecedence {
                    value: predecessor.map(Predecessor::into_value),
                })
            }
        }
        // Genesis tranche G2b (contract pin 5): mirror the same shape.
        match self.tuning_context_chain.undo_verdict(tx) {
            ChainUndoVerdict::NotWritten => {}
            ChainUndoVerdict::Superseded { by } => superseded.push(by),
            ChainUndoVerdict::Restore(predecessor) => {
                restorations.push(ValueRestoration::TuningContext {
                    value: predecessor.map(Predecessor::into_value),
                })
            }
        }
        for (region, chain) in &self.metric_grid_chain {
            if !slot_live(TypedObjectId::Region(*region)) {
                continue;
            }
            match chain.undo_verdict(tx) {
                ChainUndoVerdict::NotWritten => {}
                ChainUndoVerdict::Superseded { by } => superseded.push(by),
                ChainUndoVerdict::Restore(predecessor) => {
                    // Flattened: no predecessor and a cleared-grid predecessor
                    // both restore "no grid".
                    restorations.push(ValueRestoration::MetricGrid {
                        region: *region,
                        value: match predecessor {
                            Some(p) => p.into_value(),
                            None => None,
                        },
                    })
                }
            }
        }
        for ((region, position), chain) in &self.meter_change_chain {
            if !slot_live(TypedObjectId::Region(*region)) {
                continue;
            }
            match chain.undo_verdict(tx) {
                ChainUndoVerdict::NotWritten => {}
                ChainUndoVerdict::Superseded { by } => superseded.push(by),
                ChainUndoVerdict::Restore(predecessor) => {
                    restorations.push(ValueRestoration::MeterChange {
                        region: *region,
                        position: position.clone(),
                        value: match predecessor {
                            Some(p) => p.into_value(),
                            None => None,
                        },
                    })
                }
            }
        }
        for ((scope, position), chain) in &self.tempo_segment_chain {
            if let Some(region) = scope {
                if !slot_live(TypedObjectId::Region(*region)) {
                    continue;
                }
            }
            match chain.undo_verdict(tx) {
                ChainUndoVerdict::NotWritten => {}
                ChainUndoVerdict::Superseded { by } => superseded.push(by),
                ChainUndoVerdict::Restore(predecessor) => {
                    restorations.push(ValueRestoration::TempoSegment {
                        region: *scope,
                        position: position.clone(),
                        value: match predecessor {
                            Some(p) => p.into_value(),
                            None => None,
                        },
                    })
                }
            }
        }
        for (instance, chain) in &self.staff_layout_chain {
            if !slot_live(TypedObjectId::StaffInstance(*instance)) {
                continue;
            }
            match chain.undo_verdict(tx) {
                ChainUndoVerdict::NotWritten => {}
                ChainUndoVerdict::Superseded { by } => superseded.push(by),
                ChainUndoVerdict::Restore(predecessor) => {
                    restorations.push(ValueRestoration::StaffLayout {
                        instance: *instance,
                        value: predecessor.map(Predecessor::into_value),
                    })
                }
            }
        }
        for ((region, position), chain) in &self.break_chain {
            if !slot_live(TypedObjectId::Region(*region)) {
                continue;
            }
            match chain.undo_verdict(tx) {
                ChainUndoVerdict::NotWritten => {}
                ChainUndoVerdict::Superseded { by } => superseded.push(by),
                ChainUndoVerdict::Restore(predecessor) => {
                    restorations.push(ValueRestoration::SystemBreak {
                        region: *region,
                        position: position.clone(),
                        predecessor,
                    })
                }
            }
        }
        for ((region, position), chain) in &self.page_break_chain {
            if !slot_live(TypedObjectId::Region(*region)) {
                continue;
            }
            match chain.undo_verdict(tx) {
                ChainUndoVerdict::NotWritten => {}
                ChainUndoVerdict::Superseded { by } => superseded.push(by),
                ChainUndoVerdict::Restore(predecessor) => {
                    restorations.push(ValueRestoration::PageBreak {
                        region: *region,
                        position: position.clone(),
                        predecessor,
                    })
                }
            }
        }
        // A pitch's value and its engraved spelling set undo as ONE unit
        // (`req:opcat:spelling-set-chain`): if either was superseded, neither is
        // restored. Restoring a pitch while leaving a spelling authored against
        // the value it used to have is the stale-notehead defect this prevents.
        //
        // The unit is keyed on the PITCH and on which chains the TRANSACTION
        // wrote — not on which operation wrote them. So it also couples a
        // transaction that writes the two halves through *different* members:
        // the editor's "move note" is `ModifyIdentifiedPitch` + `RespellPitch`,
        // and a later respell makes a best-effort undo skip both. That is
        // intentional, and regression-locked
        // (`best_effort_undo_skips_a_move_and_respell_pair_a_later_respell_superseded`).
        //
        // It cannot fire on a transaction that wrote only one half: a chain
        // reports `Superseded` only when the transaction actually wrote it, so
        // an unwritten chain yields `NotWritten` and contributes nothing.
        if !superseded_pitches.is_empty() {
            restorations.retain(|r| match r {
                ValueRestoration::Pitch { pitch, .. }
                | ValueRestoration::EngravedSpellings { pitch, .. } => {
                    !superseded_pitches.contains(pitch)
                }
                _ => true,
            });
        }
        superseded.sort();
        superseded.dedup();
        (restorations, superseded)
    }

    /// Applies the collected restorations to the bookkeeping and the graph,
    /// recording each restored *value* into its chain as a new write by the
    /// undo operation (so a later undo sees the restoration as the key's last
    /// writer — the pinned undo-of-undo discipline; see DECISIONS.md). An
    /// absence restoration (no predecessor at all) leaves the chain
    /// unchanged: a repeated undo of the same transaction re-restores absence
    /// idempotently.
    fn apply_restorations(&mut self, env: &OperationEnvelope, restorations: Vec<ValueRestoration>) {
        for restoration in restorations {
            match restoration {
                ValueRestoration::Event { event, value } => {
                    if let Some(value) = value {
                        self.apply_event_value(&value);
                        self.event_modify_chain
                            .entry(event)
                            .or_insert_with(WriteChain::new)
                            .record(env.id, env.transaction, value);
                    }
                }
                ValueRestoration::Pitch { pitch, value } => {
                    if let Some(value) = value {
                        self.graph_modify_pitch(pitch, &value);
                        self.pitch_modify_chain
                            .entry(pitch)
                            .or_insert_with(WriteChain::new)
                            .record(env.id, env.transaction, value);
                    }
                }
                ValueRestoration::Spelling { pitch, predecessor } => match predecessor {
                    Some(Predecessor::Write(spelling)) => {
                        self.spellings.insert(pitch, spelling.clone());
                        self.respell_chain
                            .entry(pitch)
                            .or_insert_with(WriteChain::new)
                            .record(env.id, env.transaction, spelling.clone());
                        self.graph_respell_pitch(pitch, &spelling);
                    }
                    Some(Predecessor::Base(spelling)) => {
                        // The ledger returns to key-absence (the base state
                        // lives in the graph); the graph attachment restores
                        // the base value.
                        self.spellings.remove(&pitch);
                        self.respell_chain
                            .entry(pitch)
                            .or_insert_with(WriteChain::new)
                            .record(env.id, env.transaction, spelling.clone());
                        self.graph_respell_pitch(pitch, &spelling);
                    }
                    None => {
                        self.spellings.remove(&pitch);
                        self.graph_remove_respell(pitch);
                    }
                },
                ValueRestoration::EngravedSpellings { pitch, predecessor } => {
                    let set: Vec<SpellingAttachment> = match predecessor {
                        Some(Predecessor::Write(set)) | Some(Predecessor::Base(set)) => set,
                        None => Vec::new(),
                    };
                    self.engraved_spelling_chain
                        .entry(pitch)
                        .or_insert_with(WriteChain::new)
                        .record(env.id, env.transaction, set.clone());
                    self.graph_replace_spelling_set(pitch, &set);
                }
                ValueRestoration::CrossCutting { id, value } => {
                    if let Some(value) = value {
                        self.structures.insert(id, value.endpoints());
                        self.graph_modify_cross_cutting(&value);
                        self.cross_cutting_modify_chain
                            .entry(id)
                            .or_insert_with(WriteChain::new)
                            .record(env.id, env.transaction, value);
                    }
                }
                ValueRestoration::Metadata { value } => {
                    if let Some(value) = value {
                        if let Some(score) = self.graph.as_mut() {
                            score.metadata = value.clone();
                        }
                        self.metadata_chain.record(env.id, env.transaction, value);
                    }
                }
                // Genesis tranche G2a (contract pin 7): mirror `Metadata`'s
                // restoration-apply shape for the two new score-singleton
                // settings chains.
                ValueRestoration::CanvasLayoutDefaults { value } => {
                    if let Some(value) = value {
                        if let Some(score) = self.graph.as_mut() {
                            score.canvas.layout_defaults = value;
                        }
                        self.canvas_layout_defaults_chain
                            .record(env.id, env.transaction, value);
                    }
                }
                ValueRestoration::SpellingPrecedence { value } => {
                    if let Some(value) = value {
                        if let Some(score) = self.graph.as_mut() {
                            score.spelling_precedence = value.clone();
                        }
                        self.spelling_precedence_chain
                            .record(env.id, env.transaction, value);
                    }
                }
                // Genesis tranche G2b (contract pin 5): mirror `Metadata`'s
                // restoration-apply shape; writes only the five subset
                // fields, leaving `accidental_extensions` untouched.
                ValueRestoration::TuningContext { value } => {
                    if let Some(value) = value {
                        if let Some(score) = self.graph.as_mut() {
                            score.tuning_context.default_pitch_space =
                                value.default_pitch_space.clone();
                            score.tuning_context.default_tuning_system =
                                value.default_tuning_system.clone();
                            score.tuning_context.reference = value.reference.clone();
                            score.tuning_context.smufl = value.smufl;
                            score.tuning_context.overrides = value.overrides.clone();
                        }
                        self.tuning_context_chain
                            .record(env.id, env.transaction, value);
                    }
                }
                ValueRestoration::MetricGrid { region, value } => {
                    self.metric_grid_chain
                        .entry(region)
                        .or_insert_with(WriteChain::new)
                        .record(env.id, env.transaction, value.clone());
                    self.graph_set_metric_grid(region, &value);
                }
                ValueRestoration::MeterChange {
                    region,
                    position,
                    value,
                } => {
                    self.meter_change_chain
                        .entry((region, position.clone()))
                        .or_insert_with(WriteChain::new)
                        .record(env.id, env.transaction, value.clone());
                    self.graph_apply_meter_change(region, &position, &value);
                }
                ValueRestoration::TempoSegment {
                    region,
                    position,
                    value,
                } => {
                    self.tempo_segment_chain
                        .entry((region, position.clone()))
                        .or_insert_with(WriteChain::new)
                        .record(env.id, env.transaction, value.clone());
                    self.graph_apply_tempo_segment(region, &position, &value);
                }
                ValueRestoration::StaffLayout { instance, value } => {
                    if let Some(value) = value {
                        self.graph_set_staff_layout(instance, &value);
                        self.staff_layout_chain
                            .entry(instance)
                            .or_insert_with(WriteChain::new)
                            .record(env.id, env.transaction, value);
                    }
                }
                ValueRestoration::SystemBreak {
                    region,
                    position,
                    predecessor,
                } => self.restore_break(env, region, position, predecessor, false),
                ValueRestoration::PageBreak {
                    region,
                    position,
                    predecessor,
                } => self.restore_break(env, region, position, predecessor, true),
            }
        }
    }

    /// Restores one user-break key: a write predecessor re-enters the ledger
    /// map; a base predecessor returns the map to key-absence while the graph
    /// restores the base anchor; no predecessor removes the key from map and
    /// graph alike.
    fn restore_break(
        &mut self,
        env: &OperationEnvelope,
        region: RegionId,
        position: MusicalPosition,
        predecessor: Option<Predecessor<(TimeAnchor, bool)>>,
        page: bool,
    ) {
        let key = (region, position.clone());
        match predecessor {
            Some(Predecessor::Write((anchor, present))) => {
                if page {
                    self.page_breaks.insert(key.clone(), present);
                    self.page_break_chain
                        .entry(key)
                        .or_insert_with(WriteChain::new)
                        .record(env.id, env.transaction, (anchor.clone(), present));
                } else {
                    self.breaks.insert(key.clone(), present);
                    self.break_chain
                        .entry(key)
                        .or_insert_with(WriteChain::new)
                        .record(env.id, env.transaction, (anchor.clone(), present));
                }
                self.graph_apply_break(region, &anchor, present, page);
            }
            Some(Predecessor::Base((anchor, present))) => {
                if page {
                    self.page_breaks.remove(&key);
                    self.page_break_chain
                        .entry(key)
                        .or_insert_with(WriteChain::new)
                        .record(env.id, env.transaction, (anchor.clone(), present));
                } else {
                    self.breaks.remove(&key);
                    self.break_chain
                        .entry(key)
                        .or_insert_with(WriteChain::new)
                        .record(env.id, env.transaction, (anchor.clone(), present));
                }
                self.graph_apply_break(region, &anchor, present, page);
            }
            None => {
                if page {
                    self.page_breaks.remove(&key);
                } else {
                    self.breaks.remove(&key);
                }
                self.graph_clear_break(region, &position, page);
            }
        }
    }

    fn graph_apply_break(
        &mut self,
        region: RegionId,
        anchor: &TimeAnchor,
        present: bool,
        page: bool,
    ) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        if let Some(region) = score.canvas.regions.iter_mut().find(|r| r.id == region) {
            if let Some(content) = region.content.staff_based_mut() {
                let list = if page {
                    &mut content.user_page_breaks
                } else {
                    &mut content.user_system_breaks
                };
                apply_break_lww(list, anchor, present);
            }
        }
    }

    fn graph_clear_break(&mut self, region: RegionId, position: &MusicalPosition, page: bool) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        if let Some(region) = score.canvas.regions.iter_mut().find(|r| r.id == region) {
            if let Some(content) = region.content.staff_based_mut() {
                let list = if page {
                    &mut content.user_page_breaks
                } else {
                    &mut content.user_system_breaks
                };
                list.retain(|existing| resolved_anchor_position(existing) != *position);
            }
        }
    }

    /// Removes the user-chosen explicit spelling attachment for `pitch` — the
    /// inverse of the attachment `graph_respell_pitch` installs, used when a
    /// respell restoration has no predecessor (the operation introduced the
    /// first spelling).
    fn graph_remove_respell(&mut self, pitch: PitchId) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        score.spelling_attachments.retain(|a| {
            !(a.layer.is_none()
                && matches!(a.source, SpellingSource::UserChosen)
                && matches!(&a.scope, SpellingScope::Pitch(p) if *p == pitch)
                && matches!(a.directive, SpellingDirective::Explicit(_)))
        });
    }

    // --- Group 1 (M2): event & pitch leaf-field ops. ------------------------
    //
    // The modify/transpose ops follow respell's field-overwrite discipline but
    // do NOT store the resolved value in MaterializedState (an Event/Pitch is a
    // graph object, not a bookkeeping-owned annotation like a spelling): their
    // canonical footprint is the effect-log entry plus, on a concurrent differing
    // write, a StructuralFieldCollision. The resolved value is materialized in the
    // graph by reduce_onto. The LWW key/diff uses `last_*_modify` working state.

    /// A `SYSTEM_DERIVED` pitch's intrinsic content is immutable under
    /// reduction (Pass 12, P12-K3; core spec Ch5 §System-Derived
    /// Identifiers): its identifier is content-derived, so an in-place
    /// rewrite would invalidate the derivation. The check compares the
    /// replacement value's canonical pitch bytes against the id's
    /// *registered derivation inputs* — the same `system_mints` registry the
    /// collision pre-walk maintains (base-seeded occupants plus op mints),
    /// so `reduce()` and `reduce_onto()` agree wherever the registry holds
    /// the entry. An unregistered id (base-free reduction over a pitch the
    /// base seeded) is unverifiable and passes, like the other
    /// graph-aware-only preconditions.
    ///
    /// This is the *rewrite* precondition (a live system pitch's content
    /// changed in place). The sibling *introduction* case — a system pitch
    /// never minted, introduced by a `ModifyEvent` replacement — is refused
    /// upfront in [`Self::modify_event`] (P13-K1, resolved: reject the
    /// introduction), which closes the checkpoint-cut asymmetry that once let
    /// an introduced system pitch slip through in-session yet read
    /// `SystemDerivedContentImmutable` after a snapshot re-seeded it here.
    fn system_derived_rewrite(&self, id: PitchId, value: &Pitch) -> bool {
        if id.replica() != ReplicaId::SYSTEM_DERIVED {
            return false;
        }
        match self.system_mints.get(&(ObjectKind::Pitch, id.counter())) {
            Some((inputs, _)) => inputs.0 != canonical_pitch_bytes(value),
            None => false,
        }
    }

    fn modify_event(&mut self, env: &OperationEnvelope, op: &ModifyEventOp) -> OperationEffect {
        let event_id = op.event_id();
        let ev_obj = TypedObjectId::Event(event_id);
        match self.objects.get(&ev_obj) {
            None => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::TargetMissing,
                    },
                }
            }
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::TargetTombstoned,
                }
            }
            Some(ObjectState::Live) => {}
        }
        let mut carried = Vec::new();
        op.event.collect_identified_pitches(&mut carried);
        // Introduction precondition (P13-K1, ratified: reject the
        // introduction) before the identity one: a `ModifyEvent` may not
        // *introduce* a never-minted SYSTEM-DERIVED pitch id — that id lives in
        // the reserved system namespace and only the system mints it. A carried
        // system-derived pitch absent from `objects` (never minted) is refused,
        // consistently across a snapshot cut: this closes the asymmetry where
        // an introduced system pitch slipped through in-session (`system_mints`
        // had no entry, so the identity check below saw nothing) yet read
        // `SystemDerivedContentImmutable` once a snapshot re-seeded it as a
        // system mint. A user-replica pitch carries no such namespace claim and
        // has no snapshot asymmetry, so it is untouched here; the event's own
        // live system pitches are in `objects` (both reduction modes), so an
        // in-place content rewrite passes.
        if carried.iter().any(|ip| {
            ip.id.replica() == ReplicaId::SYSTEM_DERIVED
                && !matches!(
                    self.objects.get(&TypedObjectId::Pitch(ip.id)),
                    Some(ObjectState::Live)
                )
        }) {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetMissing,
                },
            };
        }
        // Identity precondition (P12-K3) before the placement precondition:
        // a replacement value that rewrites a system-derived pitch's
        // intrinsic content in place is refused outright.
        if carried
            .iter()
            .any(|ip| self.system_derived_rewrite(ip.id, &ip.pitch))
        {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::SystemDerivedContentImmutable,
                },
            };
        }
        // A `ModifyEvent` that moves a metric event's span (a trim or move) is now
        // materialized, but it must keep invariant 3 (`VoiceEventsSortedNonOverlap`):
        // refuse a move onto another live event in the voice, or one with a
        // non-positive span, rather than skip it silently (which would log a clean op
        // that never took effect). The verdict reads `voice_occupancy`, the
        // graph-independent index, so `reduce()` and `reduce_onto()` agree on it.
        let placement = self.metric_placement_verdict(&op.event);
        if matches!(placement, PlacementVerdict::Refused) {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::EventDurationInvalid,
                },
            };
        }
        let prev = self
            .event_modify_chain
            .get(&event_id)
            .and_then(|chain| chain.last_write())
            .map(|write| (write.op, write.value.clone()));
        let effect = match prev {
            Some((prev_op, prev_event)) if self.concurrent(env.id, prev_op) => {
                if prev_event == op.event {
                    return OperationEffect::NoOp {
                        reason: NoOpReason::AlreadyApplied,
                    };
                }
                // Later in canonical order wins and materializes; the earlier op
                // is the loser. (Winner carries the Conflicted tag; see DECISIONS.)
                let conflict = ConflictRecord::new(
                    ConflictKind::StructuralFieldCollision {
                        winner: env.id,
                        loser: prev_op,
                        field: FieldPath("event".to_string()),
                    },
                    vec![env.id, prev_op],
                    vec![ev_obj],
                );
                let cid = conflict.id;
                self.conflicts.insert(conflict);
                OperationEffect::Conflicted { conflict: cid }
            }
            // First modify, or a causally-ordered intentional overwrite.
            _ => OperationEffect::Applied,
        };
        self.event_modify_chain
            .entry(event_id)
            .or_insert_with(WriteChain::new)
            .record(env.id, env.transaction, op.event.clone());
        self.apply_event_value(&op.event);
        effect
    }

    /// Applies an event *value* (a modify's replacement, or an undo's restored
    /// predecessor) to the graph and the occupancy index. A move materializes
    /// only when it is a sanctioned metric move (`Moved`) *and* the value is
    /// well-formed — so the graph and the occupancy index move together. A
    /// malformed (empty) pitched value is not materialized in the graph
    /// (`graph_replace_event` skips it), so it must not move occupancy either;
    /// a refused or non-metric placement leaves placement untouched (only
    /// same-placement field edits apply).
    fn apply_event_value(&mut self, value: &Event) {
        let placement = self.metric_placement_verdict(value);
        let materialize_move = matches!(placement, PlacementVerdict::Moved { .. })
            && !matches!(value, Event::Pitched(pe) if !pe.is_well_formed());
        self.graph_replace_event(value, materialize_move);
        // Keep the voice-occupancy index in step with a materialized move, so a later
        // insert sees the freed/changed span (the same index its overlap check reads).
        if materialize_move {
            if let PlacementVerdict::Moved {
                voice,
                position,
                duration,
            } = placement
            {
                if let Some(events) = self.voice_occupancy.get_mut(&voice) {
                    for slot in events.iter_mut().filter(|slot| slot.2 == value.id()) {
                        slot.0 = position.clone();
                        slot.1 = duration.clone();
                    }
                }
            }
        }
    }

    /// The verdict on a [`ModifyEvent`](OperationKind::ModifyEvent)'s placement: does
    /// it move the event's metric span, and if so does the move keep invariant 3
    /// (`VoiceEventsSortedNonOverlap`)? Read from `voice_occupancy` — the canonical,
    /// graph-independent placement index — so the verdict is identical with or without
    /// a base graph.
    fn metric_placement_verdict(&self, new_event: &Event) -> PlacementVerdict {
        let event_id = new_event.id();
        let Some((voice, current_position, current_duration)) =
            self.voice_occupancy.iter().find_map(|(voice, events)| {
                events
                    .iter()
                    .find(|(_, _, event)| *event == event_id)
                    .map(|(position, duration, _)| (*voice, position.clone(), duration.clone()))
            })
        else {
            // The event has no metric occupancy entry (untracked or non-metric):
            // nothing to materialize or refuse here.
            return PlacementVerdict::Unchanged;
        };
        let (EventPosition::Musical(new_position), EventDuration::Musical(new_duration)) =
            (new_event.position(), new_event.duration())
        else {
            // A non-metric placement is left deferred, neither moved nor refused.
            return PlacementVerdict::Unchanged;
        };
        if *new_position == current_position && *new_duration == current_duration {
            return PlacementVerdict::Unchanged;
        }
        if !new_duration.is_positive() {
            return PlacementVerdict::Refused;
        }
        let overlaps = self.voice_occupancy.get(&voice).is_some_and(|events| {
            events.iter().any(|(position, duration, event)| {
                *event != event_id
                    && intervals_overlap(new_position, new_duration, position, duration)
            })
        });
        if overlaps {
            PlacementVerdict::Refused
        } else {
            PlacementVerdict::Moved {
                voice,
                position: new_position.clone(),
                duration: new_duration.clone(),
            }
        }
    }

    /// Re-sorts `voice`'s graph event list by ascending position (id-tiebroken), the
    /// same order an insert maintains — run after a materialized placement change so
    /// the voice stays sorted (invariant 3). A no-op when the graph is absent.
    fn resort_voice(&mut self, voice: VoiceId) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        let Some((region_index, instance_index, voice_index)) = graph_voice_location(score, voice)
        else {
            return;
        };
        let mut ordered = score.canvas.regions[region_index].staff_instances()[instance_index]
            .voices[voice_index]
            .events
            .clone();
        ordered.sort_by(|a, b| {
            let a_position = score.events.get(*a).map(Event::position);
            let b_position = score.events.get(*b).map(Event::position);
            match (a_position, b_position) {
                (
                    Some(EventPosition::Musical(a_position)),
                    Some(EventPosition::Musical(b_position)),
                ) => a_position.cmp(b_position).then_with(|| a.cmp(b)),
                _ => a.cmp(b),
            }
        });
        score.canvas.regions[region_index]
            .content
            .staff_instances_mut()
            .expect("the voice was located in a staff-based instance")[instance_index]
            .voices[voice_index]
            .events = ordered;
    }

    fn transpose(&mut self, _env: &OperationEnvelope, op: &TransposeOp) -> OperationEffect {
        // Precondition: a target that never entered canonical state is a
        // dangling reference — the whole operation refuses. Tombstoned targets
        // are *skipped* per the catalog's re-anchoring rule ("the transpose
        // applies only to live pitches", Operation Catalog §Transpose); the
        // shift still applies to the remaining live targets. Transpose is
        // order-dependent (transpositions do not commute); its canonical
        // footprint is the effect-log entry. The transposed values are
        // materialized in the graph.
        if op
            .targets
            .iter()
            .any(|pitch| !self.objects.contains_key(&TypedObjectId::Pitch(*pitch)))
        {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetMissing,
                },
            };
        }
        let live: Vec<PitchId> = op
            .targets
            .iter()
            .copied()
            .filter(|pitch| {
                matches!(
                    self.objects.get(&TypedObjectId::Pitch(*pitch)),
                    Some(ObjectState::Live)
                )
            })
            .collect();
        if live.is_empty() {
            // Every target was tombstoned by a causally-prior delete: the
            // skip-all case degenerates to no effect.
            return OperationEffect::NoOp {
                reason: NoOpReason::TargetTombstoned,
            };
        }
        // P12-K3: a SYSTEM_DERIVED pitch's intrinsic content is immutable —
        // an in-place alteration shift would desynchronize the content from
        // the id's derivation inputs (and from the `system_mints` registry).
        // System-derived targets are *skipped* like tombstoned ones (the
        // shift still applies to the remaining targets); a transpose whose
        // live targets are all system-derived reduces as a precondition
        // no-op. The filter reads only the id's namespace, so base-free and
        // graph-aware reduction agree.
        let mutable: Vec<PitchId> = live
            .into_iter()
            .filter(|pitch| pitch.replica() != ReplicaId::SYSTEM_DERIVED)
            .collect();
        if mutable.is_empty() {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::SystemDerivedContentImmutable,
                },
            };
        }
        for pitch in mutable {
            self.graph_transpose_pitch(pitch, op.chromatic_steps);
        }
        OperationEffect::Applied
    }

    /// The faithful transpose (operation_catalog §TransposeInterval; Push 4a,
    /// closing P12-K2).
    ///
    /// Shares [`Self::transpose`]'s target discipline: a target that never
    /// entered canonical state refuses the whole operation; tombstoned and
    /// `SYSTEM_DERIVED` targets are *skipped*. A deleted pitch is not an
    /// untransposable pitch — it is one the operation has nothing to say about.
    ///
    /// Then it adds atomic refusal. Every remaining live target must be
    /// transposable under `req:pitch:transposition`, or **nothing moves**: a
    /// chord transposed except for one note is a different chord.
    ///
    /// Like the other graph-aware-only preconditions (see
    /// [`Self::modify_identified_pitch`]'s system-derived rewrite check), the
    /// refusal is unverifiable under base-free `reduce()` — no pitch values
    /// exist there — and passes. It also writes nothing there, so the two modes
    /// agree on `objects`, and on the effect log for every operation whose
    /// targets are all transposable, which is the only case base-free reduction
    /// can distinguish.
    fn transpose_interval(
        &mut self,
        env: &OperationEnvelope,
        op: &TransposeIntervalOp,
    ) -> OperationEffect {
        if op
            .targets
            .iter()
            .any(|pitch| !self.objects.contains_key(&TypedObjectId::Pitch(*pitch)))
        {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetMissing,
                },
            };
        }
        let live: Vec<PitchId> = op
            .targets
            .iter()
            .copied()
            .filter(|pitch| {
                matches!(
                    self.objects.get(&TypedObjectId::Pitch(*pitch)),
                    Some(ObjectState::Live)
                )
            })
            .collect();
        if live.is_empty() {
            return OperationEffect::NoOp {
                reason: NoOpReason::TargetTombstoned,
            };
        }
        let mutable: Vec<PitchId> = live
            .into_iter()
            .filter(|pitch| pitch.replica() != ReplicaId::SYSTEM_DERIVED)
            .collect();
        if mutable.is_empty() {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::SystemDerivedContentImmutable,
                },
            };
        }

        // Atomicity: resolve every target's new value AND every spelling
        // rewrite BEFORE writing any of them. `targets` is a set, so `mutable`
        // is in canonical order, and the reported failure is the
        // canonically-first offender — `req:opcat:transpose-interval-atomic`.
        let mut resolved: Vec<ResolvedTranspose> = Vec::with_capacity(mutable.len());
        for pitch in &mutable {
            let Some(current) = self.graph_pitch_value(*pitch) else {
                continue; // base-free: no value to check, and none to write
            };
            let next = match current.transposed(op.interval) {
                Ok(next) => next,
                Err(refusal) => {
                    let reason = match refusal {
                        TransposeRefusal::NonCmnPosition
                        | TransposeRefusal::PitchSpaceUnavailable => {
                            PreconditionFailureReason::PitchSpaceMismatch
                        }
                        TransposeRefusal::AcousticPinned => {
                            PreconditionFailureReason::AcousticRealizationPinned
                        }
                        TransposeRefusal::OutOfRange => {
                            PreconditionFailureReason::TranspositionOutOfRange
                        }
                    };
                    return OperationEffect::NoOp {
                        reason: NoOpReason::PreconditionFailedUnderReduction { reason },
                    };
                }
            };
            match self.resolve_transposed_spellings(*pitch, &next, op.interval) {
                Some(authored) => resolved.push(ResolvedTranspose {
                    pitch: *pitch,
                    value: next,
                    authored,
                }),
                // An authored spelling that cannot be written at the transposed
                // staff position refuses the whole operation, like any other
                // untransposable target. Silently leaving it stale is what this
                // operation exists to stop.
                None => {
                    return OperationEffect::NoOp {
                        reason: NoOpReason::PreconditionFailedUnderReduction {
                            reason: PreconditionFailureReason::TranspositionOutOfRange,
                        },
                    }
                }
            }
        }

        // Two passes. The authored rewrites address `spelling_attachments` by
        // index, and the propagated upsert may PUSH — which would shift every
        // later target's indices. So every rewrite lands before any append.
        for r in &resolved {
            self.graph_modify_pitch(r.pitch, &r.value);
            self.graph_rewrite_authored_spellings(&r.authored);
        }
        for r in &resolved {
            self.graph_propagate_spelling(r.pitch, &r.value);
        }

        // Value-restoring undo (`operation_catalog` §TransposeInterval). Record
        // AFTER the graph writes, so the recorded spelling set is the
        // post-transpose one and the chain's predecessor is the pre-transpose
        // state. Restoring the pitch alone would leave a notehead spelled for a
        // pitch that is no longer there.
        for r in &resolved {
            self.pitch_modify_chain
                .entry(r.pitch)
                .or_insert_with(WriteChain::new)
                .record(env.id, env.transaction, r.value.clone());
            self.record_engraved_spellings(env, r.pitch);
        }
        OperationEffect::Applied
    }

    /// The engraved-layer authored spellings on `pitch`, each moved to where the
    /// transposed pitch writes it. `None` if any of them cannot be written
    /// there.
    ///
    /// `Propagated` attachments are skipped: they are this operation's own
    /// output, regenerated from the transposed value. Everything else —
    /// `UserChosen`, `Imported` — is an assertion that *this pitch is written
    /// like so*, and once the pitch moves that assertion has to move with it or
    /// it is simply false. (Import fidelity is a property of the file on disk,
    /// which a transposition does not touch.)
    fn resolve_transposed_spellings(
        &self,
        pitch: PitchId,
        transposed: &Pitch,
        interval: TranspositionInterval,
    ) -> Option<Vec<(usize, PitchSpelling)>> {
        let Some(score) = self.graph.as_ref() else {
            return Some(Vec::new());
        };
        let mut out = Vec::new();
        for (index, att) in score.spelling_attachments.iter().enumerate() {
            if att.layer.is_some() || matches!(att.source, SpellingSource::Propagated { .. }) {
                continue;
            }
            if !matches!(&att.scope, SpellingScope::Pitch(p) if *p == pitch) {
                continue;
            }
            let SpellingDirective::Explicit(spelling) = &att.directive else {
                continue;
            };
            // The transposed 12-TET semitone is needed ONLY to rewrite an
            // authored spelling, and the spelling pre-pass is still
            // 12-chromatic (the built-in catalog's conformance note). So it is
            // computed here, at point of use, and NOT before the loop: a pitch
            // in a resolved non-12-chromatic space (`cmn-24`, since Push 4b
            // tranche 1) transposes its *value* correctly and must not be
            // refused merely for carrying no authored spelling to rewrite.
            // When it does carry one, `?` still refuses — a 24-chromatic
            // authored spelling is the documented spelling-layer limitation,
            // not a silently stale write. Hoisting this above the loop is what
            // made a spelling-less `cmn-24` transpose refuse (P13-S3-shaped:
            // latent in code, made reachable the moment the space resolved).
            let semitone = transposed.twelve_tet_semitone()?;
            out.push((index, spelling.transposed(interval, semitone)?));
        }
        Some(out)
    }

    /// Applies the rewrites `resolve_transposed_spellings` computed, preserving
    /// each attachment's `source`, `priority`, and `layer`. A transposed
    /// `UserChosen` spelling is still the user's choice.
    fn graph_rewrite_authored_spellings(&mut self, rewrites: &[(usize, PitchSpelling)]) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        for (index, spelling) in rewrites {
            if let Some(att) = score.spelling_attachments.get_mut(*index) {
                att.directive = SpellingDirective::Explicit(spelling.clone());
            }
        }
    }

    /// The current value of a live embedded pitch, or `None` under base-free
    /// reduction (no graph) or if the pitch is not embedded in any event.
    fn graph_pitch_value(&self, pitch: PitchId) -> Option<Pitch> {
        let score = self.graph.as_ref()?;
        let event = Self::graph_event_of_pitch(score, pitch)?;
        match score.events.get(event) {
            Some(Event::Pitched(pe)) => pe
                .pitches
                .iter()
                .find(|ip| ip.id == pitch)
                .map(|ip| ip.pitch.clone()),
            _ => None,
        }
    }

    /// Records the spelling a transposition determined
    /// (`req:opcat:transpose-interval-spelling`; core Ch2 §Spelling Sources:
    /// "editing operations that move or transpose a pitch MUST produce
    /// attachments with source `Propagated`").
    ///
    /// This is the record for a pitch with **no authored spelling**: without it
    /// the pre-pass re-infers, and may pick the enharmonic the interval did not
    /// choose. `simplest_spelling` on a `Cmn` position returns that position's
    /// letter verbatim (it infers only for non-`Cmn` positions, which this
    /// operation refuses), so the attachment carries exactly the interval's
    /// determination.
    ///
    /// It does **not** by itself fix a *stale authored* spelling: the default
    /// precedence ranks `UserChosen` and `Imported` above `Propagated`
    /// (Chapter 2 §"Configurable Precedence"), so an authored attachment wins
    /// and would engrave the pre-transpose notehead — a C#4 drawn as a C
    /// natural, accidental and all. Authored spellings are therefore *moved*,
    /// by `resolve_transposed_spellings`; this attachment is the fallback for
    /// pitches that have none.
    fn graph_propagate_spelling(&mut self, pitch: PitchId, value: &Pitch) {
        let Some(spelling) = simplest_spelling(value) else {
            return;
        };
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        // Upsert the propagated attachment (one per pitch), keeping the
        // attachment list's canonical order stable for the resolver's
        // tie-break — the same discipline `graph_respell_pitch` follows.
        if let Some(existing) = score.spelling_attachments.iter_mut().find(|a| {
            a.layer.is_none()
                && matches!(a.source, SpellingSource::Propagated { .. })
                && matches!(&a.scope, SpellingScope::Pitch(p) if *p == pitch)
                && matches!(a.directive, SpellingDirective::Explicit(_))
        }) {
            existing.directive = SpellingDirective::Explicit(spelling);
        } else {
            score.spelling_attachments.push(SpellingAttachment {
                scope: SpellingScope::Pitch(pitch),
                directive: SpellingDirective::Explicit(spelling),
                // Identifiers are preserved by transposition, so the pitch the
                // spelling propagated *from* is the pitch it is attached to.
                source: SpellingSource::Propagated { from: pitch },
                priority: 0,
                layer: None,
            });
        }
    }

    fn insert_identified_pitch(
        &mut self,
        env: &OperationEnvelope,
        op: &InsertIdentifiedPitchOp,
    ) -> OperationEffect {
        let pitch_id = op.pitch_id();
        let p_obj = TypedObjectId::Pitch(pitch_id);
        // The target event must be live; the pitch id must be fresh.
        if !matches!(
            self.objects.get(&TypedObjectId::Event(op.event)),
            Some(ObjectState::Live)
        ) {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetMissing,
                },
            };
        }
        match self.objects.get(&p_obj) {
            Some(ObjectState::Live) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::AlreadyApplied,
                }
            }
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::TargetTombstoned,
                }
            }
            None => {}
        }
        self.objects.insert(p_obj, ObjectState::Live);
        self.minted_by.insert(p_obj, env.id);
        self.note_minted(env, p_obj);
        // Seed the pitch's write chain with the minted value, so a later
        // modify's chain-predecessor is the inserted state.
        self.pitch_modify_chain
            .entry(pitch_id)
            .or_insert_with(WriteChain::new)
            .seed(op.pitch.pitch.clone());
        self.event_pitches
            .entry(op.event)
            .or_default()
            .push(pitch_id);
        self.graph_insert_pitch(op.event, &op.pitch);
        OperationEffect::Applied
    }

    fn delete_identified_pitch(
        &mut self,
        env: &OperationEnvelope,
        op: &DeleteIdentifiedPitchOp,
    ) -> OperationEffect {
        let p_obj = TypedObjectId::Pitch(op.pitch);
        let minted_by = match self.objects.get(&p_obj) {
            None => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::TargetMissing,
                    },
                }
            }
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::AlreadyApplied,
                }
            }
            Some(ObjectState::Live) => self.minted_by.get(&p_obj).copied().unwrap_or(env.id),
        };
        self.objects.insert(
            p_obj,
            ObjectState::Tombstoned {
                deleted_by: env.id,
                minted_by,
            },
        );
        for pitches in self.event_pitches.values_mut() {
            pitches.retain(|p| *p != op.pitch);
        }
        self.graph_delete_pitch(op.pitch);
        OperationEffect::Applied
    }

    fn modify_identified_pitch(
        &mut self,
        env: &OperationEnvelope,
        op: &ModifyIdentifiedPitchOp,
    ) -> OperationEffect {
        let p_obj = TypedObjectId::Pitch(op.pitch);
        match self.objects.get(&p_obj) {
            None => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::TargetMissing,
                    },
                }
            }
            Some(ObjectState::Tombstoned { .. }) => {
                return OperationEffect::NoOp {
                    reason: NoOpReason::TargetTombstoned,
                }
            }
            Some(ObjectState::Live) => {}
        }
        // Identity precondition (P12-K3): a system-derived pitch's intrinsic
        // content is immutable in place.
        if self.system_derived_rewrite(op.pitch, &op.value) {
            return OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::SystemDerivedContentImmutable,
                },
            };
        }
        let prev = self
            .pitch_modify_chain
            .get(&op.pitch)
            .and_then(|chain| chain.last_write())
            .map(|write| (write.op, write.value.clone()));
        let effect = match prev {
            Some((prev_op, prev_value)) if self.concurrent(env.id, prev_op) => {
                if prev_value == op.value {
                    return OperationEffect::NoOp {
                        reason: NoOpReason::AlreadyApplied,
                    };
                }
                let conflict = ConflictRecord::new(
                    ConflictKind::StructuralFieldCollision {
                        winner: env.id,
                        loser: prev_op,
                        field: FieldPath("pitch".to_string()),
                    },
                    vec![env.id, prev_op],
                    vec![p_obj],
                );
                let cid = conflict.id;
                self.conflicts.insert(conflict);
                OperationEffect::Conflicted { conflict: cid }
            }
            _ => OperationEffect::Applied,
        };
        self.pitch_modify_chain
            .entry(op.pitch)
            .or_insert_with(WriteChain::new)
            .record(env.id, env.transaction, op.value.clone());
        self.graph_modify_pitch(op.pitch, &op.value);
        effect
    }

    // --- Group 1 graph mutations (reduce_onto only; no-op when graph is None). --

    /// Applies a `ModifyEvent`'s value to the graph. `materialize_move` is the caller's
    /// sanction (from [`Self::metric_placement_verdict`]) that a *placement* change is a
    /// valid metric move and should be applied + the voice re-sorted; when it is false a
    /// placement change is deferred (a non-metric move, a no-occupancy event, or a
    /// refused move), leaving only same-placement field edits to apply. Keeping
    /// materialization gated on this single sanction is what holds the graph and the
    /// `voice_occupancy` index in agreement.
    fn graph_replace_event(&mut self, new_event: &Event, materialize_move: bool) {
        let placement_changed;
        let voice;
        {
            let Some(score) = self.graph.as_mut() else {
                return;
            };
            // A ModifyEvent carrying a malformed (empty) pitched event must not
            // corrupt the arena: `get_mut` bypasses `insert`'s well-formedness guard,
            // so an empty chord would only be caught later by `check_invariants`.
            // Skip the graph replace in that case (bookkeeping still records it).
            if let Event::Pitched(pe) = new_event {
                if !pe.is_well_formed() {
                    return;
                }
            }
            let Some(existing) = score.events.get_mut(new_event.id()) else {
                return;
            };
            placement_changed = new_event.position() != existing.position()
                || new_event.duration() != existing.duration();
            // A placement change is materialized (and the voice re-sorted below) only
            // when the caller sanctioned it as a valid metric move; otherwise it is
            // deferred, leaving the LWW bookkeeping to record the modify. Same-placement
            // field edits always apply, preserving the original voice membership.
            if placement_changed && !materialize_move {
                return;
            }
            voice = existing.voice();
            let mut replacement = new_event.clone();
            replacement.set_voice(voice);
            *existing = replacement;
        }
        if placement_changed {
            self.resort_voice(voice);
        }
    }

    fn graph_event_of_pitch(score: &Score, pitch: PitchId) -> Option<EventId> {
        score.events.iter().find_map(|event| {
            let mut ips = Vec::new();
            event.collect_identified_pitches(&mut ips);
            ips.iter().any(|ip| ip.id == pitch).then(|| event.id())
        })
    }

    fn graph_insert_pitch(&mut self, event: EventId, pitch: &epiphany_core::IdentifiedPitch) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        let Some(slot) = score.events.get_mut(event) else {
            return;
        };
        if let Event::Pitched(pe) = slot {
            if !pe.pitches.iter().any(|ip| ip.id == pitch.id) {
                pe.pitches.push(pitch.clone());
            }
            return;
        }
        // Adding a pitch to a rest turns the rest into a note — the dual of a
        // last-pitch delete (below). Without this, the bookkeeping mints the
        // pitch live while the graph silently drops it (a non-pitched slot has
        // no pitch list), so the two would diverge.
        if let Event::Rest(rest) = slot {
            let replacement = epiphany_core::PitchedEvent {
                id: rest.id,
                voice: rest.voice,
                position: rest.position.clone(),
                duration: rest.duration.clone(),
                pitches: vec![pitch.clone()],
                articulations: Vec::new(),
                dynamic: None,
                ornaments: Vec::new(),
                stem: epiphany_core::StemConfiguration,
                grace: None,
            };
            *slot = Event::Pitched(replacement);
        }
    }

    fn graph_delete_pitch(&mut self, pitch: PitchId) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        // Drop any user-chosen respell override for the deleted pitch (the dual
        // of `graph_respell_pitch`), so no spelling attachment is left targeting a
        // pitch that is no longer present (Chapter 5 SpellingScopeResolves). The
        // pitch is not added to `tombstoned_pitches` here: unlike a whole-event
        // delete the event survives, and a later ModifyEvent may legitimately
        // reintroduce the id — tombstoning it would make it both live and
        // tombstoned (invariant 11).
        score.spelling_attachments.retain(|a| {
            !(a.layer.is_none()
                && matches!(a.source, SpellingSource::UserChosen)
                && matches!(&a.scope, SpellingScope::Pitch(p) if *p == pitch)
                && matches!(a.directive, SpellingDirective::Explicit(_)))
        });
        let Some(event) = Self::graph_event_of_pitch(score, pitch) else {
            return;
        };
        let Some(slot) = score.events.get_mut(event) else {
            return;
        };
        if let Event::Pitched(pe) = slot {
            if pe.pitches.iter().filter(|ip| ip.id != pitch).count() == 0 {
                // Removing the last pitch would leave an empty (invalid) pitched
                // event; Chapter 5 forbids that ("use Rest for the no-pitch
                // case"), so the note degrades to a rest of the same placement
                // and duration. Keeps `get_mut` from materializing a malformed
                // chord that `check_invariants` would later reject.
                let rest = epiphany_core::Rest {
                    id: pe.id,
                    voice: pe.voice,
                    position: pe.position.clone(),
                    duration: pe.duration.clone(),
                    vertical_position: None,
                    visible: true,
                };
                *slot = Event::Rest(rest);
            } else {
                pe.pitches.retain(|ip| ip.id != pitch);
            }
        }
    }

    fn graph_modify_pitch(&mut self, pitch: PitchId, value: &Pitch) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        let Some(event) = Self::graph_event_of_pitch(score, pitch) else {
            return;
        };
        if let Some(Event::Pitched(pe)) = score.events.get_mut(event) {
            if let Some(ip) = pe.pitches.iter_mut().find(|ip| ip.id == pitch) {
                ip.pitch = value.clone();
            }
        }
    }

    fn graph_transpose_pitch(&mut self, pitch: PitchId, chromatic_steps: i32) {
        let Some(score) = self.graph.as_mut() else {
            return;
        };
        let Some(event) = Self::graph_event_of_pitch(score, pitch) else {
            return;
        };
        if let Some(Event::Pitched(pe)) = score.events.get_mut(event) {
            if let Some(ip) = pe.pitches.iter_mut().find(|ip| ip.id == pitch) {
                // Minimal interval: shift the CMN alteration, saturating at the
                // `i8` bound (a lossy stand-in — an extreme transpose clamps
                // rather than renormalizing nominal/octave). Full interval
                // algebra (Chapter 4 tuning) is deferred — P12-K2.
                if let epiphany_core::PitchSpacePosition::Cmn { alteration, .. } =
                    &mut ip.pitch.scale_position.position
                {
                    let shifted = (*alteration as i32).saturating_add(chromatic_steps);
                    *alteration = shifted.clamp(i8::MIN as i32, i8::MAX as i32) as i8;
                }
            }
        }
    }

    // --- Re-anchoring (Chapter 6 §6.5 rule table, representative subset). ----

    fn reanchor_for_tombstone(
        &mut self,
        env: &OperationEnvelope,
        tombstoned: TypedObjectId,
        repairs: &mut Vec<RepairRecord>,
        referent_voice: Option<VoiceId>,
    ) {
        // Find structures referencing the tombstoned object.
        let referencing: Vec<TypedObjectId> = self
            .structures
            .iter()
            .filter(|(_, endpoints)| endpoints.contains(&tombstoned))
            .map(|(sid, _)| *sid)
            .collect();
        for sid in referencing {
            // Skip a structure that is no longer Live — it may already have
            // been tombstoned by this same effect (an undo tombstones a whole
            // transaction's mints together, and its stale index entry lingers)
            // or cascaded by an earlier referent in this call. Re-processing it
            // would push a duplicate repair. The direct-delete path never hits
            // this (a tombstoned structure is dropped from `structures`), so the
            // guard is a no-op there and load-bearing only for the undo path.
            if !matches!(self.objects.get(&sid), Some(ObjectState::Live)) {
                continue;
            }
            match sid {
                TypedObjectId::Tie(_) => {
                    // A tie's existence requires both endpoints: cascade-delete.
                    self.cascade_structure(env, sid, repairs);
                }
                // The graph-only referent kinds — markers, cue events,
                // comments, analytical annotations, graphic gestures — are
                // repaired where their graph mutation happens
                // (`reanchor_event_referents`, run from
                // `materialize_graph_delete`), so the ledger record and the
                // graph always agree. They only exist under graph-aware
                // reduction (none is creatable by an operation).
                TypedObjectId::Marker(_)
                | TypedObjectId::Comment(_)
                | TypedObjectId::AnalyticalAnnotation(_)
                | TypedObjectId::GraphicGesture(_)
                | TypedObjectId::Event(_) => {}
                TypedObjectId::Beam(_) => {
                    let survivors = self.surviving_endpoints(sid, tombstoned);
                    if survivors < 2 {
                        self.cascade_structure(env, sid, repairs);
                    } else {
                        repairs.push(RepairRecord {
                            kind: RepairKind::SpannerTruncated {
                                removed_members: vec![tombstoned],
                            },
                            target: sid,
                        });
                    }
                }
                // Repeat structures follow the spanner row across every
                // anchor site (rule table "Repeat structure / Anchor").
                TypedObjectId::Slur(_)
                | TypedObjectId::Spanner(_)
                | TypedObjectId::RepeatStructure(_) => {
                    let survivors = self.surviving_endpoints(sid, tombstoned);
                    if survivors < 1 {
                        self.cascade_structure(env, sid, repairs);
                    } else if let Some(to) = self.nearest_survivor(sid, tombstoned) {
                        // The survivor is fixed (the structure's other
                        // endpoint — surviving-endpoint collapse per the rule
                        // table), so only the containment key applies: the
                        // reason names the survivor's actual proximity rank to
                        // the tombstoned endpoint rather than a hardcoded
                        // same-voice claim.
                        let survivor_voice = match to {
                            TypedObjectId::Event(event) => self.event_voice(event),
                            _ => None,
                        };
                        let reason = match (referent_voice, survivor_voice) {
                            (Some(referent), Some(survivor)) => self.rank_reason(
                                self.containment_rank(referent, survivor),
                                referent,
                                Some(survivor),
                            ),
                            // No indexed placement for either side (a
                            // non-metric endpoint): the pre-four-key default.
                            _ => ReanchorReason::SameVoiceNearer,
                        };
                        repairs.push(RepairRecord {
                            kind: RepairKind::Reanchored {
                                from: tombstoned,
                                to,
                                reason,
                            },
                            target: sid,
                        });
                    } else {
                        self.cascade_structure(env, sid, repairs);
                    }
                }
                _ => {
                    repairs.push(RepairRecord {
                        kind: RepairKind::AttachmentTombstoned,
                        target: sid,
                    });
                }
            }
        }
    }

    fn cascade_structure(
        &mut self,
        env: &OperationEnvelope,
        sid: TypedObjectId,
        repairs: &mut Vec<RepairRecord>,
    ) {
        let minter = self.minted_by.get(&sid).copied().unwrap_or(env.id);
        self.objects.insert(
            sid,
            ObjectState::Tombstoned {
                deleted_by: env.id,
                minted_by: minter,
            },
        );
        repairs.push(RepairRecord {
            kind: RepairKind::CascadeDeleted,
            target: sid,
        });
    }

    fn surviving_endpoints(&self, sid: TypedObjectId, just_tombstoned: TypedObjectId) -> usize {
        self.structures
            .get(&sid)
            .map(|eps| {
                eps.iter()
                    .filter(|e| {
                        **e != just_tombstoned
                            && matches!(self.objects.get(*e), Some(ObjectState::Live))
                    })
                    .count()
            })
            .unwrap_or(0)
    }

    fn nearest_survivor(
        &self,
        sid: TypedObjectId,
        just_tombstoned: TypedObjectId,
    ) -> Option<TypedObjectId> {
        // For slurs/spanners the rule table prescribes surviving-endpoint
        // collapse, so the candidate set is the structure's own endpoints; the
        // lexicographically-smallest survivor realizes the id tie-break (a
        // two-endpoint structure has exactly one). Proximity-aware re-targeting
        // beyond the endpoints stays a deferred refinement (the table says so
        // explicitly); the open-candidate four-key ordering lives in
        // `nearest_live_event`.
        self.structures.get(&sid).and_then(|eps| {
            eps.iter()
                .filter(|e| {
                    **e != just_tombstoned
                        && matches!(self.objects.get(*e), Some(ObjectState::Live))
                })
                .min()
                .copied()
        })
    }

    // --- The four-key "nearest" ordering (Chapter 6 §"Total Ordering for
    // Nearest") and the graph-only rule-table rows. ---------------------------

    /// The staff instance a voice lives in, from the base-free ledger index.
    fn voice_instance(&self, voice: VoiceId) -> Option<StaffInstanceId> {
        self.instance_voices
            .iter()
            .find_map(|(instance, voices)| voices.contains(&voice).then_some(*instance))
    }

    /// The region a staff instance lives in, from the base-free ledger index.
    fn instance_region_of(&self, instance: StaffInstanceId) -> Option<RegionId> {
        self.region_instances
            .iter()
            .find_map(|(region, instances)| instances.contains(&instance).then_some(*region))
    }

    /// The voice of a live event with an indexed metric placement.
    fn event_voice(&self, event: EventId) -> Option<VoiceId> {
        self.voice_occupancy.iter().find_map(|(voice, placements)| {
            placements
                .iter()
                .any(|(_, _, placed)| *placed == event)
                .then_some(*voice)
        })
    }

    /// Containment proximity (key 1 of the "nearest" ordering): same voice 0,
    /// same staff instance 1, same staff 2, same region 3, same canvas 4.
    /// Computed from the base-free ledger indices, so `reduce()` and
    /// `reduce_onto()` rank identically wherever both represent the scenario.
    /// Whether a rank-4 verdict from [`Self::containment_rank`] was
    /// *established* (both voices' placements resolve through instance and
    /// region, so "same canvas" is a proven fact of the singleton canvas)
    /// rather than the unresolvable-placement fallthrough. Recording reads
    /// this so an unestablished 4 stays the honest `ExplicitFallback`
    /// (Pass 12, P12-C4) — selection order is unaffected either way.
    fn canvas_rank_established(&self, referent_voice: VoiceId, candidate_voice: VoiceId) -> bool {
        let (Some(referent), Some(candidate)) = (
            self.voice_instance(referent_voice),
            self.voice_instance(candidate_voice),
        ) else {
            return false;
        };
        self.instance_region_of(referent).is_some() && self.instance_region_of(candidate).is_some()
    }

    /// The [`ReanchorReason`] to *record* for an achieved rank: ranks 0–3 map
    /// directly; rank 4 records `SameCanvasNearer` only when the proximity
    /// was established ([`Self::canvas_rank_established`]), else the honest
    /// `ExplicitFallback`. `survivor_voice` is `None` when the winning
    /// candidate's voice is itself unresolvable — never established.
    fn rank_reason(
        &self,
        rank: u8,
        referent_voice: VoiceId,
        survivor_voice: Option<VoiceId>,
    ) -> ReanchorReason {
        if rank == 4 {
            let established = survivor_voice
                .is_some_and(|survivor| self.canvas_rank_established(referent_voice, survivor));
            return if established {
                ReanchorReason::SameCanvasNearer
            } else {
                ReanchorReason::ExplicitFallback
            };
        }
        reason_for_rank(rank)
    }

    fn containment_rank(&self, referent_voice: VoiceId, candidate_voice: VoiceId) -> u8 {
        if referent_voice == candidate_voice {
            return 0;
        }
        let (Some(referent), Some(candidate)) = (
            self.voice_instance(referent_voice),
            self.voice_instance(candidate_voice),
        ) else {
            return 4;
        };
        if referent == candidate {
            return 1;
        }
        if let (Some(a), Some(b)) = (
            self.instance_staff.get(&referent),
            self.instance_staff.get(&candidate),
        ) {
            if a == b {
                return 2;
            }
        }
        if let (Some(a), Some(b)) = (
            self.instance_region_of(referent),
            self.instance_region_of(candidate),
        ) {
            if a == b {
                return 3;
            }
        }
        4
    }

    /// The nearest surviving live event to the tombstoned referent under the
    /// four-key total order (Chapter 6 §"Total Ordering for Nearest"): the
    /// strict lexicographic minimum of (containment proximity, absolute time
    /// distance from the referent's resolved position, forward before
    /// backward, typed id bytes ascending — an `EventId`'s numeric order *is*
    /// its canonical 16-byte order). Candidates ranked farther than `max_rank`
    /// are excluded. Read entirely from the canonical ledger indices, so the
    /// choice is a function of canonical state (permutation-invariant). Only
    /// *metric* placements are indexed; wall-clock distance (proportional
    /// regions) is a deferred refinement, so a wall-clock referent finds no
    /// candidate and falls to the kind's declared failure action.
    fn nearest_live_event(
        &self,
        referent: &ReferentContext,
        exclude: EventId,
        max_rank: u8,
    ) -> Option<(EventId, u8)> {
        let EventPosition::Musical(referent_position) = &referent.position else {
            return None;
        };
        let mut best: Option<(u8, RationalTime, u8, EventId)> = None;
        for (voice, placements) in &self.voice_occupancy {
            let rank = self.containment_rank(referent.voice, *voice);
            if rank > max_rank {
                continue;
            }
            for (position, _, event) in placements {
                if *event == exclude
                    || !matches!(
                        self.objects.get(&TypedObjectId::Event(*event)),
                        Some(ObjectState::Live)
                    )
                {
                    continue;
                }
                let signed = position.0.sub(&referent_position.0);
                let (direction, distance) = if signed.is_negative() {
                    (1u8, RationalTime::zero().sub(&signed))
                } else {
                    (0u8, signed)
                };
                let key = (rank, distance, direction, *event);
                if best.as_ref().is_none_or(|current| key < *current) {
                    best = Some(key);
                }
            }
        }
        best.map(|(rank, _, _, event)| (event, rank))
    }

    /// Drops `dead` from `sid`'s referent-index entry, removing the entry when
    /// no event reference remains.
    fn drop_structure_ref(&mut self, sid: TypedObjectId, dead: TypedObjectId) {
        if let Some(refs) = self.structures.get_mut(&sid) {
            refs.retain(|existing| *existing != dead);
            if refs.is_empty() {
                self.structures.remove(&sid);
            }
        }
    }

    /// The rule-table rows for the graph-only referent kinds — markers, cue
    /// events, comments, analytical annotations, graphic gestures (Chapter 6
    /// §"The Re-Anchoring Rule Table"). Runs from
    /// [`Self::materialize_graph_delete`], so both the DeleteEvent path and the
    /// undo path record the same repairs in the triggering operation's effect.
    /// Each row's ledger record and graph mutation are decided together, in
    /// canonical id order ("the graph follows the ledger").
    fn reanchor_event_referents(
        &mut self,
        env: &OperationEnvelope,
        deleted: EventId,
        referent: &ReferentContext,
    ) -> Vec<RepairRecord> {
        let mut repairs = Vec::new();
        let deleted_obj = TypedObjectId::Event(deleted);
        // The deleted event's own referent entry (a cue's source list) dies
        // with it.
        self.structures.remove(&deleted_obj);
        let referencing: Vec<TypedObjectId> = self
            .structures
            .iter()
            .filter(|(sid, refs)| {
                matches!(
                    sid,
                    TypedObjectId::Marker(_)
                        | TypedObjectId::Comment(_)
                        | TypedObjectId::AnalyticalAnnotation(_)
                        | TypedObjectId::GraphicGesture(_)
                        | TypedObjectId::Event(_)
                ) && refs.contains(&deleted_obj)
                    && matches!(self.objects.get(sid), Some(ObjectState::Live))
            })
            .map(|(sid, _)| *sid)
            .collect();
        for sid in referencing {
            match sid {
                TypedObjectId::Marker(_) => {
                    self.reanchor_marker(deleted, referent, sid, &mut repairs)
                }
                TypedObjectId::Event(cue) => self.cascade_cue(env, cue, &mut repairs),
                TypedObjectId::Comment(_) => {
                    self.orphan_comment(deleted, referent, sid, &mut repairs)
                }
                TypedObjectId::AnalyticalAnnotation(_) => {
                    self.reanchor_annotation(deleted, referent, sid, &mut repairs)
                }
                TypedObjectId::GraphicGesture(_) => {
                    self.reanchor_gesture(deleted, referent, sid, &mut repairs)
                }
                _ => {}
            }
        }
        repairs
    }

    /// Row "Marker / Anchor": re-anchor to the nearest event in the same staff
    /// instance (proximity max: same staff instance); orphan on failure.
    fn reanchor_marker(
        &mut self,
        deleted: EventId,
        referent: &ReferentContext,
        sid: TypedObjectId,
        repairs: &mut Vec<RepairRecord>,
    ) {
        let TypedObjectId::Marker(marker) = sid else {
            return;
        };
        match self.nearest_live_event(referent, deleted, PROXIMITY_SAME_STAFF_INSTANCE) {
            Some((to, rank)) => {
                if let Some(score) = self.graph.as_mut() {
                    if let Some(value) = score
                        .cross_cutting
                        .markers
                        .iter_mut()
                        .find(|value| value.id == marker)
                    {
                        if let TimeAnchor::Event { id, .. } = &mut value.anchor {
                            if *id == deleted {
                                // The anchor offset is preserved: the survivor
                                // shares the staff instance, hence the region
                                // and its offset discipline (invariant 9).
                                *id = to;
                            }
                        }
                    }
                }
                self.structures.insert(sid, vec![TypedObjectId::Event(to)]);
                repairs.push(RepairRecord {
                    kind: RepairKind::Reanchored {
                        from: TypedObjectId::Event(deleted),
                        to: TypedObjectId::Event(to),
                        reason: reason_for_rank(rank),
                    },
                    target: sid,
                });
            }
            None => {
                // Orphan: the marker (user content) is kept. Invariant 10
                // rejects a dangling event anchor, so the graph anchor degrades
                // to the containing region's start — anchor hygiene, not a
                // re-anchoring choice; the ledger records the orphaning.
                if let Some(region) = referent.region {
                    if let Some(score) = self.graph.as_mut() {
                        if let Some(value) = score
                            .cross_cutting
                            .markers
                            .iter_mut()
                            .find(|value| value.id == marker)
                        {
                            if matches!(value.anchor, TimeAnchor::Event { id, .. } if id == deleted)
                            {
                                value.anchor = TimeAnchor::Region {
                                    id: region,
                                    edge: RegionEdge::Start,
                                    offset: AnchorOffset::Zero,
                                };
                            }
                        }
                    }
                }
                self.structures.remove(&sid);
                repairs.push(RepairRecord {
                    kind: RepairKind::Orphaned,
                    target: sid,
                });
            }
        }
    }

    /// Row "Cue event / Source event": cascade-delete — the plain normative
    /// action, on *any* source deletion (the multi-source rationale tension is
    /// a proposed Pass-12 row). The cascaded cue is itself a tombstoned event,
    /// so the full re-anchoring pass — the graph-only rows via the recursive
    /// `materialize_graph_delete`, and the tie/beam/slur/spanner ledger arm via
    /// `reanchor_for_tombstone` — runs over its own referents transitively, in
    /// the same reduction step.
    fn cascade_cue(
        &mut self,
        env: &OperationEnvelope,
        cue: EventId,
        repairs: &mut Vec<RepairRecord>,
    ) {
        let sid = TypedObjectId::Event(cue);
        // A cue this pass already cascaded transitively (a cue-of-a-cue chain
        // reaching back into the referencing list) must not double-record.
        if !matches!(self.objects.get(&sid), Some(ObjectState::Live)) {
            return;
        }
        let cue_voice = self.event_voice(cue);
        self.cascade_structure(env, sid, repairs);
        self.structures.remove(&sid);
        for events in self.voice_occupancy.values_mut() {
            events.retain(|(_, _, event)| *event != cue);
        }
        self.voice_occupancy.retain(|_, events| !events.is_empty());
        self.event_pitches.remove(&cue);
        let cue_delete = DeleteEventOp {
            event: cue,
            tuplet_compensation: TupletCompensation::NotInTuplet,
        };
        repairs.extend(self.materialize_graph_delete(env, &cue_delete));
        self.reanchor_for_tombstone(env, sid, repairs, cue_voice);
    }

    /// Row "Comment / Anchor": orphan — user content is never silently
    /// deleted. The comment stays live in ledger and graph; its dangling
    /// anchor references degrade to the containing-region forms so invariant
    /// 10 keeps holding.
    fn orphan_comment(
        &mut self,
        deleted: EventId,
        referent: &ReferentContext,
        sid: TypedObjectId,
        repairs: &mut Vec<RepairRecord>,
    ) {
        let TypedObjectId::Comment(comment) = sid else {
            return;
        };
        if let Some(region) = referent.region {
            if let Some(score) = self.graph.as_mut() {
                if let Some(value) = score
                    .cross_cutting
                    .comments
                    .iter_mut()
                    .find(|value| value.id == comment)
                {
                    orphan_annotation_anchor(&mut value.anchor, deleted, region);
                }
            }
        }
        self.drop_structure_ref(sid, TypedObjectId::Event(deleted));
        repairs.push(RepairRecord {
            kind: RepairKind::Orphaned,
            target: sid,
        });
    }

    /// Row "Analytical annotation / Anchor": re-anchor to a time range
    /// preserving the original extent; orphan when the range cannot be
    /// reconstructed. Reconstruction needs the containing region plus an exact
    /// musical placement — the range endpoints become region-start offsets, so
    /// they resolve to the deleted event's exact span. A wall-clock or
    /// indeterminate span is not expressible as a stored region-relative range
    /// (the expressibility gap is a proposed Pass-12 row), so it orphans.
    fn reanchor_annotation(
        &mut self,
        deleted: EventId,
        referent: &ReferentContext,
        sid: TypedObjectId,
        repairs: &mut Vec<RepairRecord>,
    ) {
        let TypedObjectId::AnalyticalAnnotation(annotation) = sid else {
            return;
        };
        let deleted_obj = TypedObjectId::Event(deleted);
        let current = self.graph.as_ref().and_then(|score| {
            score
                .cross_cutting
                .analytical
                .iter()
                .find(|value| value.id == annotation)
                .map(|value| value.anchor.clone())
        });
        let Some(current) = current else {
            self.drop_structure_ref(sid, deleted_obj);
            return;
        };
        // A stale index entry (the anchor no longer references the deleted
        // event) drops the reference with no repair.
        if !annotation_anchor_event_refs(&current).contains(&deleted_obj) {
            self.drop_structure_ref(sid, deleted_obj);
            return;
        }
        let musical_span = match (&referent.position, &referent.duration) {
            (EventPosition::Musical(position), EventDuration::Musical(duration)) => {
                Some((position.0.clone(), duration.0.clone()))
            }
            _ => None,
        };
        let range_point = |resolved: RationalTime, region: RegionId| TimeAnchor::Region {
            id: region,
            edge: RegionEdge::Start,
            offset: AnchorOffset::Musical(MusicalDuration(resolved)),
        };
        let reconstructed: Option<AnnotationAnchor> = match &current {
            AnnotationAnchor::Event(event) if *event == deleted => {
                match (musical_span.as_ref(), referent.region) {
                    (Some((position, duration)), Some(region)) => Some(AnnotationAnchor::Range {
                        start: range_point(position.clone(), region),
                        end: range_point(position.add(duration), region),
                    }),
                    _ => None,
                }
            }
            AnnotationAnchor::Range { start, end } => {
                // Per endpoint: an event-anchored endpoint of the deleted event
                // is rebuilt at its resolved position (the event's position
                // plus any musical anchor offset); live endpoints are kept.
                let rebuild = |endpoint: &TimeAnchor| -> Option<TimeAnchor> {
                    match endpoint {
                        TimeAnchor::Event { id, offset } if *id == deleted => {
                            let (position, _) = musical_span.as_ref()?;
                            let region = referent.region?;
                            let resolved = match offset {
                                AnchorOffset::Zero => position.clone(),
                                AnchorOffset::Musical(delta) => position.add(&delta.0),
                                AnchorOffset::WallClock(_) => return None,
                            };
                            Some(range_point(resolved, region))
                        }
                        other => Some(other.clone()),
                    }
                };
                match (rebuild(start), rebuild(end)) {
                    (Some(start), Some(end)) => Some(AnnotationAnchor::Range { start, end }),
                    _ => None,
                }
            }
            // Stale index entry (the anchor no longer references the deleted
            // event): drop the reference, no repair.
            _ => {
                self.drop_structure_ref(sid, deleted_obj);
                return;
            }
        };
        match reconstructed {
            Some(anchor) => {
                let region = referent
                    .region
                    .expect("range reconstruction required the containing region");
                if let Some(score) = self.graph.as_mut() {
                    if let Some(value) = score
                        .cross_cutting
                        .analytical
                        .iter_mut()
                        .find(|value| value.id == annotation)
                    {
                        value.anchor = anchor;
                    }
                }
                self.drop_structure_ref(sid, deleted_obj);
                repairs.push(RepairRecord {
                    kind: RepairKind::Reanchored {
                        from: deleted_obj,
                        to: TypedObjectId::Region(region),
                        reason: ReanchorReason::ExplicitFallback,
                    },
                    target: sid,
                });
            }
            None => {
                if let Some(region) = referent.region {
                    if let Some(score) = self.graph.as_mut() {
                        if let Some(value) = score
                            .cross_cutting
                            .analytical
                            .iter_mut()
                            .find(|value| value.id == annotation)
                        {
                            orphan_annotation_anchor(&mut value.anchor, deleted, region);
                        }
                    }
                }
                self.drop_structure_ref(sid, deleted_obj);
                repairs.push(RepairRecord {
                    kind: RepairKind::Orphaned,
                    target: sid,
                });
            }
        }
    }

    /// Row "Graphic gesture / Anchor event": re-anchor each deleted event
    /// reference to the nearest surviving event of the same staff instance
    /// (proximity max: same staff instance); with no candidate the reference is
    /// dropped — truncation while references remain, orphaning when the list
    /// empties. Range anchoring truncates (dead endpoints move to the region
    /// edges); Free anchoring is never indexed.
    fn reanchor_gesture(
        &mut self,
        deleted: EventId,
        referent: &ReferentContext,
        sid: TypedObjectId,
        repairs: &mut Vec<RepairRecord>,
    ) {
        let TypedObjectId::GraphicGesture(gesture) = sid else {
            return;
        };
        let deleted_obj = TypedObjectId::Event(deleted);
        let current = self.graph.as_ref().and_then(|score| {
            score
                .cross_cutting
                .graphic_gestures
                .iter()
                .find(|value| value.id == gesture)
                .map(|value| value.anchoring.clone())
        });
        let Some(anchoring) = current else {
            self.drop_structure_ref(sid, deleted_obj);
            return;
        };
        let set_anchoring = |reducer: &mut Self, anchoring: GestureAnchoring| {
            if let Some(score) = reducer.graph.as_mut() {
                if let Some(value) = score
                    .cross_cutting
                    .graphic_gestures
                    .iter_mut()
                    .find(|value| value.id == gesture)
                {
                    value.anchoring = anchoring;
                }
            }
        };
        match anchoring {
            GestureAnchoring::Events(events) => {
                if !events.contains(&deleted) {
                    self.drop_structure_ref(sid, deleted_obj);
                    return;
                }
                match self.nearest_live_event(referent, deleted, PROXIMITY_SAME_STAFF_INSTANCE) {
                    Some((to, rank)) => {
                        let retargeted: Vec<EventId> = events
                            .iter()
                            .map(|event| if *event == deleted { to } else { *event })
                            .collect();
                        self.structures.insert(
                            sid,
                            retargeted
                                .iter()
                                .copied()
                                .map(TypedObjectId::Event)
                                .collect(),
                        );
                        set_anchoring(self, GestureAnchoring::Events(retargeted));
                        repairs.push(RepairRecord {
                            kind: RepairKind::Reanchored {
                                from: deleted_obj,
                                to: TypedObjectId::Event(to),
                                reason: reason_for_rank(rank),
                            },
                            target: sid,
                        });
                    }
                    None => {
                        let remaining: Vec<EventId> = events
                            .iter()
                            .copied()
                            .filter(|event| *event != deleted)
                            .collect();
                        let emptied = remaining.is_empty();
                        if emptied {
                            self.structures.remove(&sid);
                        } else {
                            self.structures.insert(
                                sid,
                                remaining
                                    .iter()
                                    .copied()
                                    .map(TypedObjectId::Event)
                                    .collect(),
                            );
                        }
                        set_anchoring(self, GestureAnchoring::Events(remaining));
                        repairs.push(RepairRecord {
                            kind: if emptied {
                                // The reference list emptied: the gesture (user
                                // content) is kept, reference-free.
                                RepairKind::Orphaned
                            } else {
                                RepairKind::SpannerTruncated {
                                    removed_members: vec![deleted_obj],
                                }
                            },
                            target: sid,
                        });
                    }
                }
            }
            GestureAnchoring::Range { start, end, staves } => {
                let Some(region) = referent.region else {
                    self.drop_structure_ref(sid, deleted_obj);
                    return;
                };
                let mut start = start;
                let mut end = end;
                retarget_dead_endpoint(&mut start, deleted, region, RegionEdge::Start);
                retarget_dead_endpoint(&mut end, deleted, region, RegionEdge::End);
                set_anchoring(self, GestureAnchoring::Range { start, end, staves });
                self.drop_structure_ref(sid, deleted_obj);
                repairs.push(RepairRecord {
                    kind: RepairKind::Reanchored {
                        from: deleted_obj,
                        to: TypedObjectId::Region(region),
                        reason: ReanchorReason::ExplicitFallback,
                    },
                    target: sid,
                });
            }
            GestureAnchoring::Free => {
                self.drop_structure_ref(sid, deleted_obj);
            }
        }
    }

    // --- Transactions (Chapter 6 §6.6). -------------------------------------

    fn reduce_transaction_block(&mut self, tx: TransactionId, members: &[&'a OperationEnvelope]) {
        let ordered = canonical_reduction_order(members);
        // Descriptor-precedence rule: the DeclareTransaction must be present and
        // causally precede every member.
        let desc = self.descriptors.get(&tx).copied();
        let well_formed = desc.is_some()
            && ordered
                .iter()
                .all(|m| m.causal_context.covers(desc.expect("checked is_some")));
        if !well_formed {
            let member_ids: Vec<OperationId> = ordered.iter().map(|m| m.id).collect();
            let conflict = ConflictRecord::new(
                ConflictKind::TransactionConflict {
                    transaction: tx,
                    failed_members: member_ids.clone(),
                },
                member_ids,
                vec![],
            );
            self.conflicts.insert(conflict);
            for m in &ordered {
                self.effects.push((
                    m.id,
                    OperationEffect::NoOp {
                        reason: NoOpReason::TransactionConflict,
                    },
                ));
            }
            return;
        }

        // Atomic: apply members against a snapshot; if any fails, roll back.
        let snapshot = self.snapshot();
        self.current_tx = Some(tx);
        let mut member_effects: Vec<(OperationId, OperationEffect)> = Vec::new();
        let mut failed_members: Vec<OperationId> = Vec::new();
        for m in &ordered {
            let eff = self.apply(m);
            if is_member_failure(&eff) {
                failed_members.push(m.id);
            }
            member_effects.push((m.id, eff));
        }
        self.current_tx = None;

        if failed_members.is_empty() {
            for (id, eff) in member_effects {
                self.effects.push((id, eff));
            }
        } else {
            self.restore(snapshot);
            let member_ids: Vec<OperationId> = ordered.iter().map(|m| m.id).collect();
            let conflict = ConflictRecord::new(
                ConflictKind::TransactionConflict {
                    transaction: tx,
                    failed_members,
                },
                member_ids,
                vec![],
            );
            self.conflicts.insert(conflict);
            for m in &ordered {
                self.effects.push((
                    m.id,
                    OperationEffect::NoOp {
                        reason: NoOpReason::TransactionConflict,
                    },
                ));
            }
        }
    }

    /// Records an object as minted by the operation's transaction (if any), so
    /// undo can compensate it later.
    fn note_minted(&mut self, _env: &OperationEnvelope, obj: TypedObjectId) {
        if let Some(tx) = self.current_tx {
            self.tx_minted.entry(tx).or_default().push(obj);
        }
    }

    fn concurrent(&self, a: OperationId, b: OperationId) -> bool {
        let a_ctx = self
            .env_of(a)
            .map(|e| e.causal_context.covers(b))
            .unwrap_or(false);
        let b_ctx = self
            .env_of(b)
            .map(|e| e.causal_context.covers(a))
            .unwrap_or(false);
        !a_ctx && !b_ctx
    }

    fn snapshot(&self) -> WorkingSnapshot {
        WorkingSnapshot {
            objects: self.objects.clone(),
            spellings: self.spellings.clone(),
            breaks: self.breaks.clone(),
            page_breaks: self.page_breaks.clone(),
            conflicts: self.conflicts.clone(),
            minted_by: self.minted_by.clone(),
            event_pitches: self.event_pitches.clone(),
            voice_occupancy: self.voice_occupancy.clone(),
            respell_chain: self.respell_chain.clone(),
            engraved_spelling_chain: self.engraved_spelling_chain.clone(),
            event_modify_chain: self.event_modify_chain.clone(),
            pitch_modify_chain: self.pitch_modify_chain.clone(),
            cross_cutting_modify_chain: self.cross_cutting_modify_chain.clone(),
            metric_grid_chain: self.metric_grid_chain.clone(),
            metadata_chain: self.metadata_chain.clone(),
            canvas_layout_defaults_chain: self.canvas_layout_defaults_chain.clone(),
            spelling_precedence_chain: self.spelling_precedence_chain.clone(),
            tuning_context_chain: self.tuning_context_chain.clone(),
            break_chain: self.break_chain.clone(),
            page_break_chain: self.page_break_chain.clone(),
            meter_change_chain: self.meter_change_chain.clone(),
            tempo_segment_chain: self.tempo_segment_chain.clone(),
            staff_layout_chain: self.staff_layout_chain.clone(),
            staff_values: self.staff_values.clone(),
            time_signature_values: self.time_signature_values.clone(),
            instrument_values: self.instrument_values.clone(),
            staff_group_values: self.staff_group_values.clone(),
            part_definition_values: self.part_definition_values.clone(),
            analysis_layer_values: self.analysis_layer_values.clone(),
            view_values: self.view_values.clone(),
            measure_values: self.measure_values.clone(),
            repeat_values: self.repeat_values.clone(),
            instance_grid: self.instance_grid.clone(),
            structures: self.structures.clone(),
            region_instances: self.region_instances.clone(),
            instance_voices: self.instance_voices.clone(),
            instance_staff: self.instance_staff.clone(),
            staff_based_regions: self.staff_based_regions.clone(),
            migrated_regions: self.migrated_regions.clone(),
            region_migrator: self.region_migrator.clone(),
            descriptors: self.descriptors.clone(),
            tx_minted: self.tx_minted.clone(),
            graph: self.graph.clone(),
        }
    }

    fn restore(&mut self, s: WorkingSnapshot) {
        self.objects = s.objects;
        self.spellings = s.spellings;
        self.breaks = s.breaks;
        self.page_breaks = s.page_breaks;
        self.conflicts = s.conflicts;
        self.minted_by = s.minted_by;
        self.event_pitches = s.event_pitches;
        self.voice_occupancy = s.voice_occupancy;
        self.respell_chain = s.respell_chain;
        self.engraved_spelling_chain = s.engraved_spelling_chain;
        self.event_modify_chain = s.event_modify_chain;
        self.pitch_modify_chain = s.pitch_modify_chain;
        self.cross_cutting_modify_chain = s.cross_cutting_modify_chain;
        self.metric_grid_chain = s.metric_grid_chain;
        self.metadata_chain = s.metadata_chain;
        self.canvas_layout_defaults_chain = s.canvas_layout_defaults_chain;
        self.spelling_precedence_chain = s.spelling_precedence_chain;
        self.tuning_context_chain = s.tuning_context_chain;
        self.break_chain = s.break_chain;
        self.page_break_chain = s.page_break_chain;
        self.meter_change_chain = s.meter_change_chain;
        self.tempo_segment_chain = s.tempo_segment_chain;
        self.staff_layout_chain = s.staff_layout_chain;
        self.staff_values = s.staff_values;
        self.time_signature_values = s.time_signature_values;
        self.instrument_values = s.instrument_values;
        self.staff_group_values = s.staff_group_values;
        self.part_definition_values = s.part_definition_values;
        self.analysis_layer_values = s.analysis_layer_values;
        self.view_values = s.view_values;
        self.measure_values = s.measure_values;
        self.repeat_values = s.repeat_values;
        self.instance_grid = s.instance_grid;
        self.structures = s.structures;
        self.region_instances = s.region_instances;
        self.instance_voices = s.instance_voices;
        self.instance_staff = s.instance_staff;
        self.staff_based_regions = s.staff_based_regions;
        self.migrated_regions = s.migrated_regions;
        self.region_migrator = s.region_migrator;
        self.descriptors = s.descriptors;
        self.tx_minted = s.tx_minted;
        self.graph = s.graph;
    }
}

/// Whether a transaction member's effect counts as an invariant-precondition
/// failure that conflicts the whole transaction (Chapter 6 §6.6).
fn is_member_failure(effect: &OperationEffect) -> bool {
    matches!(
        effect,
        OperationEffect::Conflicted { .. }
            | OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction { .. }
            }
            | OperationEffect::NoOp {
                reason: NoOpReason::TargetTombstoned
            }
    )
}

/// The transaction an envelope is a *member* of: its `transaction` field, unless
/// it is the `DeclareTransaction` descriptor itself (which is not a member of
/// the transaction it declares).
fn member_transaction(env: &OperationEnvelope) -> Option<TransactionId> {
    let tx = env.transaction?;
    if let OperationPayload::Primitive(OperationKind::DeclareTransaction(desc)) = &env.payload {
        if desc.id == tx {
            return None;
        }
    }
    Some(tx)
}

/// Groups active operations into transaction blocks by membership.
fn transaction_members<'a>(
    active: &[&'a OperationEnvelope],
) -> BTreeMap<TransactionId, Vec<&'a OperationEnvelope>> {
    let mut map: BTreeMap<TransactionId, Vec<&'a OperationEnvelope>> = BTreeMap::new();
    for env in active {
        if let Some(tx) = member_transaction(env) {
            map.entry(tx).or_default().push(env);
        }
    }
    map
}

/// Computes which reducible operations are held pending under the
/// missing-causal-predecessor rule (Chapter 6 §6.5, §6.6), and why.
///
/// An operation is directly blocked if a causal predecessor is absent,
/// equivocated, or excluded; the block then propagates transitively to anything
/// that causally depends on a blocked operation. Ties between multiple blocking
/// causes are broken by smallest blocker `OperationId`, so the reason is
/// deterministic.
fn compute_pending(
    reducible: &[&OperationEnvelope],
    reducible_ids: &BTreeSet<OperationId>,
    equivocated: &BTreeSet<OperationId>,
    excluded: &BTreeSet<OperationId>,
    declared_transactions: &BTreeSet<TransactionId>,
) -> BTreeMap<OperationId, PendingReason> {
    let mut blocked: BTreeMap<OperationId, PendingReason> = BTreeMap::new();
    let known_ids: BTreeSet<OperationId> = reducible_ids
        .iter()
        .chain(equivocated)
        .chain(excluded)
        .copied()
        .collect();
    // Direct causes: a hole in an asserted contiguous vector range, a dot
    // referencing a non-reducible id, or coverage of a known bad id.
    for env in reducible {
        // An absent transaction descriptor has a more specific normative
        // outcome: TransactionConflict. Let transaction reduction report it
        // instead of masking it as an ordinary missing predecessor.
        if member_transaction(env).is_some_and(|tx| !declared_transactions.contains(&tx)) {
            continue;
        }
        let mut causes: Vec<(OperationId, PendingReason)> = Vec::new();
        if let Some(missing) = first_missing_vector_predecessor(env, &known_ids) {
            causes.push((missing, PendingReason::MissingCausalPredecessor { missing }));
        }
        for d in env.causal_context.dots() {
            if !reducible_ids.contains(&d) {
                let reason = if equivocated.contains(&d) {
                    PendingReason::DependsOnEquivocated { on: d }
                } else if excluded.contains(&d) {
                    PendingReason::DependsOnExcluded { on: d }
                } else {
                    PendingReason::MissingCausalPredecessor { missing: d }
                };
                causes.push((d, reason));
            }
        }
        for e in equivocated {
            if env.causal_context.covers(*e) {
                causes.push((*e, PendingReason::DependsOnEquivocated { on: *e }));
            }
        }
        for x in excluded {
            if env.causal_context.covers(*x) {
                causes.push((*x, PendingReason::DependsOnExcluded { on: *x }));
            }
        }
        if let Some((_, reason)) = causes.into_iter().min_by_key(|(id, _)| *id) {
            blocked.insert(env.id, reason);
        }
    }

    // Transitive propagation: an op covering a blocked op is itself blocked.
    loop {
        let mut changed = false;
        for env in reducible {
            if blocked.contains_key(&env.id) {
                continue;
            }
            // Smallest blocked id this op covers.
            let cover = blocked
                .keys()
                .copied()
                .find(|b| env.causal_context.covers(*b));
            if let Some(on) = cover {
                blocked.insert(env.id, PendingReason::DependsOnPending { on });
                changed = true;
            }
        }
        if !changed {
            break;
        }
    }

    blocked
}

/// Finds the smallest absent id asserted by a causal context's contiguous
/// vector ranges without expanding those ranges counter by counter.
fn first_missing_vector_predecessor(
    env: &OperationEnvelope,
    known_ids: &BTreeSet<OperationId>,
) -> Option<OperationId> {
    let mut first_missing = None;

    for (&replica, &high) in &env.causal_context.vector {
        let mut expected = 0_u64;
        let mut complete = false;

        for id in known_ids.range(OperationId::new(replica, 0)..=OperationId::new(replica, high)) {
            if id.counter > expected {
                break;
            }
            if id.counter == expected {
                if expected == high {
                    complete = true;
                    break;
                }
                expected += 1;
            }
        }

        if !complete {
            let candidate = OperationId::new(replica, expected);
            if first_missing.is_none_or(|current| candidate < current) {
                first_missing = Some(candidate);
            }
        }
    }

    first_missing
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::causal::CausalContext;
    use crate::stamp::{HybridLogicalClock, OperationStamp};
    use crate::support::AuthorId;
    use epiphany_core::{IdentityContext, RationalTime, ReplicaId, StaffInstanceId, WallClockTime};

    fn pos(n: i64) -> MusicalPosition {
        MusicalPosition(RationalTime::from_int(n as i32))
    }

    // -----------------------------------------------------------------
    // G-minor (`spec/PLAN_GMINOR_SCHEMA_MINOR.md` §4, pin 5): s7.
    // -----------------------------------------------------------------

    #[test]
    fn s7_a_canonical_base_whose_effects_include_same_canvas_nearer_stamps_5() {
        use epiphany_core::EventId;
        let from = TypedObjectId::Event(EventId::new(ReplicaId(1), 1));
        let to = TypedObjectId::Event(EventId::new(ReplicaId(1), 2));
        let state = MaterializedState {
            effects: vec![(
                OperationId::new(ReplicaId(1), 1),
                OperationEffect::AppliedWithRepair {
                    repairs: vec![RepairRecord {
                        kind: RepairKind::Reanchored {
                            from,
                            to,
                            reason: ReanchorReason::SameCanvasNearer,
                        },
                        target: from,
                    }],
                },
            )],
            ..Default::default()
        };
        assert_eq!(state.introduced_minor(), Some(5));
    }

    #[test]
    fn s7_a_canonical_base_without_the_effect_stamps_baseline_even_from_kind_33_sources() {
        // The base's own bytes carry only a plain `Applied` effect — never an
        // `OperationKind`, `OperationKindTag`, or `OperationPayload` — so even
        // though the *source operation* that produced it (not modeled in this
        // state at all, by construction: pin 5) might have been kind 33
        // (`SetSpellingPrecedence`, epoch 9), the base itself must not be
        // dragged to epoch 9. It has no additive requirement.
        let state = MaterializedState {
            effects: vec![(OperationId::new(ReplicaId(1), 1), OperationEffect::Applied)],
            ..Default::default()
        };
        assert_eq!(state.introduced_minor(), None);
    }

    fn insert(
        replica: u64,
        counter: u64,
        physical: i64,
        voice: u64,
        event: u64,
        pos_units: i64,
    ) -> OperationEnvelope {
        let id = OperationId::new(ReplicaId(replica), counter);
        OperationEnvelope {
            id,
            author: AuthorId(0),
            stamp: OperationStamp::new(HybridLogicalClock::new(WallClockTime(physical), 0), id),
            causal_context: CausalContext::new(),
            transaction: None,
            payload: OperationPayload::Primitive(OperationKind::InsertEvent(InsertEventOp {
                // Voice and staff instance live in a shared (author-independent)
                // namespace so two authors can target the same voice.
                staff_instance: StaffInstanceId::new(ReplicaId(9), 0),
                event: crate::valuegen::insert_event_value(
                    EventId::new(ReplicaId(replica), event),
                    VoiceId::new(ReplicaId(9), voice),
                    pos(pos_units),
                    epiphany_core::MusicalDuration::whole(),
                    &[],
                ),
            })),
        }
    }

    // --- Subquadratic canonical order vs. the retained O(n²) oracle. --------

    /// A minimal envelope for pure ordering tests: payload content never
    /// affects the canonical reduction order.
    fn order_env(
        replica: ReplicaId,
        counter: u64,
        physical: i64,
        logical: u32,
        ctx: CausalContext,
    ) -> OperationEnvelope {
        let id = OperationId::new(replica, counter);
        OperationEnvelope {
            id,
            author: AuthorId(1),
            stamp: OperationStamp::new(
                HybridLogicalClock::new(WallClockTime(physical), logical),
                id,
            ),
            causal_context: ctx,
            transaction: None,
            payload: OperationPayload::Primitive(OperationKind::DeleteEvent(DeleteEventOp {
                event: EventId::new(ReplicaId(7), counter % 5),
                tuplet_compensation: TupletCompensation::NotInTuplet,
            })),
        }
    }

    /// Asserts the subquadratic order equals the reference oracle's
    /// element-for-element — by slice element identity (pointer equality), the
    /// strictest possible check: it distinguishes even byte-identical
    /// duplicate envelopes, whose tuple ties both implementations must break
    /// by slice position.
    fn assert_order_matches_reference(envelopes: &[OperationEnvelope]) {
        let refs: Vec<&OperationEnvelope> = envelopes.iter().collect();
        let fast = canonical_reduction_order(&refs);
        let oracle = canonical_reduction_order_reference(&refs);
        assert_eq!(fast.len(), oracle.len());
        for (at, (a, b)) in fast.iter().zip(&oracle).enumerate() {
            assert!(
                std::ptr::eq(*a, *b),
                "canonical order diverges from the reference at position {at}: \
                 {:?} vs {:?} (n = {})",
                a.id,
                b.id,
                envelopes.len()
            );
        }
    }

    /// In-place Fisher–Yates driven by the seeded generator (slice order is an
    /// input to the tuple tie-break, so permutations must be exercised too).
    fn shuffle_envelopes(
        envelopes: &mut [OperationEnvelope],
        rng: &mut epiphany_determinism::fuzz::SplitMix64,
    ) {
        for i in (1..envelopes.len()).rev() {
            let j = (rng.next_u64() % (i as u64 + 1)) as usize;
            envelopes.swap(i, j);
        }
    }

    /// A hostile ordering input the crate's well-formed generators avoid:
    /// floors that cover the envelope's own id or absent counters, dots to
    /// present / absent / own ids, duplicate ids (byte-identical twins),
    /// `SYSTEM_DERIVED` replicas, colliding stamps that contradict the causal
    /// edges (so the topological pass and the cycle-breaker both engage), and
    /// empty contexts.
    fn adversarial_set(
        rng: &mut epiphany_determinism::fuzz::SplitMix64,
        n: usize,
    ) -> Vec<OperationEnvelope> {
        let replicas = 1 + rng.next_u64() % 4;
        let mut next_counter: BTreeMap<ReplicaId, u64> = BTreeMap::new();
        let mut envs: Vec<OperationEnvelope> = Vec::with_capacity(n);
        for _ in 0..n {
            if !envs.is_empty() && rng.next_u64() % 8 == 0 {
                // A duplicate id — and a byte-identical stamp, so the
                // reduction tuple genuinely ties.
                let victim = envs[(rng.next_u64() % envs.len() as u64) as usize].clone();
                envs.push(victim);
                continue;
            }
            let replica = if rng.next_u64() % 16 == 0 {
                ReplicaId::SYSTEM_DERIVED
            } else {
                ReplicaId(1 + rng.next_u64() % replicas)
            };
            let slot = next_counter.entry(replica).or_insert(0);
            // Occasionally skip counters so floors assert absent predecessors.
            let counter = *slot + rng.next_u64() % 2;
            *slot = counter + 1;
            let id = OperationId::new(replica, counter);

            let mut ctx = CausalContext::new();
            for _ in 0..rng.next_u64() % 3 {
                let target = match rng.next_u64() % 5 {
                    0 => replica,      // may cover the envelope's own id
                    1 => ReplicaId(9), // absent replica
                    2 => ReplicaId::SYSTEM_DERIVED,
                    _ => ReplicaId(1 + rng.next_u64() % replicas),
                };
                // May exceed every present counter (covering future authoring
                // of that replica — a causal cycle) or fall below all of them.
                ctx = ctx.with_seen(target, rng.next_u64() % 8);
            }
            for _ in 0..rng.next_u64() % 3 {
                let dot = if !envs.is_empty() && rng.next_u64() % 2 == 0 {
                    envs[(rng.next_u64() % envs.len() as u64) as usize].id
                } else if rng.next_u64() % 4 == 0 {
                    id // the envelope's own id
                } else {
                    OperationId::new(ReplicaId(1 + rng.next_u64() % 5), rng.next_u64() % 10)
                };
                ctx = ctx.with_dot(dot);
            }

            // Tiny stamp ranges force heavy tuple collisions and stamps that
            // contradict the causal edges.
            envs.push(order_env(
                replica,
                counter,
                (rng.next_u64() % 6) as i64,
                (rng.next_u64() % 3) as u32,
                ctx,
            ));
        }
        envs
    }

    #[test]
    fn canonical_order_matches_reference_on_fuzz_sets() {
        // The crate's own well-formed generator: multi-replica meshes of
        // vector floors, occasional equivocation twins (duplicate ids) and
        // HLC-monotonicity anomalies, empty contexts on counter-0 roots.
        let mut rng = epiphany_determinism::fuzz::SplitMix64::new(0xF1_0DE2_0001);
        for _ in 0..250 {
            let n = 1 + (rng.next_u64() % 40) as usize;
            let mut envs = crate::fuzz::gen_envelope_set(&mut rng, n);
            assert_order_matches_reference(&envs);
            shuffle_envelopes(&mut envs, &mut rng);
            assert_order_matches_reference(&envs);
        }
    }

    #[test]
    fn canonical_order_matches_reference_on_adversarial_sets() {
        let mut rng = epiphany_determinism::fuzz::SplitMix64::new(0xADE5_A71A_0002);
        assert_order_matches_reference(&[]);
        for iteration in 0..400 {
            let n = 1 + (rng.next_u64() % 60) as usize;
            let mut envs = adversarial_set(&mut rng, n);
            assert_order_matches_reference(&envs);
            if iteration % 4 == 0 {
                shuffle_envelopes(&mut envs, &mut rng);
                assert_order_matches_reference(&envs);
            }
        }
    }

    #[test]
    fn canonical_order_matches_reference_on_directed_shapes() {
        let r = ReplicaId(1);

        // A 2,000-envelope single-replica chain whose every DVV floor covers
        // the full replica prefix — the inherently-quadratic-pairs shape the
        // subquadratic construction exists for — with *descending* stamps, so
        // the causal edges (not the HLC) decide every single emission.
        let full_chain: Vec<OperationEnvelope> = (0..2_000)
            .map(|c| {
                let ctx = if c == 0 {
                    CausalContext::new()
                } else {
                    CausalContext::new().with_seen(r, c - 1)
                };
                order_env(r, c, 2_000 - c as i64, 0, ctx)
            })
            .collect();
        assert_order_matches_reference(&full_chain);

        // A self-covering chain: every floor also covers the envelope's own
        // id (the exempted self-pair).
        let self_chain: Vec<OperationEnvelope> = (0..600)
            .map(|c| {
                order_env(
                    r,
                    c,
                    600 - c as i64,
                    0,
                    CausalContext::new().with_seen(r, c),
                )
            })
            .collect();
        assert_order_matches_reference(&self_chain);

        // A dot-only chain (no vector floors at all).
        let dot_chain: Vec<OperationEnvelope> = (0..600)
            .map(|c| {
                let ctx = if c == 0 {
                    CausalContext::new()
                } else {
                    CausalContext::new().with_dot(OperationId::new(r, c - 1))
                };
                order_env(r, c, 600 - c as i64, 0, ctx)
            })
            .collect();
        assert_order_matches_reference(&dot_chain);

        // Malformed dot cycles (2-cycle and 3-cycle) among bystanders with
        // empty contexts and identical stamps.
        let id = |rep: u64, c: u64| OperationId::new(ReplicaId(rep), c);
        let cycles = vec![
            order_env(
                ReplicaId(2),
                0,
                5,
                0,
                CausalContext::new().with_dot(id(2, 1)),
            ),
            order_env(
                ReplicaId(2),
                1,
                5,
                0,
                CausalContext::new().with_dot(id(2, 0)),
            ),
            order_env(
                ReplicaId(3),
                0,
                5,
                0,
                CausalContext::new().with_dot(id(3, 2)),
            ),
            order_env(
                ReplicaId(3),
                1,
                5,
                0,
                CausalContext::new().with_dot(id(3, 0)),
            ),
            order_env(
                ReplicaId(3),
                2,
                5,
                0,
                CausalContext::new().with_dot(id(3, 1)),
            ),
            order_env(ReplicaId(4), 0, 5, 0, CausalContext::new()),
            order_env(ReplicaId(5), 0, 5, 0, CausalContext::new()),
        ];
        assert_order_matches_reference(&cycles);

        // Mutual full-coverage floors (a floor cycle where each envelope also
        // covers itself), plus coverage of absent ids on an absent replica.
        let floor_cycle = vec![
            order_env(
                ReplicaId(6),
                0,
                9,
                0,
                CausalContext::new().with_seen(ReplicaId(6), 1),
            ),
            order_env(
                ReplicaId(6),
                1,
                8,
                0,
                CausalContext::new().with_seen(ReplicaId(6), 1),
            ),
            order_env(
                ReplicaId(6),
                2,
                7,
                0,
                CausalContext::new()
                    .with_seen(ReplicaId(40), 12)
                    .with_dot(id(41, 3)),
            ),
        ];
        assert_order_matches_reference(&floor_cycle);

        // Byte-identical duplicate ids (tuple ties broken by slice position)
        // in several slice orders, including a dot and a floor onto the
        // duplicated id.
        let twin = order_env(ReplicaId(2), 3, 1, 0, CausalContext::new());
        let mut twins = vec![
            twin.clone(),
            twin.clone(),
            order_env(
                ReplicaId(2),
                4,
                0,
                0,
                CausalContext::new().with_dot(id(2, 3)),
            ),
            order_env(
                ReplicaId(3),
                0,
                0,
                0,
                CausalContext::new().with_seen(ReplicaId(2), 3),
            ),
            // A twin that dots its own id: covers only its duplicate.
            order_env(
                ReplicaId(2),
                3,
                1,
                0,
                CausalContext::new().with_dot(id(2, 3)),
            ),
        ];
        assert_order_matches_reference(&twins);
        twins.reverse();
        assert_order_matches_reference(&twins);
        twins.swap(0, 2);
        assert_order_matches_reference(&twins);

        // SYSTEM_DERIVED authoring under floors and dots from user replicas.
        let sys = ReplicaId::SYSTEM_DERIVED;
        let system = vec![
            order_env(sys, 0, 3, 0, CausalContext::new()),
            order_env(sys, 1, 2, 0, CausalContext::new().with_seen(sys, 0)),
            order_env(
                ReplicaId(2),
                0,
                1,
                0,
                CausalContext::new().with_seen(sys, 1),
            ),
            order_env(
                ReplicaId(2),
                1,
                0,
                0,
                CausalContext::new().with_dot(id(u64::MAX, 0)),
            ),
        ];
        assert_order_matches_reference(&system);
    }

    #[test]
    fn reduction_is_permutation_invariant() {
        let envs = vec![
            insert(1, 0, 10, 1, 100, 0),
            insert(1, 1, 20, 1, 101, 1),
            insert(2, 0, 15, 2, 200, 0),
        ];
        let mut forward = OperationSet::new();
        forward.accept_all(envs.clone());
        let mut backward = OperationSet::new();
        let mut rev = envs.clone();
        rev.reverse();
        backward.accept_all(rev);
        assert_eq!(
            forward.reduce().canonical_bytes(),
            backward.reduce().canonical_bytes()
        );
    }

    #[test]
    fn concurrent_same_position_insert_promotes_the_greater_id() {
        // Two concurrent inserts, same voice and position, different events.
        let a = insert(1, 0, 10, 7, 100, 5);
        let b = insert(2, 0, 10, 7, 200, 5);
        let mut set = OperationSet::new();
        set.accept_all(vec![a.clone(), b.clone()]);
        let state = set.reduce();
        // The greater OperationId (replica 2) is promoted to a system voice.
        let promoted = state
            .effects
            .iter()
            .find(|(id, _)| *id == b.id)
            .map(|(_, e)| e);
        assert!(matches!(
            promoted,
            Some(OperationEffect::AppliedWithRepair { .. })
        ));
        let kept = state
            .effects
            .iter()
            .find(|(id, _)| *id == a.id)
            .map(|(_, e)| e);
        assert_eq!(kept, Some(&OperationEffect::Applied));
    }

    #[test]
    fn resolve_conflict_with_dismiss_reaches_dismissed_state() {
        // Pass 11, item 2.5: an authored ResolveConflict whose action is
        // `Dismiss` must reach the `Dismissed` resolution state (previously
        // `Dismissed` was representable but unreachable by any authored op).
        use crate::conflict::{ConflictResolutionState, ResolutionAction};
        use crate::payload::{ResolveConflictPayload, RespellPitchOp};
        use epiphany_core::PitchId;

        let pitch = PitchId::new(ReplicaId(9), 500);

        // An InsertEvent carrying `pitch` makes the pitch Live.
        let mut insert_env = insert(1, 0, 10, 1, 100, 0);
        if let OperationPayload::Primitive(OperationKind::InsertEvent(ref mut op)) =
            insert_env.payload
        {
            op.event = crate::valuegen::insert_event_value(
                op.event_id(),
                op.voice(),
                op.musical_position(),
                op.musical_duration(),
                &[pitch],
            );
        }

        // Two concurrent, differing respellings of `pitch`, both causally after
        // the insert (so the pitch is Live) but concurrent with each other (so
        // they collide into a StructuralFieldCollision conflict).
        let respell = |replica: u64, counter: u64, physical: i64, byte: u8| {
            let id = OperationId::new(ReplicaId(replica), counter);
            OperationEnvelope {
                id,
                author: AuthorId(0),
                stamp: OperationStamp::new(HybridLogicalClock::new(WallClockTime(physical), 0), id),
                causal_context: CausalContext::new().with_seen(ReplicaId(1), 0),
                transaction: None,
                payload: OperationPayload::Primitive(OperationKind::RespellPitch(RespellPitchOp {
                    pitch,
                    spelling: crate::valuegen::spelling(byte),
                })),
            }
        };
        let respell_a = respell(2, 0, 20, 0xAA);
        let respell_b = respell(3, 0, 21, 0xBB);

        // Phase 1: reduce to discover the content-derived conflict id.
        let mut set = OperationSet::new();
        set.accept_all(vec![
            insert_env.clone(),
            respell_a.clone(),
            respell_b.clone(),
        ]);
        let state = set.reduce();
        assert_eq!(
            state.conflicts.records().len(),
            1,
            "expected exactly one field-collision conflict"
        );
        let cid = state.conflicts.records()[0].id;
        assert_eq!(
            state.conflicts.records()[0].resolution_state,
            ConflictResolutionState::Unresolved
        );

        // Phase 2: author ResolveConflict { Dismiss } against that conflict,
        // causally after the colliding respells so it reduces against the
        // already-created conflict record.
        let resolve_id = OperationId::new(ReplicaId(4), 0);
        let resolve_env = OperationEnvelope {
            id: resolve_id,
            author: AuthorId(0),
            stamp: OperationStamp::new(HybridLogicalClock::new(WallClockTime(30), 0), resolve_id),
            causal_context: CausalContext::new()
                .with_dot(respell_a.id)
                .with_dot(respell_b.id),
            transaction: None,
            payload: OperationPayload::ResolveConflict(ResolveConflictPayload {
                target: cid,
                action: ResolutionAction::Dismiss,
            }),
        };

        let mut set2 = OperationSet::new();
        set2.accept_all(vec![insert_env, respell_a, respell_b, resolve_env]);
        let state2 = set2.reduce();
        let rec = state2
            .conflicts
            .records()
            .iter()
            .find(|r| r.id == cid)
            .expect("conflict still present after resolution");
        assert_eq!(
            rec.resolution_state,
            ConflictResolutionState::Dismissed { by: resolve_id },
            "Dismiss action must select the Dismissed state"
        );
    }

    // --- Group 1 (M2) behavior. --------------------------------------------

    fn prim_env(
        replica: u64,
        counter: u64,
        physical: i64,
        ctx: CausalContext,
        kind: OperationKind,
    ) -> OperationEnvelope {
        let id = OperationId::new(ReplicaId(replica), counter);
        OperationEnvelope {
            id,
            author: AuthorId(0),
            stamp: OperationStamp::new(HybridLogicalClock::new(WallClockTime(physical), 0), id),
            causal_context: ctx,
            transaction: None,
            payload: OperationPayload::Primitive(kind),
        }
    }

    fn modify_event_of(event: EventId, pitch: PitchId) -> OperationKind {
        OperationKind::ModifyEvent(crate::payload::ModifyEventOp {
            event: crate::valuegen::insert_event_value(
                event,
                VoiceId::new(ReplicaId(9), 1),
                pos(0),
                epiphany_core::MusicalDuration::whole(),
                &[pitch],
            ),
        })
    }

    #[test]
    fn concurrent_differing_modify_event_conflicts() {
        let event = EventId::new(ReplicaId(1), 100);
        let seen = CausalContext::new().with_seen(ReplicaId(1), 0);
        // Insert the event (replica 1), then two concurrent differing modifies.
        let insert = insert(1, 0, 10, 1, 100, 0);
        let mod_a = prim_env(
            2,
            0,
            20,
            seen.clone(),
            modify_event_of(event, PitchId::new(ReplicaId(1), 1)),
        );
        let mod_b = prim_env(
            3,
            0,
            20,
            seen,
            modify_event_of(event, PitchId::new(ReplicaId(1), 2)),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![insert, mod_a, mod_b]);
        let state = set.reduce();
        assert_eq!(
            state.conflicts.records().len(),
            1,
            "concurrent differing ModifyEvent must record exactly one conflict"
        );
        assert!(matches!(
            state.conflicts.records()[0].kind,
            ConflictKind::StructuralFieldCollision { .. }
        ));
    }

    // --- ModifyEvent placement changes (trim/move): the make-room enabler. ------

    fn musical(numerator: i64, denominator: i64) -> MusicalDuration {
        MusicalDuration(RationalTime::new(numerator, denominator).unwrap())
    }

    fn position_of(numerator: i64, denominator: i64) -> MusicalPosition {
        MusicalPosition(RationalTime::new(numerator, denominator).unwrap())
    }

    /// An InsertEvent of a rest at an explicit metric span.
    fn insert_at(
        replica: u64,
        counter: u64,
        event: u64,
        voice: u64,
        position: MusicalPosition,
        duration: MusicalDuration,
        ctx: CausalContext,
    ) -> OperationEnvelope {
        prim_env(
            replica,
            counter,
            (counter as i64 + 1) * 10,
            ctx,
            OperationKind::InsertEvent(InsertEventOp {
                staff_instance: StaffInstanceId::new(ReplicaId(9), 0),
                event: crate::valuegen::insert_event_value(
                    EventId::new(ReplicaId(replica), event),
                    VoiceId::new(ReplicaId(9), voice),
                    position,
                    duration,
                    &[],
                ),
            }),
        )
    }

    /// A ModifyEvent that re-places `event` (a rest) at a new metric span.
    fn modify_to(
        replica: u64,
        counter: u64,
        event: u64,
        voice: u64,
        position: MusicalPosition,
        duration: MusicalDuration,
        ctx: CausalContext,
    ) -> OperationEnvelope {
        prim_env(
            replica,
            counter,
            (counter as i64 + 1) * 10,
            ctx,
            OperationKind::ModifyEvent(crate::payload::ModifyEventOp {
                event: crate::valuegen::insert_event_value(
                    EventId::new(ReplicaId(replica), event),
                    VoiceId::new(ReplicaId(9), voice),
                    position,
                    duration,
                    &[],
                ),
            }),
        )
    }

    fn effect_at(state: &MaterializedState, counter: u64) -> Option<&OperationEffect> {
        state
            .effects
            .iter()
            .find(|(id, _)| *id == OperationId::new(ReplicaId(1), counter))
            .map(|(_, effect)| effect)
    }

    #[test]
    fn modify_event_trim_frees_the_voice_slot() {
        // e1 fills [0, 1). Trim it to [0, 1/2), then insert e2 into the freed [1/2, 1):
        // the insert only fits if the trim updated the voice-occupancy index.
        let e1 = insert(1, 0, 10, 1, 100, 0);
        let trim = modify_to(
            1,
            1,
            100,
            1,
            position_of(0, 1),
            musical(1, 2),
            CausalContext::new().with_seen(ReplicaId(1), 0),
        );
        let e2 = insert_at(
            1,
            2,
            101,
            1,
            position_of(1, 2),
            musical(1, 2),
            CausalContext::new().with_seen(ReplicaId(1), 1),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![e1, trim, e2]);
        let state = set.reduce();
        assert!(
            matches!(effect_at(&state, 1), Some(OperationEffect::Applied)),
            "the trim applies"
        );
        assert!(
            matches!(effect_at(&state, 2), Some(OperationEffect::Applied)),
            "the insert fits the span the trim freed (occupancy was updated)"
        );
    }

    #[test]
    fn modify_event_move_onto_a_sibling_is_refused() {
        // e1 [0, 1), e2 [1, 2). Moving e1 onto e2's span would break invariant 3, so
        // it is refused (a clean NoOp), not silently skipped.
        let e1 = insert(1, 0, 10, 1, 100, 0);
        let e2 = insert(1, 1, 20, 1, 101, 1);
        let onto_sibling = modify_to(
            1,
            2,
            100,
            1,
            position_of(1, 1),
            musical(1, 1),
            CausalContext::new().with_seen(ReplicaId(1), 1),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![e1, e2, onto_sibling]);
        let state = set.reduce();
        assert!(
            matches!(
                effect_at(&state, 2),
                Some(OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction {
                        reason: PreconditionFailureReason::EventDurationInvalid,
                    },
                })
            ),
            "a move onto a live sibling is refused"
        );
        assert!(
            state.is_clean(),
            "a refused move records no conflict/anomaly (like an insert overlap no-op)"
        );
    }

    #[test]
    fn modify_event_trim_materializes_in_the_graph() {
        use epiphany_core::check_invariants;
        use epiphany_core::generators::valid_score;

        // Shrink the first metric event's duration; the change must now reach the
        // graph (it was previously deferred) and leave the voice invariant-3 valid.
        let base = valid_score(0x5EED);
        let (event_id, duration) = base
            .voices()
            .flat_map(|(_, _, v)| v.events.clone())
            .find_map(|eid| {
                let ev = base.events.get(eid)?;
                match (ev.position(), ev.duration()) {
                    (EventPosition::Musical(_), EventDuration::Musical(d)) => {
                        Some((eid, d.clone()))
                    }
                    _ => None,
                }
            })
            .expect("the fixture has a metric event");
        let half = MusicalDuration(duration.0.mul(&RationalTime::new(1, 2).unwrap()));
        let mut shrunk = base.events.get(event_id).unwrap().clone();
        match &mut shrunk {
            Event::Pitched(pe) => pe.duration = EventDuration::Musical(half.clone()),
            Event::Rest(rest) => rest.duration = EventDuration::Musical(half.clone()),
            _ => panic!("a metric event is pitched or a rest"),
        }
        let modify = prim_env(
            2,
            0,
            10,
            CausalContext::new(),
            OperationKind::ModifyEvent(crate::payload::ModifyEventOp { event: shrunk }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![modify]);
        let result = set.reduce_onto(&base);
        assert_eq!(
            result.score.events.get(event_id).map(Event::duration),
            Some(&EventDuration::Musical(half)),
            "the trimmed duration is materialized in the graph"
        );
        assert!(
            check_invariants(&result.score).is_empty(),
            "the trimmed voice stays sorted and non-overlapping"
        );
    }

    #[test]
    fn modify_event_does_not_rewrite_a_non_metric_event_as_metric() {
        use epiphany_core::check_invariants;
        use epiphany_core::generators::valid_score_rich;

        // A ModifyEvent that rewrites a wall-clock event (a proportional region) into a
        // metric one must stay deferred — materializing it would re-place a non-metric
        // event onto a musical grid, breaking the region's time-model invariant.
        let base = valid_score_rich(0x5EED);
        let event_id = base
            .voices()
            .flat_map(|(_, _, v)| v.events.clone())
            .find(|eid| {
                matches!(
                    base.events.get(*eid).map(Event::position),
                    Some(EventPosition::WallClock(_))
                )
            })
            .expect("the fixture has a proportional region with a wall-clock event");
        let voice = base.events.get(event_id).unwrap().voice();
        let as_metric = crate::valuegen::insert_event_value(
            event_id,
            voice,
            position_of(0, 1),
            musical(1, 2),
            &[],
        );
        let modify = prim_env(
            2,
            0,
            10,
            CausalContext::new(),
            OperationKind::ModifyEvent(crate::payload::ModifyEventOp { event: as_metric }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![modify]);
        let result = set.reduce_onto(&base);
        assert!(
            matches!(
                result.score.events.get(event_id).map(Event::position),
                Some(EventPosition::WallClock(_))
            ),
            "the non-metric event is left as-is, not rewritten onto the musical grid"
        );
        assert!(
            check_invariants(&result.score).is_empty(),
            "the graph stays invariant-valid"
        );
    }

    #[test]
    fn modify_event_malformed_move_does_not_free_the_slot() {
        // A ModifyEvent rewriting e1 (filling [0, 1)) to an *empty* (malformed) pitched
        // event at [0, 1/2) is not materialized in the graph — so it must not move the
        // occupancy index either. A later insert into [1/2, 1) is therefore refused,
        // since e1 still occupies [0, 1).
        let e1 = insert(1, 0, 10, 1, 100, 0);
        let empty = Event::Pitched(epiphany_core::PitchedEvent {
            id: EventId::new(ReplicaId(1), 100),
            voice: VoiceId::new(ReplicaId(9), 1),
            position: EventPosition::Musical(position_of(0, 1)),
            duration: EventDuration::Musical(musical(1, 2)),
            pitches: vec![],
            articulations: vec![],
            dynamic: None,
            ornaments: vec![],
            stem: epiphany_core::StemConfiguration,
            grace: None,
        });
        let malformed = prim_env(
            1,
            1,
            20,
            CausalContext::new().with_seen(ReplicaId(1), 0),
            OperationKind::ModifyEvent(crate::payload::ModifyEventOp { event: empty }),
        );
        let e2 = insert_at(
            1,
            2,
            101,
            1,
            position_of(1, 2),
            musical(1, 2),
            CausalContext::new().with_seen(ReplicaId(1), 1),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![e1, malformed, e2]);
        let state = set.reduce();
        assert!(
            matches!(
                effect_at(&state, 2),
                Some(OperationEffect::NoOp {
                    reason: NoOpReason::PreconditionFailedUnderReduction { .. },
                })
            ),
            "the malformed trim did not free the slot, so the later insert is refused"
        );
    }

    #[test]
    fn insert_then_delete_identified_pitch_tombstones() {
        let event = EventId::new(ReplicaId(1), 100);
        let pitch = PitchId::new(ReplicaId(1), 7);
        let insert = insert(1, 0, 10, 1, 100, 0);
        let add = prim_env(
            1,
            1,
            20,
            CausalContext::new().with_seen(ReplicaId(1), 0),
            OperationKind::InsertIdentifiedPitch(crate::payload::InsertIdentifiedPitchOp {
                event,
                pitch: crate::valuegen::identified_pitch(pitch),
            }),
        );
        let del = prim_env(
            1,
            2,
            30,
            CausalContext::new().with_seen(ReplicaId(1), 1),
            OperationKind::DeleteIdentifiedPitch(crate::payload::DeleteIdentifiedPitchOp { pitch }),
        );

        let mut after_add = OperationSet::new();
        after_add.accept_all(vec![insert.clone(), add.clone()]);
        assert_eq!(
            after_add.reduce().objects.get(&TypedObjectId::Pitch(pitch)),
            Some(&ObjectState::Live),
            "InsertIdentifiedPitch mints the pitch live"
        );

        let mut after_del = OperationSet::new();
        after_del.accept_all(vec![insert, add, del]);
        assert!(
            matches!(
                after_del.reduce().objects.get(&TypedObjectId::Pitch(pitch)),
                Some(ObjectState::Tombstoned { .. })
            ),
            "DeleteIdentifiedPitch tombstones the pitch"
        );
    }

    // --- Group 2 (M2) behavior. --------------------------------------------

    fn create_slur(slur: epiphany_core::SlurId, a: EventId, b: EventId) -> OperationKind {
        OperationKind::CreateCrossCutting(crate::payload::CreateCrossCuttingOp {
            structure: CrossCuttingValue::Slur(crate::valuegen::slur(slur, a, b)),
        })
    }

    #[test]
    fn delete_cross_cutting_tombstones_the_structure() {
        let e1 = EventId::new(ReplicaId(1), 100);
        let e2 = EventId::new(ReplicaId(1), 101);
        let slur = epiphany_core::SlurId::new(ReplicaId(1), 1);
        let sid = TypedObjectId::Slur(slur);
        let create = prim_env(
            1,
            2,
            12,
            CausalContext::new().with_seen(ReplicaId(1), 1),
            create_slur(slur, e1, e2),
        );
        let delete = prim_env(
            1,
            3,
            13,
            CausalContext::new().with_seen(ReplicaId(1), 2),
            OperationKind::DeleteCrossCutting(crate::payload::DeleteCrossCuttingOp {
                structure: sid,
            }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![
            insert(1, 0, 10, 1, 100, 0),
            insert(1, 1, 11, 1, 101, 1),
            create,
            delete,
        ]);
        let state = set.reduce();
        assert!(
            matches!(
                state.objects.get(&sid),
                Some(ObjectState::Tombstoned { .. })
            ),
            "DeleteCrossCutting tombstones the structure (delete-wins)"
        );
    }

    #[test]
    fn concurrent_differing_modify_cross_cutting_conflicts() {
        let e1 = EventId::new(ReplicaId(1), 100);
        let e2 = EventId::new(ReplicaId(1), 101);
        let e3 = EventId::new(ReplicaId(1), 102);
        let slur = epiphany_core::SlurId::new(ReplicaId(1), 1);
        let create = prim_env(
            1,
            3,
            13,
            CausalContext::new().with_seen(ReplicaId(1), 2),
            create_slur(slur, e1, e2),
        );
        // Two concurrent modifies (seen the create, not each other) with differing
        // endpoints: e1->e2 vs e1->e3.
        let seen_create = CausalContext::new().with_seen(ReplicaId(1), 3);
        let modify = |replica: u64, end: EventId| {
            prim_env(
                replica,
                0,
                20,
                seen_create.clone(),
                OperationKind::ModifyCrossCutting(crate::payload::ModifyCrossCuttingOp {
                    structure: CrossCuttingValue::Slur(crate::valuegen::slur(slur, e1, end)),
                }),
            )
        };
        let mut set = OperationSet::new();
        set.accept_all(vec![
            insert(1, 0, 10, 1, 100, 0),
            insert(1, 1, 11, 1, 101, 1),
            insert(1, 2, 12, 1, 102, 2),
            create,
            modify(2, e2),
            modify(3, e3),
        ]);
        let state = set.reduce();
        assert_eq!(
            state.conflicts.records().len(),
            1,
            "concurrent differing ModifyCrossCutting must record exactly one conflict"
        );
        assert!(matches!(
            state.conflicts.records()[0].kind,
            ConflictKind::StructuralFieldCollision { .. }
        ));
    }

    // --- Phase D: repeat authoring (schema-major-2 revision). ----------------

    fn create_repeat(
        rid: epiphany_core::RepeatStructureId,
        a: EventId,
        b: EventId,
    ) -> OperationKind {
        OperationKind::CreateRepeatStructure(CreateRepeatStructureOp {
            repeat: crate::valuegen::repeat_structure(rid, a, b),
        })
    }

    #[test]
    fn create_repeat_structure_mints_and_delete_wins_tombstones() {
        let e1 = EventId::new(ReplicaId(1), 100);
        let e2 = EventId::new(ReplicaId(1), 101);
        let rid = epiphany_core::RepeatStructureId::new(ReplicaId(1), 1);
        let sid = TypedObjectId::RepeatStructure(rid);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            insert(1, 0, 10, 1, 100, 0),
            insert(1, 1, 11, 1, 101, 1),
            prim_env(1, 2, 12, seen_r1(1), create_repeat(rid, e1, e2)),
        ]);
        assert!(
            matches!(set.reduce().objects.get(&sid), Some(ObjectState::Live)),
            "set-union mint with live anchors"
        );

        // Delete-wins: the tombstone survives a concurrent re-delete
        // (idempotent) and a post-delete re-create (TargetTombstoned no-op).
        let mut set = OperationSet::new();
        set.accept_all(vec![
            insert(1, 0, 10, 1, 100, 0),
            insert(1, 1, 11, 1, 101, 1),
            prim_env(1, 2, 12, seen_r1(1), create_repeat(rid, e1, e2)),
            prim_env(
                1,
                3,
                13,
                seen_r1(2),
                OperationKind::DeleteRepeatStructure(DeleteRepeatStructureOp { repeat: rid }),
            ),
            prim_env(
                2,
                0,
                14,
                seen_r1(3),
                OperationKind::DeleteRepeatStructure(DeleteRepeatStructureOp { repeat: rid }),
            ),
            prim_env(3, 0, 15, seen_r1(3), create_repeat(rid, e1, e2)),
        ]);
        assert!(
            matches!(
                set.reduce().objects.get(&sid),
                Some(ObjectState::Tombstoned { .. })
            ),
            "the tombstone survives re-delete and re-create (delete-wins)"
        );
    }

    #[test]
    fn create_repeat_structure_preconditions_every_anchor_site_live() {
        // The all-anchors-live precondition covers the kind's jump targets and
        // each volta's span, not just start/end (operation_catalog §"Repeat
        // Structures").
        let e1 = EventId::new(ReplicaId(1), 100);
        let e2 = EventId::new(ReplicaId(1), 101);
        let ghost = EventId::new(ReplicaId(1), 6_666);
        let rid = epiphany_core::RepeatStructureId::new(ReplicaId(1), 1);

        let mut dal_segno = crate::valuegen::repeat_structure(rid, e1, e2);
        dal_segno.kind = epiphany_core::RepeatKind::DalSegno {
            segno: crate::valuegen::event_anchor(ghost),
            end_target: crate::valuegen::event_anchor(e2),
        };
        let mut volta = crate::valuegen::volta_repeat(rid, e1, e2);
        volta.voltas[1].end = crate::valuegen::event_anchor(ghost);

        for repeat in [dal_segno, volta] {
            let mut set = OperationSet::new();
            set.accept_all(vec![
                insert(1, 0, 10, 1, 100, 0),
                insert(1, 1, 11, 1, 101, 1),
                prim_env(
                    1,
                    2,
                    12,
                    seen_r1(1),
                    OperationKind::CreateRepeatStructure(CreateRepeatStructureOp { repeat }),
                ),
            ]);
            assert!(
                !set.reduce()
                    .objects
                    .contains_key(&TypedObjectId::RepeatStructure(rid)),
                "a dead jump-target/volta anchor is a TargetMissing no-op — nothing minted"
            );
        }
    }

    #[test]
    fn deleting_an_event_reanchors_a_repeat_across_every_anchor_site() {
        // The rule table's "Repeat structure / Anchor" row: re-anchor to the
        // nearest surviving anchor, across start/end AND volta spans, recorded
        // as a RepairRecord — and the graph agrees with the ledger.
        use epiphany_core::generators::valid_score;
        let mut base = valid_score(0x5EED);
        let voice_events = base
            .voices()
            .map(|(_, _, v)| v.events.clone())
            .next()
            .expect("the fixture has a voice");
        let (e0, e1) = (voice_events[0], voice_events[1]);
        let rid = epiphany_core::RepeatStructureId::new(ReplicaId(9), 800);
        base.cross_cutting
            .repeats
            .push(epiphany_core::RepeatStructure {
                id: rid,
                start: crate::valuegen::event_anchor(e0),
                end: crate::valuegen::event_anchor(e1),
                kind: epiphany_core::RepeatKind::Volta,
                voltas: vec![epiphany_core::Volta {
                    endings: vec![1],
                    start: crate::valuegen::event_anchor(e0),
                    end: crate::valuegen::event_anchor(e1),
                }],
            });

        let del = prim_env(
            2,
            0,
            10,
            CausalContext::new(),
            OperationKind::DeleteEvent(DeleteEventOp {
                event: e0,
                tuplet_compensation: TupletCompensation::NotInTuplet,
            }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![del.clone()]);
        let result = set.reduce_onto(&base);

        let effect = result
            .state
            .effects
            .iter()
            .find(|(id, _)| *id == del.id)
            .map(|(_, e)| e)
            .expect("delete effect recorded");
        let OperationEffect::AppliedWithRepair { repairs } = effect else {
            panic!("expected AppliedWithRepair, got {effect:?}");
        };
        assert!(
            repairs.iter().any(|r| {
                r.target == TypedObjectId::RepeatStructure(rid)
                    && r.kind
                        == RepairKind::Reanchored {
                            from: TypedObjectId::Event(e0),
                            to: TypedObjectId::Event(e1),
                            reason: ReanchorReason::SameVoiceNearer,
                        }
            }),
            "the repeat re-anchor is a recorded repair: {repairs:?}"
        );
        let repeat = result
            .score
            .cross_cutting
            .repeats
            .iter()
            .find(|r| r.id == rid)
            .expect("the repeat survives with one live anchor");
        let expect_e1 =
            |anchor: &TimeAnchor| matches!(anchor, TimeAnchor::Event { id, .. } if *id == e1);
        assert!(
            expect_e1(&repeat.start)
                && expect_e1(&repeat.end)
                && expect_e1(&repeat.voltas[0].start)
                && expect_e1(&repeat.voltas[0].end),
            "EVERY dead anchor site — start and the volta span — moved to the survivor"
        );
        assert!(epiphany_core::check_invariants(&result.score).is_empty());
    }

    #[test]
    fn create_repeat_structure_preconditions_non_event_anchor_targets() {
        // The all-anchor-sites-live precondition covers OBJECT references of
        // every kind — a missing REGION or MEASURE target refuses the mint
        // exactly like a missing event (an event-only check minted a
        // dangling repeat straight past CrossCuttingRefsResolve).
        use epiphany_core::generators::valid_score_rich;
        let rid = epiphany_core::RepeatStructureId::new(ReplicaId(1), 1);

        // Base-free: live event anchors, but start names a missing region.
        let e1 = EventId::new(ReplicaId(1), 100);
        let e2 = EventId::new(ReplicaId(1), 101);
        let mut repeat = crate::valuegen::repeat_structure(rid, e1, e2);
        repeat.start = TimeAnchor::Region {
            id: RegionId::new(ReplicaId(1), 6_666),
            edge: RegionEdge::Start,
            offset: AnchorOffset::Zero,
        };
        let mut set = OperationSet::new();
        set.accept_all(vec![
            insert(1, 0, 10, 1, 100, 0),
            insert(1, 1, 11, 1, 101, 1),
            prim_env(
                1,
                2,
                12,
                seen_r1(1),
                OperationKind::CreateRepeatStructure(CreateRepeatStructureOp { repeat }),
            ),
        ]);
        assert!(
            !set.reduce()
                .objects
                .contains_key(&TypedObjectId::RepeatStructure(rid)),
            "a missing region anchor target refuses the mint"
        );

        // Graph-aware: a live measure + live region anchor MINTS (and the
        // graph stays invariant-clean); a ghost measure in a volta span
        // refuses.
        let base = valid_score_rich(0x0D0D);
        let (region_id, measure_id) = base
            .canvas
            .regions
            .iter()
            .find_map(|r| {
                r.staff_instances()
                    .iter()
                    .find_map(|si| si.measures.first().map(|m| (r.id, m.id)))
            })
            .expect("the rich fixture has a measure");
        let measure_anchor = TimeAnchor::Measure {
            id: measure_id,
            position: epiphany_core::MeasurePosition::Start,
            offset: AnchorOffset::Zero,
        };
        let region_anchor = TimeAnchor::Region {
            id: region_id,
            edge: RegionEdge::End,
            offset: AnchorOffset::Zero,
        };
        let live = epiphany_core::RepeatStructure {
            id: rid,
            start: measure_anchor.clone(),
            end: region_anchor.clone(),
            kind: epiphany_core::RepeatKind::SimpleRepeat { count: 2 },
            voltas: Vec::new(),
        };
        let mut set = OperationSet::new();
        set.accept_all(vec![prim_env(
            2,
            0,
            10,
            CausalContext::new(),
            OperationKind::CreateRepeatStructure(CreateRepeatStructureOp { repeat: live }),
        )]);
        let result = set.reduce_onto(&base);
        assert!(
            matches!(
                result
                    .state
                    .objects
                    .get(&TypedObjectId::RepeatStructure(rid)),
                Some(ObjectState::Live)
            ),
            "live measure/region anchors mint"
        );
        assert!(epiphany_core::check_invariants(&result.score).is_empty());

        let mut ghost_volta = epiphany_core::RepeatStructure {
            id: epiphany_core::RepeatStructureId::new(ReplicaId(1), 2),
            start: measure_anchor,
            end: region_anchor.clone(),
            kind: epiphany_core::RepeatKind::Volta,
            voltas: vec![epiphany_core::Volta {
                endings: vec![1],
                start: region_anchor,
                end: TimeAnchor::Measure {
                    id: epiphany_core::MeasureId::new(ReplicaId(1), 6_666),
                    position: epiphany_core::MeasurePosition::Start,
                    offset: AnchorOffset::Zero,
                },
            }],
        };
        let ghost_id = ghost_volta.id;
        ghost_volta.voltas[0].endings = vec![1];
        let mut set = OperationSet::new();
        set.accept_all(vec![prim_env(
            2,
            0,
            10,
            CausalContext::new(),
            OperationKind::CreateRepeatStructure(CreateRepeatStructureOp {
                repeat: ghost_volta,
            }),
        )]);
        let result = set.reduce_onto(&base);
        assert!(
            !result
                .state
                .objects
                .contains_key(&TypedObjectId::RepeatStructure(ghost_id)),
            "a missing measure target inside a volta span refuses the mint"
        );
        assert!(
            !result
                .score
                .cross_cutting
                .repeats
                .iter()
                .any(|r| r.id == ghost_id),
            "nothing dangling reaches the graph"
        );
    }

    #[test]
    fn create_cross_cutting_spanner_preconditions_region_measure_anchors() {
        // P13-D3 (fix the mint): a spanner anchored to a missing region or
        // measure is refused (the mint checks `anchor_object_refs`, not just the
        // event endpoints `endpoints()` returns), and a spanner anchored to a
        // live region/measure mints. Non-event referent re-anchoring stays
        // events-only (ratified — the spanner discipline).
        use epiphany_core::generators::valid_score_rich;
        use epiphany_core::{MeasurePosition, SpannerId};

        let base = valid_score_rich(0x0D0E);
        let (region_id, measure_id) = base
            .canvas
            .regions
            .iter()
            .find_map(|r| {
                r.staff_instances()
                    .iter()
                    .find_map(|si| si.measures.first().map(|m| (r.id, m.id)))
            })
            .expect("the rich fixture has a measure");
        let spanner = |id, start, end| {
            OperationKind::CreateCrossCutting(CreateCrossCuttingOp {
                structure: CrossCuttingValue::Spanner(epiphany_core::Spanner {
                    id,
                    start,
                    end,
                    staves: Vec::new(),
                    kind: Default::default(),
                    style: Default::default(),
                }),
            })
        };
        let region_anchor = |id| TimeAnchor::Region {
            id,
            edge: RegionEdge::End,
            offset: AnchorOffset::Zero,
        };

        // Start names a missing region: refused, not minted dangling.
        let dangling = SpannerId::new(ReplicaId(9), 810);
        let mut set = OperationSet::new();
        set.accept_all(vec![prim_env(
            9,
            0,
            10,
            CausalContext::new(),
            spanner(
                dangling,
                TimeAnchor::Region {
                    id: RegionId::new(ReplicaId(9), 7_777),
                    edge: RegionEdge::Start,
                    offset: AnchorOffset::Zero,
                },
                region_anchor(region_id),
            ),
        )]);
        assert!(
            !set.reduce_onto(&base)
                .state
                .objects
                .contains_key(&TypedObjectId::Spanner(dangling)),
            "a spanner anchored to a missing region is refused, not minted dangling"
        );

        // Live measure + live region anchors: mints, invariant-clean.
        let live = SpannerId::new(ReplicaId(9), 811);
        let mut set = OperationSet::new();
        set.accept_all(vec![prim_env(
            9,
            0,
            10,
            CausalContext::new(),
            spanner(
                live,
                TimeAnchor::Measure {
                    id: measure_id,
                    position: MeasurePosition::Start,
                    offset: AnchorOffset::Zero,
                },
                region_anchor(region_id),
            ),
        )]);
        let result = set.reduce_onto(&base);
        assert!(
            matches!(
                result.state.objects.get(&TypedObjectId::Spanner(live)),
                Some(ObjectState::Live)
            ),
            "live region/measure anchors mint the spanner"
        );
        assert!(epiphany_core::check_invariants(&result.score).is_empty());

        // MODIFY sibling: a live event-anchored spanner MODIFIED onto a missing
        // region is refused too — `endpoints()` is empty for the new region
        // anchors, so the pre-fix modify check slipped a dangling value into the
        // graph past the core invariant.
        let events = base
            .voices()
            .map(|(_, _, v)| v.events.clone())
            .next()
            .expect("the fixture has a voice");
        let (e0, e1) = (events[0], events[1]);
        let mod_id = SpannerId::new(ReplicaId(9), 812);
        let mod_obj = TypedObjectId::Spanner(mod_id);
        let mut set = OperationSet::new();
        set.accept_all(vec![
            prim_env(
                9,
                0,
                10,
                CausalContext::new(),
                spanner(
                    mod_id,
                    crate::valuegen::event_anchor(e0),
                    crate::valuegen::event_anchor(e1),
                ),
            ),
            prim_env(
                9,
                1,
                11,
                CausalContext::new().with_seen(ReplicaId(9), 0),
                OperationKind::ModifyCrossCutting(crate::payload::ModifyCrossCuttingOp {
                    structure: CrossCuttingValue::Spanner(epiphany_core::Spanner {
                        id: mod_id,
                        start: TimeAnchor::Region {
                            id: RegionId::new(ReplicaId(9), 7_778),
                            edge: RegionEdge::Start,
                            offset: AnchorOffset::Zero,
                        },
                        end: region_anchor(region_id),
                        staves: Vec::new(),
                        kind: Default::default(),
                        style: Default::default(),
                    }),
                }),
            ),
        ]);
        let result = set.reduce_onto(&base);
        // The spanner stays live at its original event anchors (modify refused)…
        assert!(
            matches!(result.state.objects.get(&mod_obj), Some(ObjectState::Live)),
            "the spanner survives the refused modify"
        );
        // …and the dangling region anchor never reached the graph.
        assert!(
            !result.score.cross_cutting.spanners.iter().any(|s| {
                s.id == mod_id
                    && matches!(s.start, TimeAnchor::Region { id, .. } if id == RegionId::new(ReplicaId(9), 7_778))
            }),
            "the dangling modify never reached the graph"
        );
        assert!(epiphany_core::check_invariants(&result.score).is_empty());
    }

    #[test]
    fn deleting_an_event_rewires_a_dal_segno_jump_target() {
        // The kind's jump targets are anchor SITES like any other: a dead
        // segno re-anchors to the surviving event anchor (graph + ledger),
        // and a repeat whose ONLY event anchor is its segno cascades when
        // that event dies. (No other test exercised event-anchored jump
        // targets through the delete path.)
        use epiphany_core::generators::valid_score;
        let mut base = valid_score(0x5EED);
        let voice_events = base
            .voices()
            .map(|(_, _, v)| v.events.clone())
            .next()
            .expect("the fixture has a voice");
        let (e0, e1) = (voice_events[0], voice_events[1]);
        let region = base.canvas.regions[0].id;
        let region_edge = |edge| TimeAnchor::Region {
            id: region,
            edge,
            offset: AnchorOffset::Zero,
        };

        // Repeat A: start/end/segno all event-anchored; e0 dies -> every dead
        // site (including the segno) moves to e1.
        let rid_a = epiphany_core::RepeatStructureId::new(ReplicaId(9), 810);
        base.cross_cutting
            .repeats
            .push(epiphany_core::RepeatStructure {
                id: rid_a,
                start: crate::valuegen::event_anchor(e0),
                end: crate::valuegen::event_anchor(e1),
                kind: epiphany_core::RepeatKind::DalSegno {
                    segno: crate::valuegen::event_anchor(e0),
                    end_target: crate::valuegen::event_anchor(e1),
                },
                voltas: Vec::new(),
            });
        // Repeat B: the ONLY event anchor is the segno; e0 dies -> cascade.
        let rid_b = epiphany_core::RepeatStructureId::new(ReplicaId(9), 811);
        base.cross_cutting
            .repeats
            .push(epiphany_core::RepeatStructure {
                id: rid_b,
                start: region_edge(epiphany_core::RegionEdge::Start),
                end: region_edge(epiphany_core::RegionEdge::End),
                kind: epiphany_core::RepeatKind::DalSegno {
                    segno: crate::valuegen::event_anchor(e0),
                    end_target: region_edge(epiphany_core::RegionEdge::End),
                },
                voltas: Vec::new(),
            });

        let del = prim_env(
            2,
            0,
            10,
            CausalContext::new(),
            OperationKind::DeleteEvent(DeleteEventOp {
                event: e0,
                tuplet_compensation: TupletCompensation::NotInTuplet,
            }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![del]);
        let result = set.reduce_onto(&base);

        let repeat_a = result
            .score
            .cross_cutting
            .repeats
            .iter()
            .find(|r| r.id == rid_a)
            .expect("repeat A survives on its e1 anchors");
        let segno_moved = matches!(
            &repeat_a.kind,
            epiphany_core::RepeatKind::DalSegno { segno: TimeAnchor::Event { id, .. }, .. }
                if *id == e1
        );
        assert!(
            segno_moved,
            "the dead segno jump target re-anchored to the survivor: {:?}",
            repeat_a.kind
        );
        assert!(
            matches!(repeat_a.start, TimeAnchor::Event { id, .. } if id == e1),
            "start moved with it"
        );

        assert!(
            !result
                .score
                .cross_cutting
                .repeats
                .iter()
                .any(|r| r.id == rid_b),
            "a repeat whose only event anchor was its segno cascades"
        );
        assert!(
            matches!(
                result
                    .state
                    .objects
                    .get(&TypedObjectId::RepeatStructure(rid_b)),
                Some(ObjectState::Tombstoned { .. })
            ),
            "the ledger agrees on the cascade"
        );
        assert!(epiphany_core::check_invariants(&result.score).is_empty());
    }

    #[test]
    fn deleting_the_only_anchor_event_cascades_the_repeat() {
        // No surviving event anchor: cascade-delete, in the ledger (tombstone
        // + CascadeDeleted repair) and the graph together.
        use epiphany_core::generators::valid_score;
        let mut base = valid_score(0x5EED);
        let voice_events = base
            .voices()
            .map(|(_, _, v)| v.events.clone())
            .next()
            .expect("the fixture has a voice");
        let e0 = voice_events[0];
        let rid = epiphany_core::RepeatStructureId::new(ReplicaId(9), 801);
        base.cross_cutting
            .repeats
            .push(epiphany_core::RepeatStructure {
                id: rid,
                start: crate::valuegen::event_anchor(e0),
                end: crate::valuegen::event_anchor(e0),
                kind: epiphany_core::RepeatKind::SimpleRepeat { count: 2 },
                voltas: Vec::new(),
            });

        let del = prim_env(
            2,
            0,
            10,
            CausalContext::new(),
            OperationKind::DeleteEvent(DeleteEventOp {
                event: e0,
                tuplet_compensation: TupletCompensation::NotInTuplet,
            }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![del.clone()]);
        let result = set.reduce_onto(&base);

        assert!(
            matches!(
                result
                    .state
                    .objects
                    .get(&TypedObjectId::RepeatStructure(rid)),
                Some(ObjectState::Tombstoned { .. })
            ),
            "no surviving anchor: the ledger cascade-tombstones the repeat"
        );
        let effect = result
            .state
            .effects
            .iter()
            .find(|(id, _)| *id == del.id)
            .map(|(_, e)| e)
            .expect("delete effect recorded");
        let OperationEffect::AppliedWithRepair { repairs } = effect else {
            panic!("expected AppliedWithRepair, got {effect:?}");
        };
        assert!(
            repairs.iter().any(|r| {
                r.target == TypedObjectId::RepeatStructure(rid)
                    && r.kind == RepairKind::CascadeDeleted
            }),
            "the cascade is a recorded repair: {repairs:?}"
        );
        assert!(
            !result
                .score
                .cross_cutting
                .repeats
                .iter()
                .any(|r| r.id == rid),
            "the graph agrees: the repeat is gone"
        );
        assert!(epiphany_core::check_invariants(&result.score).is_empty());
    }

    #[test]
    fn undoing_a_repeat_or_spanner_create_removes_it_from_the_graph() {
        // Undo tombstones the minted structure AND materializes the graph-side
        // removal (materialize_graph_tombstones). The spanner leg regression-
        // locks the pre-existing gap fixed alongside Phase D: an undone
        // spanner mint used to leave a ghost value in the graph.
        use epiphany_core::generators::valid_score;
        let base = valid_score(0x5EED);
        let voice_events = base
            .voices()
            .map(|(_, _, v)| v.events.clone())
            .next()
            .expect("the fixture has a voice");
        let (e0, e1) = (voice_events[0], voice_events[1]);
        let rid = epiphany_core::RepeatStructureId::new(ReplicaId(9), 802);
        let spanner_id = epiphany_core::SpannerId::new(ReplicaId(9), 803);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(1, 1, 11, seen_r1(0), tx, create_repeat(rid, e0, e1)),
            tx_member(
                1,
                2,
                12,
                seen_r1(1),
                tx,
                OperationKind::CreateCrossCutting(crate::payload::CreateCrossCuttingOp {
                    structure: CrossCuttingValue::Spanner(epiphany_core::Spanner {
                        id: spanner_id,
                        start: crate::valuegen::event_anchor(e0),
                        end: crate::valuegen::event_anchor(e1),
                        staves: Vec::new(),
                        kind: Default::default(),
                        style: Default::default(),
                    }),
                }),
            ),
            undo_env(1, 3, 13, seen_r1(2), tx, UndoPolicy::StrictInverse),
        ]);
        let result = set.reduce_onto(&base);

        assert!(
            matches!(
                result
                    .state
                    .objects
                    .get(&TypedObjectId::RepeatStructure(rid)),
                Some(ObjectState::Tombstoned { .. })
            ) && matches!(
                result
                    .state
                    .objects
                    .get(&TypedObjectId::Spanner(spanner_id)),
                Some(ObjectState::Tombstoned { .. })
            ),
            "undo tombstones both mints"
        );
        assert!(
            !result
                .score
                .cross_cutting
                .repeats
                .iter()
                .any(|r| r.id == rid),
            "the undone repeat mint leaves the graph"
        );
        assert!(
            !result
                .score
                .cross_cutting
                .spanners
                .iter()
                .any(|sp| sp.id == spanner_id),
            "the undone spanner mint leaves the graph (the ghost-value fix)"
        );
        assert!(epiphany_core::check_invariants(&result.score).is_empty());
    }

    // --- Push-1 spec-compliance fixes (Transpose skip, meta-conflict record,
    // marker re-anchor repair, system-derived counter collisions). -----------

    /// An InsertEvent envelope whose event carries exactly one identified
    /// pitch with the given id and intrinsic content.
    #[allow(clippy::too_many_arguments)]
    fn insert_with_pitch_content(
        replica: u64,
        counter: u64,
        physical: i64,
        voice: u64,
        event: u64,
        pos_units: i64,
        pitch_id: PitchId,
        content: &Pitch,
    ) -> OperationEnvelope {
        let mut env = insert(replica, counter, physical, voice, event, pos_units);
        if let OperationPayload::Primitive(OperationKind::InsertEvent(ref mut op)) = env.payload {
            op.event = crate::valuegen::insert_event_value(
                op.event_id(),
                op.voice(),
                pos(pos_units),
                epiphany_core::MusicalDuration::whole(),
                &[pitch_id],
            );
            if let Event::Pitched(pe) = &mut op.event {
                pe.pitches[0].pitch = content.clone();
            }
        }
        env
    }

    use epiphany_core::{CmnNominal, TranspositionInterval};

    // --- Push 4a: transpose test harness. ------------------------------------
    //
    // The two `transpose_*` tests below were FALSE LOCKS until Push 4a: they
    // reduced base-free, where `graph` is `None` and `graph_transpose_pitch`
    // never runs, and they asserted only `OperationEffect`. Gutting the
    // transpose entirely left both green.
    //
    // They still reduce base-free, and should: what they assert — skip
    // tombstoned, skip system-derived, refuse missing — *is* effect-log
    // behaviour. Only the first one's NAME was a lie (it claimed to check the
    // live target "shifts"). It was renamed. The shift itself is locked by the
    // `the_frozen_transpose_*` tests, which reduce ONTO a base and assert the
    // pitch value.

    /// Every `(event, pitch)` in canonical id order — `events.iter()` walks a
    /// slotmap, whose order is an implementation detail.
    fn pitch_ids(score: &Score) -> Vec<PitchId> {
        let mut pairs: Vec<(EventId, PitchId)> = Vec::new();
        for event in score.events.iter() {
            let mut ips = Vec::new();
            event.collect_identified_pitches(&mut ips);
            pairs.extend(ips.iter().map(|ip| (event.id(), ip.id)));
        }
        pairs.sort();
        pairs.into_iter().map(|(_, p)| p).collect()
    }

    fn event_of(score: &Score, pitch: PitchId) -> EventId {
        score
            .events
            .iter()
            .find_map(|event| {
                let mut ips = Vec::new();
                event.collect_identified_pitches(&mut ips);
                ips.iter().any(|ip| ip.id == pitch).then(|| event.id())
            })
            .expect("pitch is embedded in this score")
    }

    fn set_pitch(score: &mut Score, pitch: PitchId, content: Pitch) {
        let eid = event_of(score, pitch);
        if let Some(Event::Pitched(pe)) = score.events.get_mut(eid) {
            if let Some(ip) = pe.pitches.iter_mut().find(|ip| ip.id == pitch) {
                ip.pitch = content;
                return;
            }
        }
        panic!("pitch {pitch:?} is not in a pitched event");
    }

    fn pitch_of(score: &Score, pitch: PitchId) -> Pitch {
        let eid = event_of(score, pitch);
        match score.events.get(eid) {
            Some(Event::Pitched(pe)) => pe
                .pitches
                .iter()
                .find(|ip| ip.id == pitch)
                .map(|ip| ip.pitch.clone())
                .expect("pitch present"),
            _ => panic!("not a pitched event"),
        }
    }

    /// A base score whose canonically-first pitch has the given content.
    fn base_with_pitch(content: Pitch) -> (Score, PitchId) {
        let mut base = epiphany_core::generators::valid_score(0x5EED);
        let pid = *pitch_ids(&base).first().expect("the fixture has a pitch");
        set_pitch(&mut base, pid, content);
        (base, pid)
    }

    fn cmn_pitch(nominal: CmnNominal, alteration: i8, octave: i8) -> Pitch {
        Pitch {
            scale_position: epiphany_core::ScalePosition {
                space: epiphany_core::PitchSpaceId::new("cmn-12"),
                position: epiphany_core::PitchSpacePosition::Cmn {
                    nominal,
                    alteration,
                    octave,
                },
            },
            acoustic: epiphany_core::AcousticPitch {
                tuning: epiphany_core::TuningReference::Inherit,
                realization: epiphany_core::AcousticRealization::Implicit,
            },
        }
    }

    fn cmn_of(p: &Pitch) -> (CmnNominal, i8, i8) {
        match p.scale_position.position {
            epiphany_core::PitchSpacePosition::Cmn {
                nominal,
                alteration,
                octave,
            } => (nominal, alteration, octave),
            ref other => panic!("expected Cmn, got {other:?}"),
        }
    }

    fn interval(diatonic_steps: i32, chromatic_steps: i32) -> TranspositionInterval {
        TranspositionInterval {
            diatonic_steps,
            chromatic_steps,
        }
    }

    /// Reduces one `TransposeInterval` onto `base` and returns (effect, score).
    fn run_transpose(
        base: &Score,
        targets: &[PitchId],
        iv: TranspositionInterval,
    ) -> (OperationEffect, Score) {
        let env = prim_env(
            3,
            0,
            30,
            CausalContext::new(),
            OperationKind::TransposeInterval(TransposeIntervalOp {
                targets: targets.iter().copied().collect(),
                interval: iv,
            }),
        );
        let id = env.id;
        let mut set = OperationSet::new();
        set.accept_all(vec![env]);
        let out = set.reduce_onto(base);
        let effect = out
            .state
            .effects
            .iter()
            .find(|(e, _)| *e == id)
            .map(|(_, eff)| eff.clone())
            .expect("effect recorded");
        (effect, out.score)
    }

    #[test]
    fn transpose_interval_moves_the_octave_not_the_alteration() {
        // The P12-K2 defect at the operation layer: the frozen `Transpose` by
        // +12 produced `alteration: 12` on the same C4.
        let (base, pid) = base_with_pitch(cmn_pitch(CmnNominal::C, 0, 4));
        let (effect, score) = run_transpose(&base, &[pid], interval(7, 12));
        assert_eq!(effect, OperationEffect::Applied);
        assert_eq!(cmn_of(&pitch_of(&score, pid)), (CmnNominal::C, 0, 5));
    }

    #[test]
    fn transpose_interval_targets_are_a_set_so_a_duplicate_cannot_double_shift() {
        // The frozen `Transpose` shifts a duplicated target twice. The set type
        // makes that unrepresentable: both spellings of the payload build the
        // same op, so they also hash the same.
        let (base, pid) = base_with_pitch(cmn_pitch(CmnNominal::C, 0, 4));
        let once = TransposeIntervalOp {
            targets: [pid].into_iter().collect(),
            interval: interval(0, 1),
        };
        let twice = TransposeIntervalOp {
            targets: [pid, pid].into_iter().collect(),
            interval: interval(0, 1),
        };
        assert_eq!(once, twice, "a duplicate target is not representable");

        let (effect, score) = run_transpose(&base, &[pid, pid], interval(0, 1));
        assert_eq!(effect, OperationEffect::Applied);
        // Shifted ONCE: C#4, not D4 (which is what two +1 shifts would give).
        assert_eq!(cmn_of(&pitch_of(&score, pid)), (CmnNominal::C, 1, 4));
    }

    #[test]
    fn transpose_interval_refuses_atomically_and_moves_no_sibling() {
        // A two-pitch chord where one note is pinned to a frequency. Refusing
        // the whole operation is the point: a chord transposed except for one
        // note is a different chord.
        let mut base = epiphany_core::generators::valid_score(0x5EED);
        let pitches = pitch_ids(&base);
        assert!(pitches.len() >= 2, "need two pitches");
        let (movable, pinned) = (pitches[0], pitches[1]);

        set_pitch(&mut base, movable, cmn_pitch(CmnNominal::C, 0, 4));
        let mut hz = cmn_pitch(CmnNominal::E, 0, 4);
        hz.acoustic.realization =
            epiphany_core::AcousticRealization::absolute_hz(329.6).expect("finite");
        set_pitch(&mut base, pinned, hz);

        let (effect, score) = run_transpose(&base, &[movable, pinned], interval(4, 7));
        assert_eq!(
            effect,
            OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::AcousticRealizationPinned,
                },
            }
        );
        // The transposable sibling did NOT move.
        assert_eq!(cmn_of(&pitch_of(&score, movable)), (CmnNominal::C, 0, 4));
    }

    #[test]
    fn transpose_interval_refuses_a_non_cmn_target_and_an_overflow() {
        let mut integer = cmn_pitch(CmnNominal::C, 0, 4);
        integer.scale_position.position = epiphany_core::PitchSpacePosition::Integer {
            space_size: 31,
            index: 7,
        };
        let expected = integer.scale_position.position.clone();
        let (base, pid) = base_with_pitch(integer);
        let (effect, score) = run_transpose(&base, &[pid], interval(4, 7));
        assert_eq!(
            effect,
            OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::PitchSpaceMismatch,
                },
            }
        );
        assert_eq!(pitch_of(&score, pid).scale_position.position, expected);

        // The frozen `Transpose` clamps here and reports Applied.
        let (base, pid) = base_with_pitch(cmn_pitch(CmnNominal::C, 0, 127));
        let (effect, score) = run_transpose(&base, &[pid], interval(7, 12));
        assert_eq!(
            effect,
            OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TranspositionOutOfRange,
                },
            }
        );
        assert_eq!(cmn_of(&pitch_of(&score, pid)), (CmnNominal::C, 0, 127));
    }

    #[test]
    fn unresolved_cmn_space_maps_to_canonical_pitch_space_mismatch() {
        // "edo-31": the built-in catalog resolves it, but to `Chromatic`, not
        // `DiatonicOverChromatic` — a `Cmn` position has no defined action
        // there, so `Pitch::transposed` refuses with
        // `TransposeRefusal::PitchSpaceUnavailable`, which maps here to
        // `PitchSpaceMismatch`. Before Push 4b tranche 1 this fixture used
        // `"cmn-24"` and the interim `"cmn-12"`-only guard refused it; `cmn-24`
        // is now fully resolved (`DiatonicOverChromatic`) and a spelling-less
        // `cmn-24` pitch *transposes* — see
        // `cmn_24_with_no_authored_spelling_transposes_at_the_operation_layer`
        // below — so it no longer witnesses a refusal at all. `edo-31` is the
        // stable witness: resolved, but to a structure a `Cmn` position cannot
        // live in.
        let mut unresolved = cmn_pitch(CmnNominal::E, -1, 4);
        unresolved.scale_position.space = epiphany_core::PitchSpaceId::new("edo-31");
        let expected = unresolved.clone();
        let (base, pid) = base_with_pitch(unresolved);

        let (effect, score) = run_transpose(&base, &[pid], interval(4, 14));
        assert_eq!(
            effect,
            OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::PitchSpaceMismatch,
                },
            }
        );
        let mut canonical = Vec::new();
        effect.encode_canonical(&mut canonical);
        assert_eq!(canonical, vec![4, 3, 6]);
        assert_eq!(pitch_of(&score, pid), expected);
    }

    #[test]
    fn cmn_24_with_no_authored_spelling_transposes_at_the_operation_layer() {
        // The operation-layer proof of life for Push 4b tranche 1. The core's
        // `Pitch::transposed` handles `cmn-24`, but `resolve_transposed_spellings`
        // used to compute the transposed 12-TET semitone BEFORE looking for any
        // spelling to rewrite, so its `?` refused every `cmn-24` transpose —
        // even one with nothing to spell — as `TranspositionOutOfRange`. That
        // was a defect made reachable (not introduced) by the space resolving.
        // With the semitone moved to point of use, a spelling-less `cmn-24`
        // pitch now transposes end-to-end.
        let mut c4 = cmn_pitch(CmnNominal::B, 0, 4);
        c4.scale_position.space = epiphany_core::PitchSpaceId::new("cmn-24");
        let (base, pid) = base_with_pitch(c4);

        // B4 up a diatonic step + 2 quarter-tone chromatic steps = natural C5,
        // the same 24-chromatic arithmetic the core's proof-of-life test pins.
        let (effect, score) = run_transpose(&base, &[pid], interval(1, 2));
        assert_eq!(effect, OperationEffect::Applied);
        assert_eq!(cmn_of(&pitch_of(&score, pid)), (CmnNominal::C, 0, 5));
    }

    #[test]
    fn cmn_24_with_an_authored_spelling_still_refuses() {
        // The complement: the spelling pre-pass remains 12-chromatic, so an
        // *authored* spelling on a `cmn-24` pitch genuinely cannot be rewritten
        // at the transposed position, and the operation refuses rather than
        // leave the spelling stale — the point-of-use `?` still fires when
        // there is a spelling to transpose.
        let mut c4 = cmn_pitch(CmnNominal::B, 0, 4);
        c4.scale_position.space = epiphany_core::PitchSpaceId::new("cmn-24");
        let (mut base, pid) = base_with_pitch(c4);
        author_spelling(&mut base, pid, PitchSpelling::cmn(CmnNominal::B, 4));
        let expected = pitch_of(&base, pid);

        let (effect, score) = run_transpose(&base, &[pid], interval(1, 2));
        assert_eq!(
            effect,
            OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TranspositionOutOfRange,
                },
            }
        );
        // Refused atomically: the value is untouched, not left half-transposed.
        assert_eq!(pitch_of(&score, pid), expected);
    }

    #[test]
    fn transpose_interval_propagates_the_spelling_it_determined() {
        // req:opcat:transpose-interval-spelling. Core Ch2: "editing operations
        // that move or transpose a pitch MUST produce attachments with source
        // Propagated." The frozen Transpose produces none.
        let (base, pid) = base_with_pitch(cmn_pitch(CmnNominal::C, 0, 4));
        assert!(
            !base.spelling_attachments.iter().any(|a| matches!(
                &a.scope, SpellingScope::Pitch(p) if *p == pid)),
            "the fixture starts with no attachment on this pitch"
        );

        // A diminished sixth up from C4 is A-double-flat 4: same sound as G4,
        // spelled a step away. Only the interval's diatonic component knows.
        let (effect, score) = run_transpose(&base, &[pid], interval(5, 7));
        assert_eq!(effect, OperationEffect::Applied);
        assert_eq!(cmn_of(&pitch_of(&score, pid)), (CmnNominal::A, -2, 4));

        let attachment = score
            .spelling_attachments
            .iter()
            .find(|a| matches!(&a.scope, SpellingScope::Pitch(p) if *p == pid))
            .expect("a transposition records its spelling");
        assert_eq!(attachment.source, SpellingSource::Propagated { from: pid });
        let SpellingDirective::Explicit(spelling) = &attachment.directive else {
            panic!("an explicit spelling");
        };
        assert_eq!(
            spelling.nominal,
            epiphany_core::SpellingNominal::Cmn(CmnNominal::A)
        );
        assert_eq!(spelling.octave, 4);
        // Two flats, not a G-natural: the spelling follows the interval, not
        // the simplest enharmonic re-inference.
        assert_eq!(spelling.accidentals.len(), 1);
    }

    /// The effective engraved spelling for `pitch`, through the same resolver
    /// the pre-pass uses — which is the only thing that says what gets drawn.
    fn engraved_spelling(
        score: &Score,
        pitch: PitchId,
    ) -> (epiphany_core::SpellingProvenance, PitchSpelling) {
        let value = pitch_of(score, pitch);
        let inferred = simplest_spelling(&value).expect("cmn");
        let resolved = epiphany_core::resolve_spelling(
            score,
            pitch,
            inferred,
            &epiphany_core::SpellingPrecedence::default(),
        );
        (resolved.provenance, resolved.spelling)
    }

    fn author_spelling(score: &mut Score, pitch: PitchId, spelling: PitchSpelling) {
        score.spelling_attachments.push(SpellingAttachment {
            scope: SpellingScope::Pitch(pitch),
            directive: SpellingDirective::Explicit(spelling),
            source: SpellingSource::UserChosen,
            priority: 0,
            layer: None,
        });
    }

    #[test]
    fn transpose_interval_moves_an_authored_spelling_instead_of_leaving_it_stale() {
        // The gap the original test could not see, because it started with no
        // attachment: default precedence ranks UserChosen ABOVE Propagated, so
        // recording a Propagated attachment does not, by itself, stop the
        // engraved layer from drawing the pre-transpose notehead. Before this
        // fix, a C4 sharpened to C#4 still RESOLVED to C natural — the
        // accidental vanished.
        let (mut base, pid) = base_with_pitch(cmn_pitch(CmnNominal::C, 0, 4));
        author_spelling(&mut base, pid, PitchSpelling::cmn(CmnNominal::C, 4));

        let (effect, score) = run_transpose(&base, &[pid], interval(0, 1));
        assert_eq!(effect, OperationEffect::Applied);
        assert_eq!(cmn_of(&pitch_of(&score, pid)), (CmnNominal::C, 1, 4));

        let (provenance, spelling) = engraved_spelling(&score, pid);
        // Still the author's choice — a transposed UserChosen spelling is still
        // user-chosen — but it now names the pitch that is actually there.
        assert_eq!(
            provenance,
            epiphany_core::SpellingProvenance::Authored(
                epiphany_core::SpellingSourceKind::UserChosen
            )
        );
        assert_eq!(
            spelling.nominal,
            epiphany_core::SpellingNominal::Cmn(CmnNominal::C)
        );
        assert_eq!(spelling.octave, 4);
        assert_eq!(spelling.accidentals.len(), 1, "the sharp must be drawn");
    }

    #[test]
    fn a_transposed_authored_spelling_keeps_the_authors_enharmonic_choice() {
        // The discriminating case: the authored spelling's NOMINAL must disagree
        // with the pitch's own Cmn nominal, or re-inferring from the pitch would
        // give the same answer and the test would prove nothing. (It did. The
        // mutation that replaced `spelling.transposed(..)` with
        // `simplest_spelling(transposed)` passed the first version of this test,
        // which spelled a C#4 pitch as "C#".)
        //
        // So: a pitch sounding C4, which the author deliberately wrote as B#3.
        // Up a perfect fifth it sounds G4 — and must be written F##4, keeping
        // the letter the author's B implies. Re-inference would say "G".
        let (mut base, pid) = base_with_pitch(cmn_pitch(CmnNominal::C, 0, 4));
        author_spelling(
            &mut base,
            pid,
            PitchSpelling {
                nominal: epiphany_core::SpellingNominal::Cmn(CmnNominal::B),
                accidentals: vec![epiphany_core::AccidentalId::new("sharp")],
                octave: 3,
                render_hints: Default::default(),
            },
        );

        let (effect, score) = run_transpose(&base, &[pid], interval(4, 7));
        assert_eq!(effect, OperationEffect::Applied);
        // The pitch itself is plain G4.
        assert_eq!(cmn_of(&pitch_of(&score, pid)), (CmnNominal::G, 0, 4));

        // The engraved spelling is F-double-sharp 4, not G.
        let (provenance, spelling) = engraved_spelling(&score, pid);
        assert_eq!(
            provenance,
            epiphany_core::SpellingProvenance::Authored(
                epiphany_core::SpellingSourceKind::UserChosen
            )
        );
        assert_eq!(
            spelling.nominal,
            epiphany_core::SpellingNominal::Cmn(CmnNominal::F),
            "the author's letter moved; re-inference would have said G"
        );
        assert_eq!(spelling.octave, 4);
        assert_eq!(
            spelling.accidentals,
            vec![epiphany_core::AccidentalId::new("double-sharp")]
        );
    }

    #[test]
    fn an_untransposable_authored_spelling_refuses_the_whole_operation() {
        // The pitch itself transposes fine; its authored spelling cannot be
        // written at the new staff position. Leaving it stale is exactly the
        // bug, so the operation refuses and nothing moves.
        let (mut base, pid) = base_with_pitch(cmn_pitch(CmnNominal::C, 0, 4));
        author_spelling(&mut base, pid, PitchSpelling::cmn(CmnNominal::C, 127));

        let (effect, score) = run_transpose(&base, &[pid], interval(7, 12));
        assert_eq!(
            effect,
            OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TranspositionOutOfRange,
                },
            }
        );
        assert_eq!(cmn_of(&pitch_of(&score, pid)), (CmnNominal::C, 0, 4));
    }

    /// A declared transaction containing one `TransposeInterval`, plus a
    /// `StrictInverse` undo of it. Returns the reduced score.
    fn transpose_then_undo(base: &Score, pid: PitchId, iv: TranspositionInterval) -> Score {
        let tx = TransactionId::new(ReplicaId(1), 900);
        let tr = tx_member(
            1,
            1,
            11,
            seen_r1(0),
            tx,
            OperationKind::TransposeInterval(TransposeIntervalOp {
                targets: [pid].into_iter().collect(),
                interval: iv,
            }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tr,
            undo_env(1, 2, 12, seen_r1(1), tx, UndoPolicy::StrictInverse),
        ]);
        set.reduce_onto(base).score
    }

    #[test]
    fn undoing_a_transpose_interval_restores_the_pitch_and_its_spelling() {
        // operation_catalog §TransposeInterval, "Undo semantics". Before this,
        // TransposeInterval never recorded into the pitch's value chain, so
        // UndoTransaction(StrictInverse) reduced to NoOp(TargetMissing) and left
        // the pitch shifted.
        let (mut base, pid) = base_with_pitch(cmn_pitch(CmnNominal::C, 0, 4));
        author_spelling(&mut base, pid, PitchSpelling::cmn(CmnNominal::C, 4));
        let before_attachments = base.spelling_attachments.clone();

        let score = transpose_then_undo(&base, pid, interval(4, 7));

        // The pitch is back.
        assert_eq!(cmn_of(&pitch_of(&score, pid)), (CmnNominal::C, 0, 4));
        // And so is its spelling: the moved UserChosen attachment is restored,
        // and the Propagated one the transpose added is gone. Restoring the
        // pitch alone would leave a notehead spelled for a pitch that is not
        // there.
        assert_eq!(score.spelling_attachments, before_attachments);
        let (provenance, spelling) = engraved_spelling(&score, pid);
        assert_eq!(
            provenance,
            epiphany_core::SpellingProvenance::Authored(
                epiphany_core::SpellingSourceKind::UserChosen
            )
        );
        assert_eq!(spelling.accidentals.len(), 0, "the sharp is gone again");
    }

    #[test]
    fn undoing_a_transpose_of_an_unspelled_pitch_removes_the_propagated_attachment() {
        // No authored spelling: the transpose adds a Propagated attachment where
        // there was none. Undo must remove it, not leave it naming a pitch that
        // no longer exists.
        let (base, pid) = base_with_pitch(cmn_pitch(CmnNominal::C, 0, 4));
        assert!(base.spelling_attachments.is_empty());

        let score = transpose_then_undo(&base, pid, interval(0, 1));
        assert_eq!(cmn_of(&pitch_of(&score, pid)), (CmnNominal::C, 0, 4));
        assert!(
            score.spelling_attachments.is_empty(),
            "undo removed the propagated attachment"
        );
    }

    #[test]
    fn the_frozen_transpose_is_not_undoable_and_that_is_frozen_too() {
        // req:opcat:transpose-frozen. Transpose records no write into the value
        // chain, so value-restoring undo leaves the shifted pitch shifted.
        //
        // This is a DEFECT, pinned. Making it record would not change its own
        // reduction rule, but it WOULD change what a stored
        // {Transpose, UndoTransaction} history replays to — from "the pitch stays
        // shifted" to "the pitch returns" — and that is a change in what an
        // existing document means. If this test ever "fails better", history has
        // been rewritten.
        let (base, pid) = base_with_pitch(cmn_pitch(CmnNominal::C, 0, 4));
        let tx = TransactionId::new(ReplicaId(1), 900);
        let tr = tx_member(
            1,
            1,
            11,
            seen_r1(0),
            tx,
            OperationKind::Transpose(TransposeOp {
                targets: vec![pid],
                chromatic_steps: 1,
            }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tr,
            undo_env(1, 2, 12, seen_r1(1), tx, UndoPolicy::StrictInverse),
        ]);
        let out = set.reduce_onto(&base);
        assert_eq!(
            cmn_of(&pitch_of(&out.score, pid)),
            (CmnNominal::C, 1, 4),
            "the frozen transpose is not undone by value restoration"
        );
    }

    // --- P13-S3: RespellPitch and TransposeInterval share the engraved
    // spelling set, so undo must see both. ---------------------------------

    fn respell_env(
        replica: u64,
        counter: u64,
        physical: i64,
        ctx: CausalContext,
        pitch: PitchId,
        nominal: CmnNominal,
    ) -> OperationEnvelope {
        prim_env(
            replica,
            counter,
            physical,
            ctx,
            OperationKind::RespellPitch(RespellPitchOp {
                pitch,
                spelling: PitchSpelling::cmn(nominal, 4),
            }),
        )
    }

    fn transpose_member(
        replica: u64,
        counter: u64,
        physical: i64,
        ctx: CausalContext,
        tx: TransactionId,
        pitch: PitchId,
        iv: TranspositionInterval,
    ) -> OperationEnvelope {
        tx_member(
            replica,
            counter,
            physical,
            ctx,
            tx,
            OperationKind::TransposeInterval(TransposeIntervalOp {
                targets: [pitch].into_iter().collect(),
                interval: iv,
            }),
        )
    }

    /// `(source, nominal, accidental count)` of every engraved-layer explicit
    /// attachment on `pitch`.
    fn attachments_of(score: &Score, pitch: PitchId) -> Vec<(SpellingSource, CmnNominal, usize)> {
        score
            .spelling_attachments
            .iter()
            .filter(|a| a.layer.is_none())
            .filter(|a| matches!(&a.scope, SpellingScope::Pitch(p) if *p == pitch))
            .filter_map(|a| match (&a.directive, &a.source) {
                (SpellingDirective::Explicit(sp), src) => match sp.nominal {
                    epiphany_core::SpellingNominal::Cmn(n) => {
                        Some((src.clone(), n, sp.accidentals.len()))
                    }
                    _ => None,
                },
                _ => None,
            })
            .collect()
    }

    fn undo_effect(state: &MaterializedState, id: OperationId) -> OperationEffect {
        state
            .effects
            .iter()
            .find(|(e, _)| *e == id)
            .map(|(_, eff)| eff.clone())
            .expect("effect recorded")
    }

    #[test]
    fn undoing_a_transpose_restores_a_prior_respell() {
        // P13-S3, direction one. The respell is an OPERATION, not part of the
        // base, so it exists only as a write on the shared chain. Before the
        // fix, the transpose's chain had no predecessor for it and the undo
        // wiped every attachment on the pitch.
        let (base, pid) = base_with_pitch(cmn_pitch(CmnNominal::C, 0, 4));
        let tx = TransactionId::new(ReplicaId(1), 900);
        let undo = undo_env(1, 3, 13, seen_r1(2), tx, UndoPolicy::StrictInverse);
        let undo_id = undo.id;

        let mut set = OperationSet::new();
        set.accept_all(vec![
            respell_env(1, 0, 10, CausalContext::new(), pid, CmnNominal::C),
            declare_transaction(1, 1, 11, seen_r1(0), tx),
            transpose_member(1, 2, 12, seen_r1(1), tx, pid, interval(0, 1)),
            undo,
        ]);
        let out = set.reduce_onto(&base);

        assert_eq!(undo_effect(&out.state, undo_id), OperationEffect::Applied);
        assert_eq!(cmn_of(&pitch_of(&out.score, pid)), (CmnNominal::C, 0, 4));
        assert_eq!(
            attachments_of(&out.score, pid),
            vec![(SpellingSource::UserChosen, CmnNominal::C, 0)],
            "the prior respell survives the undo, and the propagated one is gone"
        );
    }

    #[test]
    fn a_respell_after_a_transposed_transaction_supersedes_its_strict_undo() {
        // P13-S3, direction two. The respell lands canonically AFTER the
        // transaction, so it is a later writer on the pitch's spelling set:
        // strict undo must refuse rather than erase it. Before the fix the
        // respell was invisible to the transpose's chain, so the undo reported
        // Applied and wiped the newer authoring.
        let (base, pid) = base_with_pitch(cmn_pitch(CmnNominal::C, 0, 4));
        let tx = TransactionId::new(ReplicaId(1), 900);
        let undo = undo_env(1, 3, 13, seen_r1(2), tx, UndoPolicy::StrictInverse);
        let undo_id = undo.id;

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            transpose_member(1, 1, 11, seen_r1(0), tx, pid, interval(0, 1)),
            respell_env(1, 2, 12, seen_r1(1), pid, CmnNominal::D),
            undo,
        ]);
        let out = set.reduce_onto(&base);

        assert!(
            matches!(
                undo_effect(&out.state, undo_id),
                OperationEffect::Conflicted { .. }
            ),
            "a later canonical writer supersedes a strict undo"
        );
        // Nothing was rolled back: the pitch stays transposed and the newer
        // authored spelling stands.
        assert_eq!(cmn_of(&pitch_of(&out.score, pid)), (CmnNominal::C, 1, 4));
        let atts = attachments_of(&out.score, pid);
        assert!(
            atts.contains(&(SpellingSource::UserChosen, CmnNominal::D, 0)),
            "the later respell was not erased: {atts:?}"
        );
    }

    #[test]
    fn best_effort_undo_will_not_restore_a_pitch_whose_spelling_was_superseded() {
        // The pitch value and its engraved spelling set are one undo unit.
        // Restoring the pitch alone would leave a spelling authored against the
        // transposed pitch attached to the pitch it used to be.
        let (base, pid) = base_with_pitch(cmn_pitch(CmnNominal::C, 0, 4));
        let tx = TransactionId::new(ReplicaId(1), 900);
        let undo = undo_env(1, 3, 13, seen_r1(2), tx, UndoPolicy::BestEffort);
        let undo_id = undo.id;

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            transpose_member(1, 1, 11, seen_r1(0), tx, pid, interval(0, 1)),
            respell_env(1, 2, 12, seen_r1(1), pid, CmnNominal::D),
            undo,
        ]);
        let out = set.reduce_onto(&base);

        assert_eq!(undo_effect(&out.state, undo_id), OperationEffect::Applied);
        assert_eq!(
            cmn_of(&pitch_of(&out.score, pid)),
            (CmnNominal::C, 1, 4),
            "best-effort skipped the pitch because its spelling set was superseded"
        );
        assert!(attachments_of(&out.score, pid).contains(&(
            SpellingSource::UserChosen,
            CmnNominal::D,
            0
        )));
    }

    #[test]
    fn a_concurrent_respell_and_transpose_converge_in_canonical_order() {
        // Neither sees the other. Both write the pitch's engraved spelling set,
        // so the canonically-last writer owns it — and both permutations of the
        // input reduce to the same score, which is the only property that
        // matters.
        let (base, pid) = base_with_pitch(cmn_pitch(CmnNominal::C, 0, 4));
        let tx = TransactionId::new(ReplicaId(1), 900);

        let build = || {
            vec![
                declare_transaction(1, 0, 10, CausalContext::new(), tx),
                // Concurrent: replica 2's respell has not seen replica 1's
                // transpose, and vice versa.
                transpose_member(1, 1, 11, seen_r1(0), tx, pid, interval(0, 1)),
                respell_env(2, 0, 12, CausalContext::new(), pid, CmnNominal::D),
            ]
        };
        let mut forward = OperationSet::new();
        forward.accept_all(build());
        let a = forward.reduce_onto(&base);

        let mut reversed = OperationSet::new();
        let mut envs = build();
        envs.reverse();
        reversed.accept_all(envs);
        let b = reversed.reduce_onto(&base);

        assert_eq!(a.score, b.score, "reduction is permutation-invariant");
        assert_eq!(a.state.canonical_bytes(), b.state.canonical_bytes());
        // The pitch moved; exactly one authored spelling stands, plus the
        // propagated record.
        assert_eq!(cmn_of(&pitch_of(&a.score, pid)), (CmnNominal::C, 1, 4));
        let atts = attachments_of(&a.score, pid);
        assert_eq!(
            atts.iter()
                .filter(|(s, _, _)| matches!(s, SpellingSource::UserChosen))
                .count(),
            1,
            "one authored spelling: {atts:?}"
        );
    }

    /// The editor's "move note": a value change plus the matching respelling, in
    /// one transaction (`epiphany-editor-core`, `apply_transaction`). Neither
    /// member writes both undo keys, but the *transaction* writes both — the
    /// modify writes the pitch value, the respell writes the engraved spelling
    /// set.
    fn move_and_respell(
        base: &Score,
        pid: PitchId,
        tx: TransactionId,
        later_respell: bool,
        policy: UndoPolicy,
    ) -> (OperationEffect, Score) {
        let mut envs = vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::ModifyIdentifiedPitch(ModifyIdentifiedPitchOp {
                    pitch: pid,
                    value: cmn_pitch(CmnNominal::D, 0, 4),
                }),
            ),
            tx_member(
                1,
                2,
                12,
                seen_r1(1),
                tx,
                OperationKind::RespellPitch(RespellPitchOp {
                    pitch: pid,
                    spelling: PitchSpelling::cmn(CmnNominal::D, 4),
                }),
            ),
        ];
        let mut counter = 3;
        if later_respell {
            envs.push(respell_env(1, 3, 13, seen_r1(2), pid, CmnNominal::E));
            counter = 4;
        }
        let undo = undo_env(1, counter, 20, seen_r1(counter - 1), tx, policy);
        let undo_id = undo.id;
        envs.push(undo);

        let mut set = OperationSet::new();
        set.accept_all(envs);
        let out = set.reduce_onto(base);
        (undo_effect(&out.state, undo_id), out.score)
    }

    #[test]
    fn a_move_and_respell_undoes_fully_when_nothing_supersedes_it() {
        // The coupling must not over-fire: with no later writer, both halves of
        // the transaction restore.
        let (base, pid) = base_with_pitch(cmn_pitch(CmnNominal::C, 0, 4));
        let tx = TransactionId::new(ReplicaId(1), 900);
        let (effect, score) = move_and_respell(&base, pid, tx, false, UndoPolicy::BestEffort);

        assert_eq!(effect, OperationEffect::Applied);
        assert_eq!(cmn_of(&pitch_of(&score, pid)), (CmnNominal::C, 0, 4));
        assert!(
            attachments_of(&score, pid).is_empty(),
            "the respell's attachment is gone with it"
        );
    }

    #[test]
    fn best_effort_undo_skips_a_move_and_respell_pair_a_later_respell_superseded() {
        // The pitch/spelling-set coupling is keyed on the PITCH and on which
        // chains the TRANSACTION wrote — not on which operation wrote them, and
        // not on `TransposeInterval` specifically. Here the modify wrote the
        // pitch value and the respell wrote the spelling set; a later respell
        // supersedes the set.
        //
        // Skipping both is the point. Restoring the pitch to C4 while the
        // engraved spelling reads E — authored against the moved pitch — is
        // exactly the stale-notehead defect the coupling exists to prevent.
        // This broader reach is intentional (`req:opcat:spelling-set-chain`).
        let (base, pid) = base_with_pitch(cmn_pitch(CmnNominal::C, 0, 4));
        let tx = TransactionId::new(ReplicaId(1), 900);
        let (effect, score) = move_and_respell(&base, pid, tx, true, UndoPolicy::BestEffort);

        assert_eq!(effect, OperationEffect::Applied);
        assert_eq!(
            cmn_of(&pitch_of(&score, pid)),
            (CmnNominal::D, 0, 4),
            "best-effort left the moved pitch, because its spelling set was superseded"
        );
        assert_eq!(
            attachments_of(&score, pid),
            vec![(SpellingSource::UserChosen, CmnNominal::E, 0)],
            "the later authoring stands"
        );
    }

    #[test]
    fn strict_undo_of_a_superseded_move_and_respell_conflicts() {
        let (base, pid) = base_with_pitch(cmn_pitch(CmnNominal::C, 0, 4));
        let tx = TransactionId::new(ReplicaId(1), 900);
        let (effect, score) = move_and_respell(&base, pid, tx, true, UndoPolicy::StrictInverse);

        assert!(
            matches!(effect, OperationEffect::Conflicted { .. }),
            "a later canonical writer supersedes a strict undo"
        );
        assert_eq!(cmn_of(&pitch_of(&score, pid)), (CmnNominal::D, 0, 4));
    }

    #[test]
    fn transpose_interval_skips_a_tombstoned_target_but_refuses_a_missing_one() {
        // The skip/refuse distinction: a deleted pitch is not an untransposable
        // pitch, it is one the operation has nothing to say about.
        let (base, pid) = base_with_pitch(cmn_pitch(CmnNominal::C, 0, 4));
        let ghost = PitchId::new(ReplicaId(9), 999);
        let (effect, score) = run_transpose(&base, &[pid, ghost], interval(0, 1));
        assert_eq!(
            effect,
            OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetMissing,
                },
            }
        );
        assert_eq!(cmn_of(&pitch_of(&score, pid)), (CmnNominal::C, 0, 4));
    }

    #[test]
    fn the_frozen_transpose_keeps_its_saturating_alteration_semantics() {
        // req:opcat:transpose-frozen. These are DEFECTS, pinned as normative
        // replay semantics: a stored Transpose must reconstruct the state its
        // author saw. If this test ever "fails better", history has been
        // rewritten.
        let (base, pid) = base_with_pitch(cmn_pitch(CmnNominal::C, 0, 4));
        let run = |targets: Vec<PitchId>, steps: i32| -> Pitch {
            let env = prim_env(
                3,
                0,
                30,
                CausalContext::new(),
                OperationKind::Transpose(TransposeOp {
                    targets,
                    chromatic_steps: steps,
                }),
            );
            let mut set = OperationSet::new();
            set.accept_all(vec![env]);
            pitch_of(&set.reduce_onto(&base).score, pid)
        };

        // An octave up moves the alteration, not the octave.
        assert_eq!(cmn_of(&run(vec![pid], 12)), (CmnNominal::C, 12, 4));
        // Saturation, silent.
        assert_eq!(cmn_of(&run(vec![pid], 1000)), (CmnNominal::C, 127, 4));
        // A duplicated target shifts twice: `targets` is a multiset.
        assert_eq!(cmn_of(&run(vec![pid, pid], 1)), (CmnNominal::C, 2, 4));
    }

    /// Tombstones `pitch` as replica 1's operation 0, so [`after_that_delete`]
    /// names a *contiguous* prefix of replica 1 — a causal vector implies every
    /// counter up to the one it names, so a lone high counter leaves the
    /// dependent op pending, not applied.
    fn delete_pitch_env(pitch: PitchId) -> OperationEnvelope {
        prim_env(
            1,
            0,
            10,
            CausalContext::new(),
            OperationKind::DeleteIdentifiedPitch(DeleteIdentifiedPitchOp { pitch }),
        )
    }

    fn after_that_delete() -> CausalContext {
        CausalContext::new().with_seen(ReplicaId(1), 0)
    }

    #[test]
    fn the_frozen_transpose_skips_a_tombstoned_target_and_shifts_the_live_sibling() {
        // The claim the old base-free test made in its name but never checked.
        let mut base = epiphany_core::generators::valid_score(0x5EED);
        let ids = pitch_ids(&base);
        let (dead, live) = (ids[0], ids[1]);
        set_pitch(&mut base, live, cmn_pitch(CmnNominal::C, 0, 4));

        let del = delete_pitch_env(dead);
        let tr = prim_env(
            3,
            0,
            30,
            after_that_delete(),
            OperationKind::Transpose(TransposeOp {
                targets: vec![dead, live],
                chromatic_steps: 1,
            }),
        );
        let tr_id = tr.id;
        let mut set = OperationSet::new();
        set.accept_all(vec![del, tr]);
        let out = set.reduce_onto(&base);
        assert_eq!(
            out.state
                .effects
                .iter()
                .find(|(e, _)| *e == tr_id)
                .map(|(_, eff)| eff),
            Some(&OperationEffect::Applied)
        );
        // The live sibling actually moved.
        assert_eq!(cmn_of(&pitch_of(&out.score, live)), (CmnNominal::C, 1, 4));
    }

    #[test]
    fn transpose_interval_skips_a_tombstoned_target_and_shifts_the_live_sibling() {
        let mut base = epiphany_core::generators::valid_score(0x5EED);
        let ids = pitch_ids(&base);
        let (dead, live) = (ids[0], ids[1]);
        set_pitch(&mut base, live, cmn_pitch(CmnNominal::C, 0, 4));

        let del = delete_pitch_env(dead);
        let tr = prim_env(
            3,
            0,
            30,
            after_that_delete(),
            OperationKind::TransposeInterval(TransposeIntervalOp {
                targets: [dead, live].into_iter().collect(),
                interval: interval(4, 7),
            }),
        );
        let tr_id = tr.id;
        let mut set = OperationSet::new();
        set.accept_all(vec![del, tr]);
        let out = set.reduce_onto(&base);
        assert_eq!(
            out.state
                .effects
                .iter()
                .find(|(e, _)| *e == tr_id)
                .map(|(_, eff)| eff),
            Some(&OperationEffect::Applied),
            "a tombstoned target is SKIPPED, not a refusal"
        );
        assert_eq!(cmn_of(&pitch_of(&out.score, live)), (CmnNominal::G, 0, 4));
    }

    #[test]
    fn transpose_effect_log_skips_tombstoned_targets_and_refuses_a_missing_one() {
        // Operation Catalog §Transpose (re-anchoring): "Tombstoned targets are
        // skipped (the transpose applies only to live pitches)."
        //
        // SCOPE: this reduces base-free, so it observes the EFFECT LOG only —
        // `graph` is `None` and no pitch value exists to check. It was named
        // "...and_shifts_the_live_ones" and asserted no shift whatsoever; a
        // gutted `graph_transpose_pitch` left it green. The shift itself is
        // locked by `the_frozen_transpose_*` tests below, against `reduce_onto`.
        let p1 = PitchId::new(ReplicaId(9), 501);
        let p2 = PitchId::new(ReplicaId(9), 502);
        let neutral = crate::valuegen::pitch_value();
        let a = insert_with_pitch_content(1, 0, 10, 1, 100, 0, p1, &neutral);
        let b = insert_with_pitch_content(1, 1, 11, 2, 101, 0, p2, &neutral);
        let del = prim_env(
            1,
            2,
            20,
            CausalContext::new().with_seen(ReplicaId(1), 1),
            OperationKind::DeleteEvent(DeleteEventOp {
                event: EventId::new(ReplicaId(1), 100),
                tuplet_compensation: TupletCompensation::NotInTuplet,
            }),
        );
        let after_delete = CausalContext::new().with_seen(ReplicaId(1), 2);
        // Mixed live/tombstoned targets: skips p1, shifts p2, applies.
        let t_mixed = prim_env(
            3,
            0,
            30,
            after_delete.clone(),
            OperationKind::Transpose(TransposeOp {
                targets: vec![p1, p2],
                chromatic_steps: 2,
            }),
        );
        // All targets tombstoned: degenerates to no effect.
        let t_dead = prim_env(
            4,
            0,
            31,
            after_delete.clone(),
            OperationKind::Transpose(TransposeOp {
                targets: vec![p1],
                chromatic_steps: 2,
            }),
        );
        // A target that never existed: dangling reference, whole op refuses.
        let t_missing = prim_env(
            5,
            0,
            32,
            after_delete,
            OperationKind::Transpose(TransposeOp {
                targets: vec![p2, PitchId::new(ReplicaId(9), 999)],
                chromatic_steps: 2,
            }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![
            a,
            b,
            del,
            t_mixed.clone(),
            t_dead.clone(),
            t_missing.clone(),
        ]);
        let state = set.reduce();
        let effect = |id: OperationId| {
            state
                .effects
                .iter()
                .find(|(e, _)| *e == id)
                .map(|(_, eff)| eff)
                .expect("effect recorded")
        };
        assert_eq!(effect(t_mixed.id), &OperationEffect::Applied);
        assert_eq!(
            effect(t_dead.id),
            &OperationEffect::NoOp {
                reason: NoOpReason::TargetTombstoned,
            }
        );
        assert_eq!(
            effect(t_missing.id),
            &OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetMissing,
                },
            }
        );
    }

    #[test]
    fn schema_majors_follow_the_minimal_stamping_rule() {
        // Binary Format §Schema Major 2, "Minimal stamping": the stamp is the
        // lowest major whose layouts decode the payload's bytes — a pure
        // function of the value. Mandatory-append kinds are always 2; the
        // Option-hidden embeddings are value-dependent; everything else keeps
        // its prior major.
        use crate::payload::{
            CreateCrossCuttingOp, CreateRegionOp, CreateStaffInstanceOp, CrossCuttingValue,
            SetStaffLayoutOp,
        };
        use epiphany_core::{RegionId, SlurId, StaffInstanceId};

        let slur = crate::valuegen::slur(
            SlurId::new(ReplicaId(9), 1),
            EventId::new(ReplicaId(9), 1),
            EventId::new(ReplicaId(9), 2),
        );
        assert_eq!(
            OperationKind::CreateCrossCutting(CreateCrossCuttingOp {
                structure: CrossCuttingValue::Slur(slur),
            })
            .schema_major(),
            2,
            "mandatory v2 appends stamp 2"
        );

        let region = crate::valuegen::region(RegionId::new(ReplicaId(9), 3));
        assert_eq!(
            OperationKind::CreateRegion(CreateRegionOp {
                region: region.clone()
            })
            .schema_major(),
            1,
            "an empty-instance CreateRegion keeps its v1 stamp"
        );

        let iid = StaffInstanceId::new(ReplicaId(9), 4);
        let mut instance = crate::valuegen::staff_instance(iid, StaffId::new(ReplicaId(9), 5));
        assert_eq!(
            OperationKind::CreateStaffInstance(CreateStaffInstanceOp {
                region: region.id,
                instance: instance.clone(),
            })
            .schema_major(),
            0,
            "a None-override instance encodes byte-identically at v0"
        );
        instance.staff_lines_override = Some(epiphany_core::StaffLineConfiguration::default());
        assert_eq!(
            OperationKind::CreateStaffInstance(CreateStaffInstanceOp {
                region: region.id,
                instance,
            })
            .schema_major(),
            2,
            "a Some-override instance bears the v2 StaffLineConfiguration"
        );

        assert_eq!(
            OperationKind::SetStaffLayout(SetStaffLayoutOp {
                staff_instance: iid,
                instrument_override: None,
                staff_lines_override: None,
                visible: true,
            })
            .schema_major(),
            0
        );
        assert_eq!(
            OperationKind::SetStaffLayout(SetStaffLayoutOp {
                staff_instance: iid,
                instrument_override: None,
                staff_lines_override: Some(epiphany_core::StaffLineConfiguration::default()),
                visible: true,
            })
            .schema_major(),
            2,
            "a Some-override layout bears the v2 StaffLineConfiguration"
        );

        // The repeat pair (Phase D): the create is born at v2 — its carried
        // RepeatStructure's kind/voltas are unconditional fields, so even the
        // migration-default value has no lower-major layout. The delete's
        // bare-id payload is a major-0 layout under a minor kind append.
        let rid = epiphany_core::RepeatStructureId::new(ReplicaId(9), 6);
        assert_eq!(
            OperationKind::CreateRepeatStructure(CreateRepeatStructureOp {
                repeat: crate::valuegen::repeat_structure(
                    rid,
                    EventId::new(ReplicaId(9), 1),
                    EventId::new(ReplicaId(9), 2),
                ),
            })
            .schema_major(),
            2,
            "CreateRepeatStructure is born at v2 — even for default kind/voltas"
        );
        assert_eq!(
            OperationKind::DeleteRepeatStructure(DeleteRepeatStructureOp { repeat: rid })
                .schema_major(),
            0,
            "DeleteRepeatStructure carries a bare id — a major-0 layout"
        );

        // Genesis tranche G1 (i7): CreateInstrument is *unconditionally* v2 —
        // contract pin 4/trap 3. Unlike CreateRegion/SetStaffLayout above,
        // whose v2 embedding rides an `Option` and is value-dependent,
        // Instrument's schema-major-2 appends (sound_config, default_clef,
        // default_staff_lines, ...) are mandatory fields, so even the most
        // minimal instrument — every optional field at `None`, built via
        // `Instrument::new` exactly like `valuegen::instrument` does — stamps
        // 2. Asserted on the minimal value specifically, so an arm that
        // becomes value-dependent (checking e.g. `range.is_some()`) is
        // caught immediately rather than only on a richer fixture.
        let minimal_instrument =
            epiphany_core::Instrument::new(epiphany_core::InstrumentId::new(ReplicaId(9), 7), "x");
        assert_eq!(
            OperationKind::CreateInstrument(crate::payload::CreateInstrumentOp {
                instrument: minimal_instrument,
            })
            .schema_major(),
            2,
            "CreateInstrument is unconditionally v2, even for the minimal instrument"
        );

        // (s5) Genesis tranche G2a: both new setters fall into the catch-all
        // `_ => 0` arm — contract pin 3 is explicit that adding them to the
        // `=> 2` arm alongside `SetMetadata` would be the bug, since
        // `SetMetadata` sits there because `ScoreMetadata` has mandatory
        // major-2 appends, a property of *that* type and nothing else.
        // Asserted on non-default values so an arm that becomes
        // value-dependent in the wrong direction cannot hide behind the
        // `Default`.
        let non_default_layout = {
            let mut d = epiphany_core::CanvasLayoutDefaults::default();
            d.page_size.width = epiphany_determinism::CanonicalF64::new(200.0).unwrap();
            d
        };
        assert_eq!(
            OperationKind::SetCanvasLayoutDefaults(crate::payload::SetCanvasLayoutDefaultsOp {
                layout_defaults: non_default_layout,
            })
            .schema_major(),
            0,
            "SetCanvasLayoutDefaults stays in the major-0 catch-all"
        );
        let non_default_precedence = crate::valuegen::spelling_precedence(1);
        assert_ne!(
            non_default_precedence,
            epiphany_core::SpellingPrecedence::default()
        );
        assert_eq!(
            OperationKind::SetSpellingPrecedence(crate::payload::SetSpellingPrecedenceOp {
                precedence: non_default_precedence,
            })
            .schema_major(),
            0,
            "SetSpellingPrecedence stays in the major-0 catch-all"
        );

        // (t2) Genesis tranche G2b: the opposite of G2a's pin — SetTuningContext
        // is *unconditionally* 3, the same "no lower-major layout exists" shape
        // as CreateInstrument above (not a value-dependent Option-hidden
        // embedding). Asserted on the minimal (default) settings specifically,
        // so an arm that becomes value-dependent is caught immediately.
        assert_eq!(
            OperationKind::SetTuningContext(crate::payload::SetTuningContextOp {
                settings: crate::valuegen::tuning_context_settings(0),
            })
            .schema_major(),
            3,
            "SetTuningContext is unconditionally v3, even for the minimal settings"
        );
    }

    /// (t1) Genesis tranche G2b: kind and tag are both 34, and the
    /// discriminant byte leads the canonical encoding of the op payload.
    ///
    /// **Mutation:** move either `OperationKind::SetTuningContext`'s
    /// discriminant or `OperationKindTag::SetTuningContext`'s tag to 35;
    /// must fail.
    #[test]
    fn t1_set_tuning_context_kind_and_tag_are_both_34() {
        use crate::payload::{OperationKindTag, SetTuningContextOp};
        let op = OperationKind::SetTuningContext(SetTuningContextOp {
            settings: crate::valuegen::tuning_context_settings(1),
        });
        assert_eq!(op.tag(), OperationKindTag::SetTuningContext);
        assert_eq!(op.tag().discriminant(), 34);
        let mut bytes = Vec::new();
        op.encode_canonical(&mut bytes);
        assert_eq!(
            bytes[0], 34,
            "the discriminant byte must lead the canonical encoding"
        );
    }

    /// (t3) Genesis tranche G2b: a block containing exactly one
    /// `SetTuningContext` stamps schema major 3.
    ///
    /// **Mutation:** make `schema_major` ignore the `SetTuningContext` arm
    /// (fold it into the catch-all `_ => 0`); must fail.
    #[test]
    fn t3_a_block_with_one_set_tuning_context_stamps_major_3() {
        let op = OperationKind::SetTuningContext(crate::payload::SetTuningContextOp {
            settings: crate::valuegen::tuning_context_settings(1),
        });
        let envelopes = [op.clone()];
        let major = envelopes.iter().map(|k| k.schema_major()).max().unwrap();
        assert_eq!(
            major, 3,
            "a block carrying only SetTuningContext stamps major 3"
        );
    }

    /// (t8) Genesis tranche G2b: kind 34 carries epoch 10
    /// (`spec/PLAN_GMINOR_SCHEMA_MINOR.md` §4), and a block containing it
    /// stamps schema minor 10.
    ///
    /// **Mutation:** assign epoch 9 instead of 10 in `introduced_minor`'s
    /// `SetTuningContext` arm; must fail.
    #[test]
    fn t8_set_tuning_context_carries_epoch_10() {
        let op = OperationKind::SetTuningContext(crate::payload::SetTuningContextOp {
            settings: crate::valuegen::tuning_context_settings(1),
        });
        assert_eq!(op.introduced_minor(), Some(10));
        assert_eq!(op.tag().introduced_minor(), Some(10));

        let env = OperationEnvelope {
            id: OperationId::new(ReplicaId(1), 1),
            author: crate::support::AuthorId(0),
            stamp: crate::stamp::OperationStamp::new(
                crate::stamp::HybridLogicalClock::new(epiphany_core::WallClockTime(1), 1),
                OperationId::new(ReplicaId(1), 1),
            ),
            causal_context: crate::causal::CausalContext::new(),
            transaction: None,
            payload: OperationPayload::Primitive(op),
        };
        assert_eq!(
            crate::payload::operation_block_introduced_minor(&[env]),
            Some(10),
            "a block containing kind 34 stamps minor 10"
        );
    }

    #[test]
    fn the_canonical_base_embeds_no_repeat_values() {
        // The surgical form of the cross-major byte-identity promise for the
        // repeat vocabulary: two reductions identical except for the created
        // repeat's v2 content (kind payload) must produce byte-identical
        // canonical bases — the base records the mint as a TypedObjectId
        // (discriminant 23) plus an Applied effect, never the filled value.
        let e1 = EventId::new(ReplicaId(1), 100);
        let e2 = EventId::new(ReplicaId(1), 101);
        let rid = epiphany_core::RepeatStructureId::new(ReplicaId(1), 1);
        let base_bytes = |count: u32| {
            let mut repeat = crate::valuegen::repeat_structure(rid, e1, e2);
            repeat.kind = epiphany_core::RepeatKind::SimpleRepeat { count };
            let mut set = OperationSet::new();
            set.accept_all(vec![
                insert(1, 0, 10, 1, 100, 0),
                insert(1, 1, 11, 1, 101, 1),
                prim_env(
                    1,
                    2,
                    12,
                    seen_r1(1),
                    OperationKind::CreateRepeatStructure(CreateRepeatStructureOp { repeat }),
                ),
            ]);
            let state = set.reduce();
            assert!(
                matches!(
                    state.objects.get(&TypedObjectId::RepeatStructure(rid)),
                    Some(ObjectState::Live)
                ),
                "the create must APPLY for this test to mean anything"
            );
            state.canonical_bytes()
        };
        assert_eq!(
            base_bytes(2),
            base_bytes(9),
            "differing repeat v2 content must not reach the canonical base"
        );
    }

    #[test]
    fn the_canonical_base_is_byte_identical_across_data_model_majors() {
        // Binary Format §Schema Major 1 / §Schema Major 2: the canonical-base
        // MaterializedState embeds none of the data-model-major values, so its
        // bytes MUST NOT move across those bumps. This golden-locks a seeded
        // reduction's canonical bytes; if it fails after a data-model change,
        // a filled type has leaked into the canonical base — which the majors
        // promise not to do. (A deliberate change to the base's own vocabulary
        // — an appended discriminant the seeded corpus emits — re-pins this
        // consciously. Re-pinned at Phase D: `gen_payload` gained the repeat
        // pair, discriminants 28/29, which shifted the seeded RNG stream and
        // with it the whole corpus. NOTE the seeded corpus's repeat creates
        // all no-op (their random anchors miss the live events), so THIS pin
        // cannot detect a repeat-value leak into the base — the dedicated
        // `the_canonical_base_embeds_no_repeat_values` test below covers
        // that with an APPLIED create.)
        //
        // Re-pinned again at Push 4a: `gen_payload` gained `TransposeInterval`,
        // discriminant 30, and `rng.below(27)` became `below(28)` — which
        // reshuffles the whole seeded stream, so every operation id and effect
        // moves. Nothing leaked: `canonical_bytes` embeds effects, conflicts,
        // and anomalies, never payload values, and the new payload's
        // constituents are major-0 layouts regardless.
        //
        // Re-pinned again at genesis tranche G1
        // (`spec/CONTRACT_GENESIS_G1_INSTRUMENT.md`): `gen_payload` gained
        // `CreateInstrument`, discriminant 31, and `rng.below(28)` became
        // `below(29)` — the same reshuffle, for the same reason. Nothing
        // leaked here either: `CreateInstrument.schema_major()` is 2
        // (unconditionally, contract pin 4), but `MaterializedState` stamps
        // no schema major at all — that is an `OperationEnvelopeBlock`
        // concern in `epiphany-bundle`, which this packet does not touch.
        //
        // Re-pinned again at genesis tranche G2a
        // (`spec/CONTRACT_GENESIS_G2A_SETTINGS.md`): `gen_payload` gained
        // `SetCanvasLayoutDefaults` (arm 29) and `SetSpellingPrecedence`
        // (arm 30), and `rng.below(29)` became `below(31)` — the same
        // reshuffle, for the same reason: every operation id, effect, and
        // conflict downstream of the first draw moves. Confirmed a corpus
        // shift, not a value leak, by construction rather than inspection:
        // `MaterializedState` (`reduce.rs:504`) embeds no `Score` field value
        // for *any* setting, `SetMetadata` included — the base carries only
        // effects, conflicts, anomalies, objects, spellings, breaks,
        // page-breaks, and pending state. Neither new payload changes that
        // shape, and both are schema major 0 unconditionally (pin 3: no new
        // `schema_major()` arm), so there is no schema-major surface for a
        // leak to appear on even if the base did stamp one (it does not —
        // that is `OperationEnvelopeBlock`'s concern in `epiphany-bundle`,
        // untouched by this packet).
        //
        // Re-pinned again at genesis tranche G2b
        // (`spec/CONTRACT_GENESIS_G2B_TUNING.md`): `gen_payload` gained
        // `SetTuningContext` (arm 31), and `rng.below(31)` became
        // `below(32)` — the same reshuffle, same reasoning. `SetTuningContext`
        // is schema major **3**, unlike its siblings, but that is
        // `OperationEnvelopeBlock`'s concern (`epiphany-bundle`), not
        // `MaterializedState`'s: the canonical base still embeds no `Score`
        // field value for any setting, so there remains no schema-major
        // surface on this type for a leak to appear on.
        //
        // Re-pinned again at genesis tranche G3a
        // (`spec/CONTRACT_GENESIS_G3A_ENTITIES.md`): `gen_payload` gained the
        // four remaining root-level mints (arms 32–35), and `rng.below(32)`
        // became `below(36)` — the same reshuffle, same reasoning. All four
        // are schema major 0 unconditionally (pin 2: no `schema_major()`
        // arm), and `MaterializedState` still embeds no `Score` field value
        // for any of the four carried types, so there remains no surface on
        // this type for a leak to appear on.
        //
        // Re-pinned again at genesis tranche G3b
        // (`spec/CONTRACT_GENESIS_G3B_MEASURE.md`): `gen_payload` gained
        // `CreateMeasure` (arm 36), and `rng.below(36)` became `below(37)` —
        // the same reshuffle, same reasoning. `CreateMeasure` is schema major
        // 0 unconditionally (pin 2: no `schema_major()` arm), and
        // `MaterializedState` still embeds no `Score` field value for the
        // carried `Measure`, so there remains no surface on this type for a
        // leak to appear on.
        let mut rng = epiphany_determinism::fuzz::SplitMix64::new(0xBA5E);
        let envelopes = crate::fuzz::gen_envelope_set(&mut rng, 200);
        let mut set = OperationSet::new();
        set.accept_all(envelopes);
        let bytes = set.reduce().canonical_bytes();
        let digest = epiphany_determinism::blake3_256(&bytes);
        let hex: String = digest.iter().map(|b| format!("{b:02x}")).collect();
        assert_eq!(
            hex,
            "aefd8ecd6df3abecb84229d5b77585dead9575b6f6554097bbd6907c7b0329d7"
        );
    }

    #[test]
    fn transpose_skips_system_derived_targets_p12_k3() {
        // Review finding on P12-K3: Transpose must not rewrite a
        // SYSTEM_DERIVED pitch's intrinsic content in place — that would
        // desynchronize the content from the id's derivation inputs (and from
        // the `system_mints` registry the modify preconditions consult),
        // making the K3 verdict depend on where a snapshot was cut. System
        // targets are skipped like tombstoned ones; all-system degenerates to
        // the K3 precondition no-op.
        use epiphany_core::derive_system_pitch_id;
        let content = crate::valuegen::pitch_value_nth(1);
        let system_id = derive_system_pitch_id(&content);
        let normal = PitchId::new(ReplicaId(9), 501);

        let a = insert_with_pitch_content(1, 0, 10, 1, 100, 0, system_id, &content);
        let b = insert_with_pitch_content(1, 1, 11, 2, 101, 0, normal, &content);
        let after_inserts = CausalContext::new().with_seen(ReplicaId(1), 1);
        // Mixed normal/system targets: the system pitch is skipped, the
        // normal one shifts, the op applies.
        let t_mixed = prim_env(
            3,
            0,
            30,
            after_inserts.clone(),
            OperationKind::Transpose(TransposeOp {
                targets: vec![system_id, normal],
                chromatic_steps: 2,
            }),
        );
        // All targets system-derived: the K3 precondition no-op.
        let t_system = prim_env(
            4,
            0,
            31,
            after_inserts,
            OperationKind::Transpose(TransposeOp {
                targets: vec![system_id],
                chromatic_steps: 2,
            }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![a, b, t_mixed.clone(), t_system.clone()]);
        let state = set.reduce();
        let effect = |id: OperationId| {
            state
                .effects
                .iter()
                .find(|(e, _)| *e == id)
                .map(|(_, eff)| eff)
                .expect("effect recorded")
        };
        assert_eq!(effect(t_mixed.id), &OperationEffect::Applied);
        assert_eq!(
            effect(t_system.id),
            &OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::SystemDerivedContentImmutable,
                },
            },
            "an all-system-derived transpose refuses under P12-K3"
        );
    }

    #[test]
    fn differing_concurrent_resolves_name_both_resolvers_in_the_meta_conflict() {
        // Chapter 6 §Conflict Resolution Operations: a later differing resolve
        // reduces to Conflicted with a meta-conflict record; the record names
        // the earlier resolver (whose action stands) as winner and both
        // resolvers as causes.
        use crate::conflict::ResolutionAction;
        use crate::payload::{ResolveConflictPayload, RespellPitchOp};

        let pitch = PitchId::new(ReplicaId(9), 500);
        let mut insert_env = insert(1, 0, 10, 1, 100, 0);
        if let OperationPayload::Primitive(OperationKind::InsertEvent(ref mut op)) =
            insert_env.payload
        {
            op.event = crate::valuegen::insert_event_value(
                op.event_id(),
                op.voice(),
                op.musical_position(),
                op.musical_duration(),
                &[pitch],
            );
        }
        let respell = |replica: u64, physical: i64, byte: u8| {
            prim_env(
                replica,
                0,
                physical,
                CausalContext::new().with_seen(ReplicaId(1), 0),
                OperationKind::RespellPitch(RespellPitchOp {
                    pitch,
                    spelling: crate::valuegen::spelling(byte),
                }),
            )
        };
        let respell_a = respell(2, 20, 0xAA);
        let respell_b = respell(3, 21, 0xBB);
        let mut set = OperationSet::new();
        set.accept_all(vec![
            insert_env.clone(),
            respell_a.clone(),
            respell_b.clone(),
        ]);
        let cid = set.reduce().conflicts.records()[0].id;

        let resolve = |replica: u64, physical: i64, action: ResolutionAction| {
            let id = OperationId::new(ReplicaId(replica), 0);
            OperationEnvelope {
                id,
                author: AuthorId(0),
                stamp: OperationStamp::new(HybridLogicalClock::new(WallClockTime(physical), 0), id),
                causal_context: CausalContext::new()
                    .with_dot(respell_a.id)
                    .with_dot(respell_b.id),
                transaction: None,
                payload: OperationPayload::ResolveConflict(ResolveConflictPayload {
                    target: cid,
                    action,
                }),
            }
        };
        let first = resolve(4, 30, ResolutionAction::KeepWinner);
        let second = resolve(5, 31, ResolutionAction::AcceptLoser);
        let mut set2 = OperationSet::new();
        set2.accept_all(vec![
            insert_env,
            respell_a,
            respell_b,
            first.clone(),
            second.clone(),
        ]);
        let state = set2.reduce();
        let meta = state
            .conflicts
            .records()
            .iter()
            .find(|r| r.id != cid)
            .expect("a meta-conflict record exists");
        assert_eq!(
            meta.kind,
            ConflictKind::StructuralFieldCollision {
                winner: first.id,
                loser: second.id,
                field: FieldPath("conflict_resolution".to_string()),
            },
            "the earlier resolver's action stands, so it is the winner"
        );
        assert_eq!(
            meta.caused_by,
            vec![first.id, second.id],
            "both resolvers are named as causes"
        );
    }

    #[test]
    fn deleting_an_event_records_the_marker_reanchor_repair() {
        // Chapter 6 §Re-Anchoring: "Re-anchoring actions MUST be recorded as
        // RepairRecord entries in the triggering operation's effect", and the
        // rule table's marker row: re-anchor to the *nearest event in the same
        // staff instance* (four-key ordering). The fixture voice's events sit
        // at ascending quarter positions, so deleting the first re-anchors the
        // marker to the second (same voice: proximity rank 0 dominates any
        // closer event in a sibling voice).
        use epiphany_core::generators::valid_score;
        let mut base = valid_score(0x5EED);
        let voice_events = base
            .voices()
            .map(|(_, _, v)| v.events.clone())
            .next()
            .expect("the fixture has a voice");
        let event_id = voice_events[0];
        let expected = voice_events[1];
        let marker_id = epiphany_core::MarkerId::new(ReplicaId(9), 700);
        base.cross_cutting.markers.push(epiphany_core::Marker {
            id: marker_id,
            anchor: TimeAnchor::Event {
                id: event_id,
                offset: AnchorOffset::Zero,
            },
        });

        let del = prim_env(
            2,
            0,
            10,
            CausalContext::new(),
            OperationKind::DeleteEvent(DeleteEventOp {
                event: event_id,
                tuplet_compensation: TupletCompensation::NotInTuplet,
            }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![del.clone()]);
        let result = set.reduce_onto(&base);

        let effect = result
            .state
            .effects
            .iter()
            .find(|(id, _)| *id == del.id)
            .map(|(_, e)| e)
            .expect("delete effect recorded");
        let OperationEffect::AppliedWithRepair { repairs } = effect else {
            panic!("expected AppliedWithRepair, got {effect:?}");
        };
        assert!(
            repairs.iter().any(|r| {
                r.target == TypedObjectId::Marker(marker_id)
                    && r.kind
                        == RepairKind::Reanchored {
                            from: TypedObjectId::Event(event_id),
                            to: TypedObjectId::Event(expected),
                            reason: ReanchorReason::SameVoiceNearer,
                        }
            }),
            "the marker re-anchor to the nearest same-voice event is a recorded \
             repair, not a silent mutation: {repairs:?}"
        );
        let marker = result
            .score
            .cross_cutting
            .markers
            .iter()
            .find(|m| m.id == marker_id)
            .expect("marker survives");
        assert!(
            matches!(marker.anchor, TimeAnchor::Event { id, .. } if id == expected),
            "the graph agrees with the recorded repair"
        );
        assert!(epiphany_core::check_invariants(&result.score).is_empty());
    }

    #[test]
    fn marker_reanchor_prefers_the_forward_survivor_on_distance_ties() {
        // Four-key ordering, key 3: forward (0) before backward (1). Three
        // whole-note events at positions 10/12/14 in the base's first voice;
        // deleting the middle one leaves survivors at equal distance 2 on both
        // sides, so the *forward* neighbor (position 14) wins.
        use epiphany_core::generators::valid_score;
        let mut base = valid_score(0x5EED);
        let (staff_instance, voice) = {
            let instance = &base.canvas.regions[0].staff_instances()[0];
            (instance.id, instance.voices[0].id)
        };
        let backward = EventId::new(ReplicaId(3), 0);
        let referent = EventId::new(ReplicaId(3), 1);
        let forward = EventId::new(ReplicaId(3), 2);
        let insert_at = |counter: u64, event: EventId, position: i64| {
            let ctx = if counter == 0 {
                CausalContext::new()
            } else {
                CausalContext::new().with_seen(ReplicaId(3), counter - 1)
            };
            prim_env(
                3,
                counter,
                10 + counter as i64,
                ctx,
                OperationKind::InsertEvent(InsertEventOp {
                    staff_instance,
                    event: crate::valuegen::insert_event_value(
                        event,
                        voice,
                        pos(position),
                        epiphany_core::MusicalDuration::whole(),
                        &[],
                    ),
                }),
            )
        };
        let marker_id = epiphany_core::MarkerId::new(ReplicaId(9), 701);
        base.cross_cutting.markers.push(epiphany_core::Marker {
            id: marker_id,
            anchor: TimeAnchor::Event {
                id: referent,
                offset: AnchorOffset::Zero,
            },
        });
        let del = prim_env(
            3,
            3,
            20,
            CausalContext::new().with_seen(ReplicaId(3), 2),
            OperationKind::DeleteEvent(DeleteEventOp {
                event: referent,
                tuplet_compensation: TupletCompensation::NotInTuplet,
            }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![
            insert_at(0, backward, 10),
            insert_at(1, referent, 12),
            insert_at(2, forward, 14),
            del.clone(),
        ]);
        let result = set.reduce_onto(&base);
        let effect = result
            .state
            .effects
            .iter()
            .find(|(id, _)| *id == del.id)
            .map(|(_, e)| e)
            .expect("delete effect recorded");
        let OperationEffect::AppliedWithRepair { repairs } = effect else {
            panic!("expected AppliedWithRepair, got {effect:?}");
        };
        assert!(
            repairs.iter().any(|r| {
                r.target == TypedObjectId::Marker(marker_id)
                    && r.kind
                        == RepairKind::Reanchored {
                            from: TypedObjectId::Event(referent),
                            to: TypedObjectId::Event(forward),
                            reason: ReanchorReason::SameVoiceNearer,
                        }
            }),
            "equal distances tie-break forward before backward: {repairs:?}"
        );
        assert!(
            matches!(
                result
                    .score
                    .cross_cutting
                    .markers
                    .iter()
                    .find(|m| m.id == marker_id)
                    .expect("marker survives")
                    .anchor,
                TimeAnchor::Event { id, .. } if id == forward
            ),
            "the graph agrees with the recorded repair"
        );
        assert!(epiphany_core::check_invariants(&result.score).is_empty());
    }

    #[test]
    fn system_pitch_counter_collision_halts_reduction() {
        // Chapter 5 §"System-Derived Counter Collisions": two different
        // canonical input sets claiming one system-derived counter record a
        // SystemIdentifierCollision, reduction does not continue past the
        // collision, and neither input set occupies the collided counter.
        use epiphany_core::derive_system_pitch_id;
        let content_x = crate::valuegen::pitch_value_nth(1);
        let content_y = crate::valuegen::pitch_value_nth(2);
        let system_id = derive_system_pitch_id(&content_x);
        assert_eq!(system_id.replica(), ReplicaId::SYSTEM_DERIVED);

        let before = insert(3, 0, 5, 4, 400, 0);
        let legit = insert_with_pitch_content(1, 0, 10, 1, 100, 0, system_id, &content_x);
        let claim = insert_with_pitch_content(2, 0, 20, 2, 200, 5, system_id, &content_y);
        let after = insert(1, 1, 30, 3, 300, 9);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            before.clone(),
            legit.clone(),
            claim.clone(),
            after.clone(),
        ]);
        let state = set.reduce();

        assert_eq!(state.anomalies.len(), 1, "exactly one collision recorded");
        match &state.anomalies[0].kind {
            IntegrityAnomalyKind::SystemIdentifierCollision {
                kind,
                colliding_counter,
                input_set_a,
                input_set_b,
            } => {
                assert_eq!(*kind, ObjectKind::Pitch);
                assert_eq!(*colliding_counter, system_id.counter());
                let mut sets = [input_set_a.0.clone(), input_set_b.0.clone()];
                sets.sort();
                let mut expected = [
                    canonical_pitch_bytes(&content_x),
                    canonical_pitch_bytes(&content_y),
                ];
                expected.sort();
                assert_eq!(sets, expected, "the anomaly retains both input sets");
            }
            other => panic!("expected SystemIdentifierCollision, got {other:?}"),
        }
        // Only the operation before the collision point reduced.
        assert_eq!(state.effects.len(), 1);
        assert_eq!(state.effects[0].0, before.id);
        // Neither input set occupies the collided counter.
        assert!(!state.objects.contains_key(&TypedObjectId::Pitch(system_id)));
        assert!(!state
            .objects
            .contains_key(&TypedObjectId::Event(EventId::new(ReplicaId(1), 100))));
        // The colliding pair and everything past the halt are held pending.
        let pending: BTreeMap<_, _> = state.pending.iter().copied().collect();
        let halted = PendingReason::HaltedBySystemCollision { at: claim.id };
        assert_eq!(pending.get(&legit.id), Some(&halted));
        assert_eq!(pending.get(&claim.id), Some(&halted));
        assert_eq!(pending.get(&after.id), Some(&halted));
        // Determinism: any permutation reduces to identical bytes.
        let mut reversed = OperationSet::new();
        reversed.accept_all(vec![after, claim, legit, before]);
        assert_eq!(state.canonical_bytes(), reversed.reduce().canonical_bytes());
    }

    #[test]
    fn reobserving_the_same_system_derivation_is_not_a_collision() {
        // The same (counter, inputs) pair re-observed is idempotent, not a
        // collision; the duplicate insert is refused by pitch-id freshness
        // (base-free parity with the graph-aware precondition).
        use epiphany_core::derive_system_pitch_id;
        let content_x = crate::valuegen::pitch_value_nth(1);
        let system_id = derive_system_pitch_id(&content_x);
        let a = insert_with_pitch_content(1, 0, 10, 1, 100, 0, system_id, &content_x);
        let b = insert_with_pitch_content(2, 0, 20, 2, 200, 5, system_id, &content_x);
        let mut set = OperationSet::new();
        set.accept_all(vec![a.clone(), b.clone()]);
        let state = set.reduce();
        assert!(state.anomalies.is_empty(), "same derivation: no collision");
        assert!(state.pending.is_empty(), "nothing is held");
        let effect = |id: OperationId| {
            state
                .effects
                .iter()
                .find(|(e, _)| *e == id)
                .map(|(_, eff)| eff)
                .expect("effect recorded")
        };
        assert_eq!(effect(a.id), &OperationEffect::Applied);
        assert_eq!(
            effect(b.id),
            &OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetTombstoned,
                },
            },
            "a reused pitch id is not fresh, in base-free reduction too"
        );
    }

    #[test]
    fn base_seeded_system_pitch_collides_with_an_op_claim() {
        // The registry seeds from the base graph: an operation claiming a
        // base-occupied system counter with different content collides. The
        // base occupant is graph state (not an operation of this reduction),
        // so it is left in place for diagnostic recovery.
        use epiphany_core::generators::valid_score;
        use epiphany_core::{derive_system_pitch_id, IdentifiedPitch};

        let content_x = crate::valuegen::pitch_value_nth(1);
        let content_y = crate::valuegen::pitch_value_nth(2);
        let system_id = derive_system_pitch_id(&content_x);

        let mut base = valid_score(0x5EED);
        let pitched_id = base
            .voices()
            .flat_map(|(_, _, v)| v.events.clone())
            .find(|e| matches!(base.events.get(*e), Some(Event::Pitched(_))))
            .expect("the fixture has a pitched event");
        if let Some(Event::Pitched(pe)) = base.events.get_mut(pitched_id) {
            pe.pitches[0] = IdentifiedPitch {
                id: system_id,
                pitch: content_x.clone(),
            };
        }

        let claim = insert_with_pitch_content(2, 0, 10, 2, 200, 5, system_id, &content_y);
        let mut set = OperationSet::new();
        set.accept_all(vec![claim.clone()]);
        let result = set.reduce_onto(&base);

        assert_eq!(result.state.anomalies.len(), 1);
        assert!(matches!(
            &result.state.anomalies[0].kind,
            IntegrityAnomalyKind::SystemIdentifierCollision {
                kind: ObjectKind::Pitch,
                ..
            }
        ));
        assert!(result.state.effects.is_empty(), "reduction halted");
        let pending: BTreeMap<_, _> = result.state.pending.iter().copied().collect();
        assert_eq!(
            pending.get(&claim.id),
            Some(&PendingReason::HaltedBySystemCollision { at: claim.id })
        );
        assert!(
            result.score.events.get(pitched_id).is_some(),
            "the base occupant stays; recovery is external"
        );
    }

    #[test]
    fn a_system_derived_pitch_content_rewrite_is_refused_p12_k3() {
        // Pass 12 (P12-K3): a SYSTEM_DERIVED pitch's intrinsic content is
        // immutable — an in-place rewrite would invalidate the id's content
        // derivation. A modify carrying the *registered* derivation content
        // still applies (nothing is rewritten).
        use epiphany_core::derive_system_pitch_id;
        let content = crate::valuegen::pitch_value_nth(1);
        let rewritten = crate::valuegen::pitch_value_nth(2);
        let system_id = derive_system_pitch_id(&content);

        let mint = insert_with_pitch_content(1, 0, 10, 1, 100, 0, system_id, &content);
        let rewrite = prim_env(
            1,
            1,
            20,
            seen_r1(0),
            OperationKind::ModifyIdentifiedPitch(ModifyIdentifiedPitchOp {
                pitch: system_id,
                value: rewritten.clone(),
            }),
        );
        let same = prim_env(
            1,
            2,
            30,
            seen_r1(1),
            OperationKind::ModifyIdentifiedPitch(ModifyIdentifiedPitchOp {
                pitch: system_id,
                value: content.clone(),
            }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![mint.clone(), rewrite.clone(), same.clone()]);
        let state = set.reduce();

        let effect_of = |id: OperationId| {
            state
                .effects
                .iter()
                .find(|(e, _)| *e == id)
                .map(|(_, eff)| eff)
        };
        assert_eq!(
            effect_of(rewrite.id),
            Some(&OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::SystemDerivedContentImmutable,
                },
            }),
            "rewriting a system-derived pitch's intrinsic content is refused"
        );
        assert_eq!(
            effect_of(same.id),
            Some(&OperationEffect::Applied),
            "a modify carrying the registered derivation content passes"
        );
        // Determinism: any permutation reduces to identical bytes.
        let mut reversed = OperationSet::new();
        reversed.accept_all(vec![same, rewrite, mint]);
        assert_eq!(state.canonical_bytes(), reversed.reduce().canonical_bytes());
    }

    #[test]
    fn a_modify_event_rewriting_a_system_pitch_is_refused_p12_k3() {
        // The same identity precondition through the ModifyEvent path: the
        // replacement event carries the system pitch with rewritten content.
        use epiphany_core::derive_system_pitch_id;
        let content = crate::valuegen::pitch_value_nth(1);
        let rewritten = crate::valuegen::pitch_value_nth(2);
        let system_id = derive_system_pitch_id(&content);

        let mint = insert_with_pitch_content(1, 0, 10, 1, 100, 0, system_id, &content);
        let mut replacement = crate::valuegen::insert_event_value(
            EventId::new(ReplicaId(1), 100),
            VoiceId::new(ReplicaId(9), 1),
            pos(0),
            epiphany_core::MusicalDuration::whole(),
            &[system_id],
        );
        if let Event::Pitched(pe) = &mut replacement {
            pe.pitches[0].pitch = rewritten;
        }
        let modify = prim_env(
            1,
            1,
            20,
            seen_r1(0),
            OperationKind::ModifyEvent(ModifyEventOp { event: replacement }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![mint, modify.clone()]);
        let state = set.reduce();

        assert_eq!(
            state
                .effects
                .iter()
                .find(|(e, _)| *e == modify.id)
                .map(|(_, eff)| eff),
            Some(&OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::SystemDerivedContentImmutable,
                },
            }),
            "a ModifyEvent rewriting a carried system pitch is refused"
        );
    }

    #[test]
    fn a_modify_event_introducing_a_never_minted_system_pitch_is_refused_p13_k1() {
        // P13-K1 (ratified: reject the introduction). The INTRODUCTION sibling
        // of the p12_k3 rewrite refusal: a ModifyEvent whose replacement
        // carries a *never-minted* system-derived pitch id is refused
        // (`TargetMissing`) — the system namespace is the system's to mint.
        // Before the fix this slipped through in-session (`system_mints` had no
        // entry, so the identity check saw nothing) yet read
        // `SystemDerivedContentImmutable` after a snapshot re-seeded the pitch
        // as a system mint — the snapshot-cut asymmetry the candidate named.
        // The verdict no longer depends on the registry: the pitch is not live
        // in `objects` in either frame, so both refuse identically.
        use epiphany_core::derive_system_pitch_id;
        let content = crate::valuegen::pitch_value_nth(3);
        let system_id = derive_system_pitch_id(&content); // never minted

        // A live, pitchless event modified to CARRY the never-minted system
        // pitch (an introduction, not an in-place rewrite).
        let insert = insert(1, 0, 10, 1, 100, 0);
        let replacement = crate::valuegen::insert_event_value(
            EventId::new(ReplicaId(1), 100),
            VoiceId::new(ReplicaId(9), 1),
            pos(0),
            epiphany_core::MusicalDuration::whole(),
            &[system_id],
        );
        let modify = prim_env(
            1,
            1,
            20,
            seen_r1(0),
            OperationKind::ModifyEvent(ModifyEventOp { event: replacement }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![insert, modify.clone()]);
        let state = set.reduce();

        assert_eq!(
            state
                .effects
                .iter()
                .find(|(e, _)| *e == modify.id)
                .map(|(_, eff)| eff),
            Some(&OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetMissing,
                },
            }),
            "a ModifyEvent introducing a never-minted system pitch is refused"
        );
        assert!(
            !state.objects.contains_key(&TypedObjectId::Pitch(system_id)),
            "the introduced system pitch never enters the ledger"
        );
    }

    #[test]
    fn undo_orphaning_a_pre_existing_slur_cascades_it_in_the_ledger_p13_d1() {
        // P13-D1: a PRE-EXISTING structure whose every anchor event is
        // undo-tombstoned must cascade in the LEDGER (`objects` → Tombstoned)
        // with a same-step RepairRecord — not merely leave the graph while
        // staying Live with no record (Ch6 §Re-Anchoring MUST). The slur is
        // created OUTSIDE the undone transaction, so the undo ORPHANS it rather
        // than tombstoning it directly. Before the fix the undo path ran only
        // the graph half of the re-anchor, leaving `objects[slur]` Live and no
        // repair recorded.
        use epiphany_core::SlurId;
        let tx = TransactionId::new(ReplicaId(1), 900);
        let e1 = EventId::new(ReplicaId(1), 100);
        let e2 = EventId::new(ReplicaId(1), 101);
        let slur_id = SlurId::new(ReplicaId(9), 500);
        let sid = TypedObjectId::Slur(slur_id);

        let insert_kind = |event: EventId, at: i64| {
            OperationKind::InsertEvent(InsertEventOp {
                staff_instance: StaffInstanceId::new(ReplicaId(9), 0),
                event: crate::valuegen::insert_event_value(
                    event,
                    VoiceId::new(ReplicaId(9), 1),
                    pos(at),
                    epiphany_core::MusicalDuration::whole(),
                    &[],
                ),
            })
        };
        let slur_op = OperationKind::CreateCrossCutting(CreateCrossCuttingOp {
            structure: CrossCuttingValue::Slur(crate::valuegen::slur(slur_id, e1, e2)),
        });
        let undo = undo_env(1, 4, 40, seen_r1(3), tx, UndoPolicy::StrictInverse);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(1, 1, 11, seen_r1(0), tx, insert_kind(e1, 0)),
            tx_member(1, 2, 12, seen_r1(1), tx, insert_kind(e2, 10)),
            prim_env(1, 3, 13, seen_r1(2), slur_op),
            undo.clone(),
        ]);
        let state = set.reduce();

        // The orphaned slur cascades in the ledger (not left Live)…
        assert!(
            matches!(
                state.objects.get(&sid),
                Some(ObjectState::Tombstoned { .. })
            ),
            "the orphaned slur cascades in the ledger, not left Live with no repair"
        );
        // …and the undo records the same-step CascadeDeleted repair (Ch6 MUST).
        let undo_records_cascade = matches!(
            state.effects.iter().find(|(id, _)| *id == undo.id).map(|(_, e)| e),
            Some(OperationEffect::AppliedWithRepair { repairs })
                if repairs.iter().any(|r| r.target == sid
                    && matches!(r.kind, RepairKind::CascadeDeleted))
        );
        assert!(
            undo_records_cascade,
            "the undo records the orphaned slur's cascade repair (Ch6 same-step MUST)"
        );
        // Determinism: a permuted delivery reduces to identical bytes.
        let mut permuted = OperationSet::new();
        permuted.accept_all(vec![
            undo.clone(),
            prim_env(
                1,
                3,
                13,
                seen_r1(2),
                OperationKind::CreateCrossCutting(CreateCrossCuttingOp {
                    structure: CrossCuttingValue::Slur(crate::valuegen::slur(slur_id, e1, e2)),
                }),
            ),
            tx_member(1, 2, 12, seen_r1(1), tx, insert_kind(e2, 10)),
            tx_member(1, 1, 11, seen_r1(0), tx, insert_kind(e1, 0)),
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
        ]);
        assert_eq!(
            state.canonical_bytes(),
            permuted.reduce().canonical_bytes(),
            "the orphan-cascade converges regardless of delivery order"
        );
    }

    #[test]
    fn deleting_a_cue_source_does_not_leave_a_contradictory_repair_for_a_bridging_slur_p13_d2() {
        // P13-D2: a slur Z anchored on {X, cue-of-X}. Deleting X cascades the
        // cue (a cue depends on its source event). The cue-cascade's ledger
        // re-anchor must NOT re-anchor Z onto X — X is itself being deleted —
        // which would record `Reanchored{to: X}` for Z and then `CascadeDeleted`
        // in the same effect (a contradictory trail). With X tombstoned before
        // the graph delete, Z sees no live survivor and cascades once.
        use epiphany_core::generators::valid_score;
        use epiphany_core::{
            check_invariants, CueEvent, CueRendering, Event, EventDuration, EventPosition,
            MusicalDuration, MusicalPosition, RationalTime, SlurId,
        };
        let mut base = valid_score(0x5EED);
        let (voice_id, x, count) = {
            let v = &base.canvas.regions[0].staff_instances()[0].voices[0];
            (v.id, v.events[0], v.events.len() as i64)
        };
        let cue = EventId::new(ReplicaId(9), 9_001);
        let slur_id = SlurId::new(ReplicaId(9), 9_002);
        let sid = TypedObjectId::Slur(slur_id);
        // A cue sourced on X, placed just past the voice's last event, and a
        // slur bridging X and its cue.
        base.events
            .insert(Event::Cue(CueEvent {
                id: cue,
                voice: voice_id,
                position: EventPosition::Musical(MusicalPosition(
                    RationalTime::new(count, 4).unwrap(),
                )),
                duration: EventDuration::Musical(MusicalDuration(RationalTime::new(1, 4).unwrap())),
                source: vec![x],
                rendering: CueRendering,
            }))
            .expect("fresh cue id");
        base.canvas.regions[0]
            .content
            .staff_instances_mut()
            .expect("staff-based content")[0]
            .voices[0]
            .events
            .push(cue);
        base.cross_cutting
            .slurs
            .push(crate::valuegen::slur(slur_id, x, cue));
        assert!(
            check_invariants(&base).is_empty(),
            "the cue + bridging-slur base is well-formed"
        );

        let del = prim_env(
            2,
            0,
            20,
            CausalContext::new(),
            OperationKind::DeleteEvent(DeleteEventOp {
                event: x,
                tuplet_compensation: TupletCompensation::NotInTuplet,
            }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![del.clone()]);
        let result = set.reduce_onto(&base);

        // The bridging slur cascaded (both its anchors — X and cue-of-X — died).
        assert!(
            matches!(
                result.state.objects.get(&sid),
                Some(ObjectState::Tombstoned { .. })
            ),
            "the bridging slur cascades"
        );
        // …recorded exactly ONCE as a cascade, never a contradictory
        // `Reanchored{to: X}` onto the event being deleted.
        let repairs = match result
            .state
            .effects
            .iter()
            .find(|(id, _)| *id == del.id)
            .map(|(_, e)| e)
        {
            Some(OperationEffect::AppliedWithRepair { repairs }) => repairs.clone(),
            other => panic!("expected AppliedWithRepair, got {other:?}"),
        };
        let slur_repairs: Vec<_> = repairs.iter().filter(|r| r.target == sid).collect();
        assert_eq!(
            slur_repairs.len(),
            1,
            "the bridging slur is repaired exactly once: {slur_repairs:?}"
        );
        assert!(
            matches!(slur_repairs[0].kind, RepairKind::CascadeDeleted),
            "the one record is a cascade, not a contradictory reanchor: {:?}",
            slur_repairs[0].kind
        );
        assert!(check_invariants(&result.score).is_empty());
    }

    #[test]
    fn a_rank_four_reanchor_records_same_canvas_nearer_p12_c4() {
        // Pass 12 (P12-C4): the rank-4 (same-canvas) proximity survivor has
        // its own appended reason; ExplicitFallback stays the beyond-ladder
        // recording only.
        assert_eq!(reason_for_rank(4), ReanchorReason::SameCanvasNearer);
        assert_eq!(reason_for_rank(3), ReanchorReason::SameRegionNearer);
        assert_eq!(reason_for_rank(5), ReanchorReason::ExplicitFallback);
    }

    #[test]
    fn an_unestablished_rank_four_reanchor_keeps_the_explicit_fallback() {
        // Review finding on P12-C4: `containment_rank` also returns 4 when a
        // voice's staff-instance placement is *unresolvable* (here: base-free
        // reduction, where inserted voices have no op-created instance), and
        // that conflated 4 must NOT be recorded as a positive
        // `SameCanvasNearer` claim — the honest recording stays
        // `ExplicitFallback`. Selection order is unchanged either way.
        let e1 = EventId::new(ReplicaId(1), 100);
        let e2 = EventId::new(ReplicaId(1), 101);
        let slur = epiphany_core::SlurId::new(ReplicaId(1), 1);
        let create = prim_env(
            1,
            2,
            12,
            CausalContext::new().with_seen(ReplicaId(1), 1),
            create_slur(slur, e1, e2),
        );
        let del = prim_env(
            1,
            3,
            13,
            CausalContext::new().with_seen(ReplicaId(1), 2),
            OperationKind::DeleteEvent(DeleteEventOp {
                event: e1,
                tuplet_compensation: TupletCompensation::NotInTuplet,
            }),
        );
        // Different voices on different staff instances, neither instance
        // op-created in a region: instance→region never resolves, so
        // containment_rank falls through to its unestablished 4.
        let a = insert(1, 0, 10, 1, 100, 0);
        let mut b = insert(1, 1, 11, 2, 101, 1);
        if let OperationPayload::Primitive(OperationKind::InsertEvent(ref mut op)) = b.payload {
            op.staff_instance = StaffInstanceId::new(ReplicaId(9), 1);
        }
        let mut set = OperationSet::new();
        set.accept_all(vec![a, b, create, del.clone()]);
        let state = set.reduce();
        let repair = state
            .effects
            .iter()
            .find(|(id, _)| *id == del.id)
            .and_then(|(_, eff)| match eff {
                OperationEffect::AppliedWithRepair { repairs } => repairs
                    .iter()
                    .find(|r| r.target == TypedObjectId::Slur(slur))
                    .cloned(),
                _ => None,
            })
            .expect("the slur endpoint deletion records a re-anchor repair");
        assert_eq!(
            repair.kind,
            RepairKind::Reanchored {
                from: TypedObjectId::Event(e1),
                to: TypedObjectId::Event(e2),
                reason: ReanchorReason::ExplicitFallback,
            },
            "an unresolvable-placement rank 4 records the honest fallback"
        );
    }

    // --- ResolveEquivocation (operation_catalog §"ResolveEquivocation"). -----

    /// A `RespellPitch` envelope at `id` with an explicit causal context.
    fn respell_at(
        id: OperationId,
        physical: i64,
        spelling: u8,
        ctx: CausalContext,
    ) -> OperationEnvelope {
        use crate::payload::RespellPitchOp;
        OperationEnvelope {
            id,
            author: AuthorId(0),
            stamp: OperationStamp::new(HybridLogicalClock::new(WallClockTime(physical), 0), id),
            causal_context: ctx,
            transaction: None,
            payload: OperationPayload::Primitive(OperationKind::RespellPitch(RespellPitchOp {
                pitch: epiphany_core::PitchId::new(ReplicaId(9), 500),
                spelling: crate::valuegen::spelling(spelling),
            })),
        }
    }

    /// A `ResolveEquivocation` envelope at `id` naming `(target, chosen)`.
    fn resolve_equivocation_env(
        id: OperationId,
        physical: i64,
        target: OperationId,
        chosen: crate::EnvelopeHash,
    ) -> OperationEnvelope {
        OperationEnvelope {
            id,
            author: AuthorId(0),
            stamp: OperationStamp::new(HybridLogicalClock::new(WallClockTime(physical), 0), id),
            causal_context: CausalContext::new(),
            transaction: None,
            payload: OperationPayload::ResolveEquivocation(
                crate::payload::ResolveEquivocationPayload { target, chosen },
            ),
        }
    }

    fn effect_of(state: &MaterializedState, id: OperationId) -> Option<&OperationEffect> {
        state
            .effects
            .iter()
            .find(|(e, _)| *e == id)
            .map(|(_, eff)| eff)
    }

    #[test]
    fn resolve_equivocation_promotes_the_chosen_candidate_and_unblocks_dependents() {
        let pitch = epiphany_core::PitchId::new(ReplicaId(9), 500);

        // An InsertEvent carrying `pitch` makes the pitch Live.
        let mut insert_env = insert(1, 0, 10, 1, 100, 0);
        if let OperationPayload::Primitive(OperationKind::InsertEvent(ref mut op)) =
            insert_env.payload
        {
            op.event = crate::valuegen::insert_event_value(
                op.event_id(),
                op.voice(),
                op.musical_position(),
                op.musical_duration(),
                &[pitch],
            );
        }

        // An equivocated pair of respellings under one id, both after the insert.
        let eq_id = OperationId::new(ReplicaId(9), 0);
        let after_insert = CausalContext::new().with_seen(ReplicaId(1), 0);
        let cand_a = respell_at(eq_id, 20, 0xAA, after_insert.clone());
        let cand_b = respell_at(eq_id, 20, 0xBB, after_insert.clone());
        assert_ne!(cand_a.envelope_hash(), cand_b.envelope_hash());

        // A dependent causally covering the equivocated id: previously held
        // pending (DependsOnEquivocated); must unblock and reduce.
        let dependent = respell_at(
            OperationId::new(ReplicaId(2), 0),
            30,
            0xCC,
            CausalContext::new()
                .with_seen(ReplicaId(1), 0)
                .with_seen(ReplicaId(9), 0),
        );

        // Baseline (no resolve): the slot is anomalous, the dependent pending.
        let mut without = OperationSet::new();
        without.accept_all(vec![
            insert_env.clone(),
            cand_a.clone(),
            cand_b.clone(),
            dependent.clone(),
        ]);
        let state = without.reduce();
        assert!(state.anomalies.iter().any(|an| matches!(
            an.kind,
            IntegrityAnomalyKind::OperationSlotEquivocated { operation_id } if operation_id == eq_id
        )));
        let pending: BTreeMap<_, _> = state.pending.iter().copied().collect();
        assert_eq!(
            pending.get(&dependent.id),
            Some(&PendingReason::DependsOnEquivocated { on: eq_id })
        );

        // With a resolve choosing candidate A: the slot reduces as if it had
        // always been Single with A — A contributes at its own canonical
        // position, the dependent unblocks, and no anomaly is recorded.
        let resolve = resolve_equivocation_env(
            OperationId::new(ReplicaId(3), 0),
            40,
            eq_id,
            cand_a.envelope_hash(),
        );
        let all = vec![
            insert_env.clone(),
            cand_a.clone(),
            cand_b.clone(),
            dependent.clone(),
            resolve.clone(),
        ];
        let mut set = OperationSet::new();
        set.accept_all(all.clone());
        let state = set.reduce();
        assert!(
            state.is_clean(),
            "no conflict, anomaly, or pending: {state:?}"
        );
        assert_eq!(effect_of(&state, eq_id), Some(&OperationEffect::Applied));
        assert_eq!(
            effect_of(&state, dependent.id),
            Some(&OperationEffect::Applied)
        );
        assert_eq!(
            effect_of(&state, resolve.id),
            Some(&OperationEffect::Applied)
        );
        // The dependent respell is causally after the promoted candidate, so
        // its spelling (0xCC) is the resolved value — an intentional overwrite.
        assert_eq!(
            state.spellings.get(&pitch),
            Some(&crate::valuegen::spelling(0xCC))
        );
        // Losing candidate B remains only in the diagnostic candidate store.
        assert!(set.candidate(cand_b.envelope_hash()).is_some());

        // Order-independent: a reversed acceptance order reduces to the bytes.
        let mut reversed = OperationSet::new();
        let mut rev = all;
        rev.reverse();
        reversed.accept_all(rev);
        assert_eq!(reversed.reduce().canonical_bytes(), state.canonical_bytes());
    }

    #[test]
    fn later_resolves_reduce_idempotently_or_collide_on_equivocation_resolution() {
        let eq_id = OperationId::new(ReplicaId(9), 0);
        let cand_a = respell_at(eq_id, 10, 0xAA, CausalContext::new());
        let cand_b = respell_at(eq_id, 10, 0xBB, CausalContext::new());

        // Three resolves: the earliest (in canonical order) governs; a later
        // one naming the same candidate is idempotent; a later one naming a
        // differing candidate collides.
        let first = resolve_equivocation_env(
            OperationId::new(ReplicaId(2), 0),
            20,
            eq_id,
            cand_a.envelope_hash(),
        );
        let same = resolve_equivocation_env(
            OperationId::new(ReplicaId(3), 0),
            30,
            eq_id,
            cand_a.envelope_hash(),
        );
        let differing = resolve_equivocation_env(
            OperationId::new(ReplicaId(4), 0),
            40,
            eq_id,
            cand_b.envelope_hash(),
        );

        let mut set = OperationSet::new();
        set.accept_all(vec![
            cand_a.clone(),
            cand_b.clone(),
            first.clone(),
            same.clone(),
            differing.clone(),
        ]);
        let state = set.reduce();

        assert_eq!(effect_of(&state, first.id), Some(&OperationEffect::Applied));
        assert_eq!(
            effect_of(&state, same.id),
            Some(&OperationEffect::NoOp {
                reason: NoOpReason::AlreadyApplied,
            })
        );
        assert!(matches!(
            effect_of(&state, differing.id),
            Some(OperationEffect::Conflicted { .. })
        ));
        assert_eq!(state.conflicts.records().len(), 1);
        let record = &state.conflicts.records()[0];
        assert_eq!(
            record.kind,
            ConflictKind::StructuralFieldCollision {
                winner: first.id,
                loser: differing.id,
                field: FieldPath("equivocation_resolution".to_string()),
            }
        );
        assert_eq!(record.caused_by, vec![first.id, differing.id]);
        assert!(record.affected_objects.is_empty());
        // The slot still promoted A; no anomaly for it.
        assert!(state.anomalies.is_empty());
        assert!(effect_of(&state, eq_id).is_some());
    }

    #[test]
    fn resolve_without_a_matching_equivocation_is_a_precondition_noop() {
        let precondition_noop = OperationEffect::NoOp {
            reason: NoOpReason::PreconditionFailedUnderReduction {
                reason: PreconditionFailureReason::TargetMissing,
            },
        };

        // (a) Target id entirely absent from the operation set.
        let absent = resolve_equivocation_env(
            OperationId::new(ReplicaId(2), 0),
            20,
            OperationId::new(ReplicaId(9), 7),
            crate::EnvelopeHash([1; 32]),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![absent.clone()]);
        let state = set.reduce();
        assert_eq!(effect_of(&state, absent.id), Some(&precondition_noop));

        // (b) Target occupies an ordinary Single slot (no equivocation).
        let single = respell_at(
            OperationId::new(ReplicaId(9), 0),
            10,
            0xAA,
            CausalContext::new(),
        );
        let not_equivocated = resolve_equivocation_env(
            OperationId::new(ReplicaId(2), 0),
            20,
            single.id,
            single.envelope_hash(),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![single.clone(), not_equivocated.clone()]);
        let state = set.reduce();
        assert_eq!(
            effect_of(&state, not_equivocated.id),
            Some(&precondition_noop)
        );

        // (c) Target is equivocated but `chosen` names no candidate: the slot
        // stays equivocated (anomaly recorded, dependents still pending) and
        // the resolve is a precondition no-op — behavior is otherwise exactly
        // the unresolved baseline.
        let eq_id = OperationId::new(ReplicaId(9), 0);
        let cand_a = respell_at(eq_id, 10, 0xAA, CausalContext::new());
        let cand_b = respell_at(eq_id, 10, 0xBB, CausalContext::new());
        let dependent = respell_at(
            OperationId::new(ReplicaId(4), 0),
            30,
            0xCC,
            CausalContext::new().with_seen(ReplicaId(9), 0),
        );
        let bogus = resolve_equivocation_env(
            OperationId::new(ReplicaId(2), 0),
            20,
            eq_id,
            crate::EnvelopeHash([0xEE; 32]),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![
            cand_a.clone(),
            cand_b.clone(),
            dependent.clone(),
            bogus.clone(),
        ]);
        let state = set.reduce();
        assert_eq!(effect_of(&state, bogus.id), Some(&precondition_noop));
        assert!(effect_of(&state, eq_id).is_none());
        assert!(state.anomalies.iter().any(|an| matches!(
            an.kind,
            IntegrityAnomalyKind::OperationSlotEquivocated { operation_id } if operation_id == eq_id
        )));
        let pending: BTreeMap<_, _> = state.pending.iter().copied().collect();
        assert_eq!(
            pending.get(&dependent.id),
            Some(&PendingReason::DependsOnEquivocated { on: eq_id })
        );
    }

    #[test]
    fn an_equivocated_resolve_is_excluded_like_any_equivocated_slot() {
        let eq_id = OperationId::new(ReplicaId(9), 0);
        let cand_a = respell_at(eq_id, 10, 0xAA, CausalContext::new());
        let cand_b = respell_at(eq_id, 10, 0xBB, CausalContext::new());

        // Two distinct resolve envelopes under one id (differing `chosen`):
        // the resolve slot itself equivocates, so it never governs.
        let resolve_id = OperationId::new(ReplicaId(5), 0);
        let resolve_a = resolve_equivocation_env(resolve_id, 20, eq_id, cand_a.envelope_hash());
        let resolve_b = resolve_equivocation_env(resolve_id, 20, eq_id, cand_b.envelope_hash());
        assert_ne!(resolve_a.envelope_hash(), resolve_b.envelope_hash());

        let mut set = OperationSet::new();
        set.accept_all(vec![cand_a, cand_b, resolve_a, resolve_b]);
        let state = set.reduce();

        // Neither slot contributes; both record equivocation anomalies.
        assert!(state.effects.is_empty());
        for id in [eq_id, resolve_id] {
            assert!(
                state.anomalies.iter().any(|an| matches!(
                    an.kind,
                    IntegrityAnomalyKind::OperationSlotEquivocated { operation_id } if operation_id == id
                )),
                "expected an equivocation anomaly for {id:?}"
            );
        }
    }

    // =========================================================================
    // Phase-3 first tranche: CreateStaff, SetTimeSignature, SetTempoSegment,
    // SetStaffLayout, and value-restoring undo (operation_catalog
    // §CreateStaff, §"Meter and Tempo Overwrites", §SetStaffLayout, §undo).
    // =========================================================================

    fn tx_member(
        replica: u64,
        counter: u64,
        physical: i64,
        ctx: CausalContext,
        tx: TransactionId,
        kind: OperationKind,
    ) -> OperationEnvelope {
        let mut env = prim_env(replica, counter, physical, ctx, kind);
        env.transaction = Some(tx);
        env
    }

    fn declare_transaction(
        replica: u64,
        counter: u64,
        physical: i64,
        ctx: CausalContext,
        tx: TransactionId,
    ) -> OperationEnvelope {
        tx_member(
            replica,
            counter,
            physical,
            ctx,
            tx,
            OperationKind::DeclareTransaction(crate::payload::TransactionDescriptor {
                id: tx,
                label: String::from("phase-3 undo scenario"),
                category: None,
            }),
        )
    }

    fn undo_env(
        replica: u64,
        counter: u64,
        physical: i64,
        ctx: CausalContext,
        target: TransactionId,
        policy: UndoPolicy,
    ) -> OperationEnvelope {
        let id = OperationId::new(ReplicaId(replica), counter);
        OperationEnvelope {
            id,
            author: AuthorId(0),
            stamp: OperationStamp::new(HybridLogicalClock::new(WallClockTime(physical), 0), id),
            causal_context: ctx,
            transaction: None,
            payload: OperationPayload::UndoTransaction(UndoTransactionPayload { target, policy }),
        }
    }

    fn seen_r1(counter: u64) -> CausalContext {
        CausalContext::new().with_seen(ReplicaId(1), counter)
    }

    fn respell_kind(pitch: PitchId, nth: u8) -> OperationKind {
        OperationKind::RespellPitch(RespellPitchOp {
            pitch,
            spelling: crate::valuegen::spelling(nth),
        })
    }

    #[test]
    fn create_staff_set_union_mint_discipline() {
        let staff_id = StaffId::new(ReplicaId(9), 7);
        let instrument = InstrumentId::new(ReplicaId(9), 1);
        let value = crate::valuegen::staff(staff_id, instrument);
        let create = prim_env(
            1,
            0,
            10,
            CausalContext::new(),
            OperationKind::CreateStaff(CreateStaffOp {
                staff: value.clone(),
            }),
        );
        let identical = prim_env(
            2,
            0,
            20,
            CausalContext::new(),
            OperationKind::CreateStaff(CreateStaffOp {
                staff: value.clone(),
            }),
        );
        let mut differing_value = value.clone();
        differing_value.name = String::from("something else");
        let differing = prim_env(
            3,
            0,
            30,
            CausalContext::new(),
            OperationKind::CreateStaff(CreateStaffOp {
                staff: differing_value,
            }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![differing.clone(), identical.clone(), create.clone()]);
        let state = set.reduce();

        let effect_of = |id: OperationId| {
            state
                .effects
                .iter()
                .find(|(e, _)| *e == id)
                .map(|(_, eff)| eff)
        };
        assert_eq!(effect_of(create.id), Some(&OperationEffect::Applied));
        assert_eq!(
            effect_of(identical.id),
            Some(&OperationEffect::NoOp {
                reason: NoOpReason::AlreadyApplied,
            }),
            "a byte-identical re-create reduces idempotently"
        );
        assert_eq!(
            effect_of(differing.id),
            Some(&OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::RecreateContentMismatch,
                },
            }),
            "a differing value under a live id is a precondition no-op (P12-K9)"
        );
        assert!(matches!(
            state.objects.get(&TypedObjectId::Staff(staff_id)),
            Some(ObjectState::Live)
        ));
    }

    fn create_region_env(
        replica: u64,
        counter: u64,
        physical: i64,
        region: RegionId,
    ) -> OperationEnvelope {
        prim_env(
            replica,
            counter,
            physical,
            CausalContext::new(),
            OperationKind::CreateRegion(CreateRegionOp {
                region: crate::valuegen::region(region),
            }),
        )
    }

    fn set_meter_kind(
        region: RegionId,
        at: MusicalPosition,
        signature: Option<TimeSignature>,
    ) -> OperationKind {
        OperationKind::SetTimeSignature(SetTimeSignatureOp {
            region,
            anchor: crate::valuegen::region_start_anchor(region, at),
            time_signature: signature,
        })
    }

    #[test]
    fn concurrent_differing_meter_writes_collide_on_meter_sequence() {
        let region = RegionId::new(ReplicaId(9), 3);
        let create = create_region_env(1, 0, 10, region);
        let seen = seen_r1(0);
        let ts_a = crate::valuegen::time_signature(TimeSignatureId::new(ReplicaId(9), 1), 4);
        let ts_b = crate::valuegen::time_signature(TimeSignatureId::new(ReplicaId(9), 2), 3);
        let set_a = prim_env(
            2,
            0,
            20,
            seen.clone(),
            set_meter_kind(region, pos(0), Some(ts_a)),
        );
        let set_b = prim_env(3, 0, 20, seen, set_meter_kind(region, pos(0), Some(ts_b)));
        let mut set = OperationSet::new();
        set.accept_all(vec![set_b.clone(), set_a.clone(), create]);
        let state = set.reduce();

        assert_eq!(state.conflicts.records().len(), 1);
        assert!(matches!(
            &state.conflicts.records()[0].kind,
            ConflictKind::StructuralFieldCollision { field, winner, loser }
                if field.0 == "meter_sequence" && *winner == set_b.id && *loser == set_a.id
        ));
    }

    #[test]
    fn identical_concurrent_meter_writes_reduce_idempotently() {
        let region = RegionId::new(ReplicaId(9), 3);
        let create = create_region_env(1, 0, 10, region);
        let seen = seen_r1(0);
        let ts = crate::valuegen::time_signature(TimeSignatureId::new(ReplicaId(9), 1), 4);
        let set_a = prim_env(
            2,
            0,
            20,
            seen.clone(),
            set_meter_kind(region, pos(0), Some(ts.clone())),
        );
        let set_b = prim_env(3, 0, 20, seen, set_meter_kind(region, pos(0), Some(ts)));
        let mut set = OperationSet::new();
        set.accept_all(vec![set_b.clone(), set_a.clone(), create]);
        let state = set.reduce();

        assert!(state.conflicts.is_empty());
        let effect_of = |id: OperationId| {
            state
                .effects
                .iter()
                .find(|(e, _)| *e == id)
                .map(|(_, eff)| eff)
        };
        assert_eq!(effect_of(set_a.id), Some(&OperationEffect::Applied));
        assert_eq!(
            effect_of(set_b.id),
            Some(&OperationEffect::NoOp {
                reason: NoOpReason::AlreadyApplied,
            })
        );
    }

    #[test]
    fn a_differing_recarry_of_a_live_time_signature_is_refused() {
        let region = RegionId::new(ReplicaId(9), 3);
        let signature_id = TimeSignatureId::new(ReplicaId(9), 1);
        let create = create_region_env(1, 0, 10, region);
        let set_a = prim_env(
            1,
            1,
            20,
            seen_r1(0),
            set_meter_kind(
                region,
                pos(0),
                Some(crate::valuegen::time_signature(signature_id, 4)),
            ),
        );
        // Causally later, same signature id, different value, different key.
        let set_b = prim_env(
            1,
            2,
            30,
            seen_r1(1),
            set_meter_kind(
                region,
                pos(4),
                Some(crate::valuegen::time_signature(signature_id, 3)),
            ),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![create, set_a, set_b.clone()]);
        let state = set.reduce();

        assert_eq!(
            state
                .effects
                .iter()
                .find(|(e, _)| *e == set_b.id)
                .map(|(_, eff)| eff),
            Some(&OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::RecreateContentMismatch,
                },
            }),
            "a differing value under a live signature id is a precondition no-op (P12-K9)"
        );
    }

    #[test]
    fn set_tempo_segment_refuses_writes_that_would_malform_the_map() {
        let region = RegionId::new(ReplicaId(9), 0);
        let anchor_at = |at: i64| crate::valuegen::region_start_anchor(region, pos(at));
        let malformed = |counter: u64, op: SetTempoSegmentOp| {
            prim_env(
                1,
                counter,
                (counter as i64 + 1) * 10,
                if counter == 0 {
                    CausalContext::new()
                } else {
                    seen_r1(counter - 1)
                },
                OperationKind::SetTempoSegment(op),
            )
        };
        // (0) A clean open constant segment at 0 applies (score scope).
        let clean = malformed(
            0,
            SetTempoSegmentOp {
                region: None,
                start: anchor_at(0),
                segment: Some(crate::valuegen::tempo_segment(region, pos(0), 120.0)),
            },
        );
        // (1) Carried segment start disagrees with the operation's key.
        let key_mismatch = malformed(
            1,
            SetTempoSegmentOp {
                region: None,
                start: anchor_at(2),
                segment: Some(crate::valuegen::tempo_segment(region, pos(3), 90.0)),
            },
        );
        // (2) A non-constant shape missing its end data.
        let mut ramp = crate::valuegen::tempo_segment(region, pos(4), 60.0);
        ramp.shape = epiphany_core::TempoShape::Linear;
        let missing_end = malformed(
            2,
            SetTempoSegmentOp {
                region: None,
                start: anchor_at(4),
                segment: Some(ramp),
            },
        );
        // (3) An explicit end overlapping the next segment: a segment at -4
        // whose end (at 2) runs past the existing segment's start at 0.
        let mut overlapping = crate::valuegen::tempo_segment(region, pos(-4), 100.0);
        overlapping.end = Some(anchor_at(2));
        let overlap = malformed(
            3,
            SetTempoSegmentOp {
                region: None,
                start: anchor_at(-4),
                segment: Some(overlapping),
            },
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![
            clean.clone(),
            key_mismatch.clone(),
            missing_end.clone(),
            overlap.clone(),
        ]);
        let state = set.reduce();

        let effect_of = |id: OperationId| {
            state
                .effects
                .iter()
                .find(|(e, _)| *e == id)
                .map(|(_, eff)| eff)
        };
        assert_eq!(effect_of(clean.id), Some(&OperationEffect::Applied));
        let refused = OperationEffect::NoOp {
            reason: NoOpReason::PreconditionFailedUnderReduction {
                reason: PreconditionFailureReason::TempoMapMalformed,
            },
        };
        assert_eq!(effect_of(key_mismatch.id), Some(&refused));
        assert_eq!(effect_of(missing_end.id), Some(&refused));
        assert_eq!(effect_of(overlap.id), Some(&refused));
    }

    /// The base scenario of the value-restoring undo unit tests: an event with
    /// one pitch (r1c0), a pre-transaction respell to `spelling(1)` (r1c1), a
    /// transaction T (declared r1c2) whose member respells to `spelling(2)`
    /// (r1c3).
    fn respell_undo_fixture(tx: TransactionId) -> (PitchId, Vec<OperationEnvelope>) {
        let pitch = PitchId::new(ReplicaId(1), 50);
        let e0 =
            insert_with_pitch_content(1, 0, 10, 1, 100, 0, pitch, &crate::valuegen::pitch_value());
        let pre = prim_env(1, 1, 20, seen_r1(0), respell_kind(pitch, 1));
        let declare = declare_transaction(1, 2, 30, seen_r1(1), tx);
        let member = tx_member(1, 3, 40, seen_r1(2), tx, respell_kind(pitch, 2));
        (pitch, vec![e0, pre, declare, member])
    }

    #[test]
    fn undo_restores_the_chain_predecessor_spelling() {
        let tx = TransactionId::from_raw(21);
        let (pitch, mut envelopes) = respell_undo_fixture(tx);
        envelopes.push(undo_env(
            1,
            4,
            50,
            seen_r1(3),
            tx,
            UndoPolicy::StrictInverse,
        ));
        let mut set = OperationSet::new();
        set.accept_all(envelopes);
        let state = set.reduce();

        assert!(state.conflicts.is_empty());
        assert_eq!(
            state.spellings.get(&pitch),
            Some(&crate::valuegen::spelling(1)),
            "undo must restore the pre-transaction spelling"
        );
        // A pure value restoration (no mints) is a clean `Applied`.
        assert_eq!(effect_at(&state, 4), Some(&OperationEffect::Applied));
    }

    #[test]
    fn undo_removes_a_first_spelling_write() {
        // No pre-transaction respell: the transaction introduced the first
        // spelling, so undo restores absence.
        let tx = TransactionId::from_raw(22);
        let pitch = PitchId::new(ReplicaId(1), 50);
        let e0 =
            insert_with_pitch_content(1, 0, 10, 1, 100, 0, pitch, &crate::valuegen::pitch_value());
        let declare = declare_transaction(1, 1, 20, seen_r1(0), tx);
        let member = tx_member(1, 2, 30, seen_r1(1), tx, respell_kind(pitch, 2));
        let undo = undo_env(1, 3, 40, seen_r1(2), tx, UndoPolicy::StrictInverse);
        let mut set = OperationSet::new();
        set.accept_all(vec![undo, member, declare, e0]);
        let state = set.reduce();

        assert!(state.conflicts.is_empty());
        assert_eq!(state.spellings.get(&pitch), None);
        assert_eq!(effect_at(&state, 3), Some(&OperationEffect::Applied));
    }

    #[test]
    fn superseded_undo_conflicts_strict_and_skips_best_effort() {
        let tx = TransactionId::from_raw(23);
        let (pitch, mut envelopes) = respell_undo_fixture(tx);
        // A causally-later respell supersedes the transaction's write.
        let superseder = prim_env(1, 4, 50, seen_r1(3), respell_kind(pitch, 3));
        let strict = undo_env(1, 5, 60, seen_r1(4), tx, UndoPolicy::StrictInverse);
        let best_effort = undo_env(1, 6, 70, seen_r1(5), tx, UndoPolicy::BestEffort);
        envelopes.extend([superseder.clone(), strict.clone(), best_effort.clone()]);
        let mut set = OperationSet::new();
        set.accept_all(envelopes);
        let state = set.reduce();

        // StrictInverse refuses the whole undo, naming the undo and the
        // superseding writer.
        assert!(matches!(
            effect_at(&state, 5),
            Some(OperationEffect::Conflicted { .. })
        ));
        let record = state
            .conflicts
            .records()
            .iter()
            .find(|record| record.caused_by.contains(&strict.id))
            .expect("the strict undo records a conflict");
        assert!(matches!(
            &record.kind,
            ConflictKind::TransactionConflict { transaction, .. } if *transaction == tx
        ));
        assert!(record.caused_by.contains(&superseder.id));
        // BestEffort skips the superseded key: applied, nothing restored.
        assert_eq!(effect_at(&state, 6), Some(&OperationEffect::Applied));
        assert_eq!(
            state.spellings.get(&pitch),
            Some(&crate::valuegen::spelling(3)),
            "the superseding write stands"
        );
    }

    #[test]
    fn undo_of_undo_restores_the_pre_undo_value() {
        // PINNED (see DECISIONS.md): an undo's restoration enters the write
        // chain as a new write by the undo operation. Undoing the undo's own
        // enclosing transaction therefore restores the value the first undo
        // removed.
        let tx = TransactionId::from_raw(24);
        let (pitch, mut envelopes) = respell_undo_fixture(tx);
        let undo_tx = TransactionId::from_raw(25);
        let declare_undo_tx = declare_transaction(1, 4, 50, seen_r1(3), undo_tx);
        let mut first_undo = undo_env(1, 5, 60, seen_r1(4), tx, UndoPolicy::StrictInverse);
        first_undo.transaction = Some(undo_tx);
        let second_undo = undo_env(1, 6, 70, seen_r1(5), undo_tx, UndoPolicy::StrictInverse);
        envelopes.extend([declare_undo_tx, first_undo, second_undo]);
        let mut set = OperationSet::new();
        set.accept_all(envelopes);
        let state = set.reduce();

        assert!(state.conflicts.is_empty());
        assert_eq!(
            state.spellings.get(&pitch),
            Some(&crate::valuegen::spelling(2)),
            "undoing the undo restores the originally-undone spelling"
        );
    }

    #[test]
    fn a_second_undo_of_the_same_transaction_sees_the_first_as_superseding() {
        // PINNED (see DECISIONS.md): the first undo's restoration is a write,
        // so a repeated strict undo of the same transaction conflicts rather
        // than double-restoring.
        let tx = TransactionId::from_raw(26);
        let (pitch, mut envelopes) = respell_undo_fixture(tx);
        let first = undo_env(1, 4, 50, seen_r1(3), tx, UndoPolicy::StrictInverse);
        let second = undo_env(1, 5, 60, seen_r1(4), tx, UndoPolicy::StrictInverse);
        envelopes.extend([first, second]);
        let mut set = OperationSet::new();
        set.accept_all(envelopes);
        let state = set.reduce();

        assert_eq!(
            state.spellings.get(&pitch),
            Some(&crate::valuegen::spelling(1)),
            "the first undo's restoration stands"
        );
        assert!(matches!(
            effect_at(&state, 5),
            Some(OperationEffect::Conflicted { .. })
        ));
    }

    #[test]
    fn undo_restoration_is_permutation_invariant() {
        // The write chains append in canonical processing order, so the undo's
        // restoration verdict and restored values are pure functions of the
        // operation set: any delivery order reduces to byte-identical state.
        let tx = TransactionId::from_raw(27);
        let (_, mut envelopes) = respell_undo_fixture(tx);
        // Add a meter overwrite + undo flavor alongside the respell flavor.
        let region = RegionId::new(ReplicaId(9), 3);
        envelopes.push(prim_env(
            2,
            0,
            15,
            CausalContext::new(),
            OperationKind::CreateRegion(CreateRegionOp {
                region: crate::valuegen::region(region),
            }),
        ));
        envelopes.push(undo_env(
            1,
            4,
            50,
            seen_r1(3),
            tx,
            UndoPolicy::StrictInverse,
        ));

        let baseline = {
            let mut set = OperationSet::new();
            set.accept_all(envelopes.clone());
            set.reduce().canonical_bytes()
        };
        let mut rng = epiphany_determinism::fuzz::SplitMix64::new(0x9E37_79B9_7F4A_7C15);
        for _ in 0..4 {
            let mut shuffled = envelopes.clone();
            shuffle_envelopes(&mut shuffled, &mut rng);
            let mut set = OperationSet::new();
            set.accept_all(shuffled);
            assert_eq!(
                set.reduce().canonical_bytes(),
                baseline,
                "value-restoring undo must be permutation-invariant"
            );
        }
    }

    // === Genesis tranche G1 (`spec/CONTRACT_GENESIS_G1_INSTRUMENT.md`). =======

    /// The full from-empty spine, one replica-1 operation per even counter
    /// (0, 2, 4, 6, 8, 10) and one minted entity id per odd counter
    /// (1, 3, 5, 7, 9, 11) — `CreateInstrument` (i1's load-bearing chain,
    /// the ruling's acceptance criterion 1): `CreateInstrument` ->
    /// `CreateStaff` -> `CreateRegion` -> `CreateStaffInstance` ->
    /// `CreateVoice` -> `InsertEvent`. Returns the envelopes in canonical
    /// authoring order, plus the ids a caller needs to inspect the result.
    struct GenesisSpine {
        envelopes: Vec<OperationEnvelope>,
        event_id: EventId,
    }

    fn genesis_spine_envelopes() -> GenesisSpine {
        let instrument_id = InstrumentId::new(ReplicaId(1), 1);
        let staff_id = StaffId::new(ReplicaId(1), 3);
        let region_id = RegionId::new(ReplicaId(1), 5);
        let instance_id = StaffInstanceId::new(ReplicaId(1), 7);
        let voice_id = VoiceId::new(ReplicaId(1), 9);
        let event_id = EventId::new(ReplicaId(1), 11);

        let create_instrument = prim_env(
            1,
            0,
            10,
            CausalContext::new(),
            OperationKind::CreateInstrument(CreateInstrumentOp {
                instrument: crate::valuegen::instrument(instrument_id),
            }),
        );
        let create_staff = prim_env(
            1,
            2,
            20,
            CausalContext::new(),
            OperationKind::CreateStaff(CreateStaffOp {
                staff: crate::valuegen::staff(staff_id, instrument_id),
            }),
        );
        let create_region = prim_env(
            1,
            4,
            30,
            CausalContext::new(),
            OperationKind::CreateRegion(CreateRegionOp {
                region: crate::valuegen::region(region_id),
            }),
        );
        let create_instance = prim_env(
            1,
            6,
            40,
            CausalContext::new(),
            OperationKind::CreateStaffInstance(CreateStaffInstanceOp {
                region: region_id,
                instance: crate::valuegen::staff_instance(instance_id, staff_id),
            }),
        );
        let create_voice = prim_env(
            1,
            8,
            50,
            CausalContext::new(),
            OperationKind::CreateVoice(CreateVoiceOp {
                staff_instance: instance_id,
                voice: crate::valuegen::voice(voice_id),
            }),
        );
        let insert_event = prim_env(
            1,
            10,
            60,
            CausalContext::new(),
            OperationKind::InsertEvent(InsertEventOp {
                staff_instance: instance_id,
                event: crate::valuegen::insert_event_value(
                    event_id,
                    voice_id,
                    pos(0),
                    epiphany_core::MusicalDuration::whole(),
                    &[],
                ),
            }),
        );
        GenesisSpine {
            envelopes: vec![
                create_instrument,
                create_staff,
                create_region,
                create_instance,
                create_voice,
                insert_event,
            ],
            event_id,
        }
    }

    /// (i1) The packet's load-bearing test and the ruling's acceptance
    /// criterion 1: a document created empty and given only operations
    /// materializes a note-bearing `Score` — no fixture, no base.
    /// `CreateInstrument` is the single missing link, so this also asserts
    /// every intermediate link `Applied` rather than only the final note, so
    /// a future regression is pinned at its actual source.
    ///
    /// **Mutation** (verified by hand, not left permanently in this test):
    /// drop the `CreateInstrument` envelope from the set. `CreateStaff` then
    /// finds no live instrument and reduces to
    /// `NoOp{PreconditionFailedUnderReduction{TargetMissing}}`, which cascades
    /// (no staff instance, no voice, no event) so the final `contains` check
    /// fails too — see the report for the observed failure text.
    #[test]
    fn from_empty_operations_alone_materialize_a_note() {
        let spine = genesis_spine_envelopes();
        let mut set = OperationSet::new();
        set.accept_all(spine.envelopes);
        let identity = IdentityContext::new(ReplicaId(1));
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        for counter in [0, 2, 4, 6, 8, 10] {
            assert_eq!(
                effect_at(&out.state, counter),
                Some(&OperationEffect::Applied),
                "spine operation at counter {counter} must apply"
            );
        }
        assert!(
            out.score.events.contains(spine.event_id),
            "the spine reaches a note"
        );
    }

    /// (t9) Regression guard: the from-empty spine still reaches a note, now
    /// with a `SetTuningContext` authored alongside it — genesis tranche G2b
    /// does not disturb the spine G1 established.
    ///
    /// **Mutation:** replace this kind's dispatch arm with
    /// `OperationKind::SetTuningContext(_) => OperationEffect::Applied`, which
    /// bypasses tuning reduction without making the match non-exhaustive. The
    /// spine ops stay applied and the note stays reachable; the *authored
    /// tuning-context* assertions fail (the seeded default survives instead of
    /// the authored value).
    ///
    /// This comment previously claimed the mutation was t2's (the
    /// `schema_major` arm). The sweep disproved that: t9 stayed **green**
    /// under it, because the spine reaches a note whatever the block stamps.
    /// A mutation borrowed from another test signs nothing unless it is
    /// observed to kill *this* one.
    #[test]
    fn from_empty_spine_reaches_a_note_with_a_tuning_context_authored() {
        let spine = genesis_spine_envelopes();
        let settings = crate::valuegen::tuning_context_settings(1);
        let set_tuning = prim_env(
            1,
            12,
            70,
            CausalContext::new(),
            OperationKind::SetTuningContext(crate::payload::SetTuningContextOp {
                settings: settings.clone(),
            }),
        );
        let mut envelopes = spine.envelopes;
        envelopes.push(set_tuning);
        let mut set = OperationSet::new();
        set.accept_all(envelopes);
        let identity = IdentityContext::new(ReplicaId(1));
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        for counter in [0, 2, 4, 6, 8, 10, 12] {
            assert_eq!(
                effect_at(&out.state, counter),
                Some(&OperationEffect::Applied),
                "spine operation at counter {counter} must apply"
            );
        }
        assert!(
            out.score.events.contains(spine.event_id),
            "the spine still reaches a note"
        );
        assert_eq!(
            out.score.tuning_context.default_pitch_space,
            settings.default_pitch_space
        );
        assert_eq!(
            out.score.tuning_context.default_tuning_system,
            settings.default_tuning_system
        );
        assert_eq!(out.score.tuning_context.reference, settings.reference);
        assert_eq!(out.score.tuning_context.smufl, settings.smufl);
        assert_eq!(out.score.tuning_context.overrides, settings.overrides);
    }

    /// (i2) Re-carry idempotence: the same `CreateInstrument` twice ->
    /// `AlreadyApplied`, and a differing second carry under the same live id
    /// -> `RecreateContentMismatch` — exactly `create_staff`'s discipline
    /// (contract pin 6).
    ///
    /// **Mutation:** make the second carry differ in one field ->
    /// `RecreateContentMismatch` where the baseline case (identical carries)
    /// reduces `AlreadyApplied`. Both branches are standing assertions here
    /// (not a temporary edit), so the contrast is permanent.
    #[test]
    fn create_instrument_recarry_is_idempotent_or_a_precondition_no_op() {
        let instrument_id = InstrumentId::new(ReplicaId(1), 1);
        let value = crate::valuegen::instrument(instrument_id);
        let create = prim_env(
            1,
            0,
            10,
            CausalContext::new(),
            OperationKind::CreateInstrument(CreateInstrumentOp {
                instrument: value.clone(),
            }),
        );
        let identical = prim_env(
            2,
            0,
            20,
            CausalContext::new(),
            OperationKind::CreateInstrument(CreateInstrumentOp {
                instrument: value.clone(),
            }),
        );
        let mut differing_value = value.clone();
        differing_value.name = String::from("something else");
        let differing = prim_env(
            3,
            0,
            30,
            CausalContext::new(),
            OperationKind::CreateInstrument(CreateInstrumentOp {
                instrument: differing_value,
            }),
        );

        let mut set = OperationSet::new();
        set.accept_all(vec![differing.clone(), identical.clone(), create.clone()]);
        let state = set.reduce();
        let effect_of = |id: OperationId| {
            state
                .effects
                .iter()
                .find(|(e, _)| *e == id)
                .map(|(_, eff)| eff)
        };
        assert_eq!(effect_of(create.id), Some(&OperationEffect::Applied));
        assert_eq!(
            effect_of(identical.id),
            Some(&OperationEffect::NoOp {
                reason: NoOpReason::AlreadyApplied,
            }),
            "a byte-identical re-create reduces idempotently"
        );
        assert_eq!(
            effect_of(differing.id),
            Some(&OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::RecreateContentMismatch,
                },
            }),
            "a differing value under a live id is a precondition no-op"
        );
    }

    /// (i3) Re-carry against a *base* instrument — the pin-8 case.
    /// `TypedObjectId::Instrument` liveness is seeded from the base
    /// (`seed_from_graph`), but without `instrument_values` seeded too, a
    /// byte-identical re-carry against a base instrument has nothing to
    /// compare.
    ///
    /// **Mutation:** skip seeding `instrument_values` in `seed_from_graph` ->
    /// the byte-identical re-carry is misreported
    /// `RecreateContentMismatch` instead of `AlreadyApplied`.
    #[test]
    fn create_instrument_recarry_against_a_base_instrument_is_idempotent() {
        let instrument_id = InstrumentId::new(ReplicaId(1), 1);
        let value = crate::valuegen::instrument(instrument_id);
        let mut base = Score::empty(IdentityContext::new(ReplicaId(1)));
        base.instruments.push(value.clone());

        let recreate = prim_env(
            2,
            0,
            10,
            CausalContext::new(),
            OperationKind::CreateInstrument(CreateInstrumentOp { instrument: value }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![recreate.clone()]);
        let out = reduce_operation_set_onto(&set, &base);

        let effect = out
            .state
            .effects
            .iter()
            .find(|(id, _)| *id == recreate.id)
            .map(|(_, eff)| eff);
        assert_eq!(
            effect,
            Some(&OperationEffect::NoOp {
                reason: NoOpReason::AlreadyApplied,
            }),
            "byte-identical re-carry against a base instrument is idempotent"
        );
        assert_eq!(
            out.score.instruments.len(),
            1,
            "no duplicate instrument is minted"
        );
    }

    /// (i4) Order independence (ruling acceptance criterion 2): two replicas
    /// racing to create the *same* instrument id with differing values (a
    /// concurrent genesis-era scenario) converge to byte-identical
    /// `MaterializedState` regardless of delivery order — canonical order,
    /// never insertion order, decides the winner.
    ///
    /// **Mutation:** perturb one op's reduction order (its stamp) — asserted
    /// permanently below as `assert_ne!`, so the equality above is proven
    /// non-vacuous: a *genuine* reordering really does change the converged
    /// bytes, which is what the primary assertion would have caught had
    /// insertion order actually leaked into the result.
    #[test]
    fn concurrent_differing_creates_of_the_same_instrument_converge_regardless_of_delivery_order() {
        let instrument_id = InstrumentId::new(ReplicaId(9), 1);
        let value_a = crate::valuegen::instrument(instrument_id);
        let mut value_b = value_a.clone();
        value_b.name = String::from("a concurrently-authored name");

        let create_a = prim_env(
            1,
            0,
            10,
            CausalContext::new(),
            OperationKind::CreateInstrument(CreateInstrumentOp {
                instrument: value_a,
            }),
        );
        let create_b = prim_env(
            2,
            0,
            10,
            CausalContext::new(),
            OperationKind::CreateInstrument(CreateInstrumentOp {
                instrument: value_b,
            }),
        );

        let forward = {
            let mut set = OperationSet::new();
            set.accept_all(vec![create_a.clone(), create_b.clone()]);
            set.reduce().canonical_bytes()
        };
        let reversed = {
            let mut set = OperationSet::new();
            set.accept_all(vec![create_b.clone(), create_a.clone()]);
            set.reduce().canonical_bytes()
        };
        assert_eq!(
            forward, reversed,
            "delivery order must not affect the converged state"
        );

        // Proves the equality above is not vacuous: perturbing one op's own
        // reduction-order-determining field (its HLC stamp) so it now sorts
        // *before* its concurrent sibling really does flip the winner and
        // change the converged bytes.
        let perturbed = {
            let mut earlier_b = create_b.clone();
            earlier_b.stamp =
                OperationStamp::new(HybridLogicalClock::new(WallClockTime(5), 0), earlier_b.id);
            let mut set = OperationSet::new();
            set.accept_all(vec![create_a.clone(), earlier_b]);
            set.reduce().canonical_bytes()
        };
        assert_ne!(
            forward, perturbed,
            "a genuine reduction-order change must change the winner"
        );
    }

    /// (i5) The identity cursor (ruling §3 point 3). Minting from a
    /// reduced-from-empty score must not collide with any id the log already
    /// used — `genesis_spine_envelopes` places replica 1's ids at counters
    /// `0..=11` (an operation id at every even counter, a minted entity id at
    /// every odd one), so the derived cursor must be exactly `12`.
    ///
    /// **Mutation:** leave `next_counter` at the seed (`0`) -> the next mint
    /// collides with `create_instrument`'s own `OperationId` counter.
    #[test]
    fn identity_cursor_advances_past_every_id_the_replica_used() {
        let spine = genesis_spine_envelopes();
        let mut set = OperationSet::new();
        set.accept_all(spine.envelopes);
        let identity = IdentityContext::new(ReplicaId(1));
        let mut out = reduce_operation_set_onto(&set, &Score::empty(identity));

        assert_eq!(
            out.score.identity.next_counter, 12,
            "the cursor advances past every id (op or entity) the log used"
        );
        let minted: EventId = out.score.identity.mint();
        assert_eq!(
            minted,
            EventId::new(ReplicaId(1), 12),
            "a fresh mint from the reduced identity collides with nothing in the log"
        );
    }

    /// (i6) Base-free reduction skips a referential precondition that
    /// graph-aware reduction enforces — a **designed asymmetry**, not a bug:
    /// base-free reduction has no instrument universe to check against
    /// (`reduce.rs` — `self.graph.is_some()` guards `create_staff`'s
    /// reference-resolution block). A later reader must not "fix" this by
    /// adding the check to base-free reduction; the fix, if this is ever
    /// wrong, is to stop calling `reduce_operation_set` on a from-empty
    /// document (contract pin 10 / ruling §4).
    #[test]
    fn base_free_reduction_skips_the_referential_precondition_graph_aware_reduction_enforces() {
        let staff_id = StaffId::new(ReplicaId(1), 1);
        let missing_instrument = InstrumentId::new(ReplicaId(1), 99); // never minted
        let create_staff = prim_env(
            1,
            0,
            10,
            CausalContext::new(),
            OperationKind::CreateStaff(CreateStaffOp {
                staff: crate::valuegen::staff(staff_id, missing_instrument),
            }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![create_staff.clone()]);

        let base_free = reduce_operation_set(&set);
        assert_eq!(
            effect_at(&base_free, 0),
            Some(&OperationEffect::Applied),
            "base-free reduction has no instrument universe to check against"
        );

        let identity = IdentityContext::new(ReplicaId(1));
        let onto = reduce_operation_set_onto(&set, &Score::empty(identity));
        assert_eq!(
            effect_at(&onto.state, 0),
            Some(&OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetMissing,
                },
            }),
            "graph-aware reduction enforces the precondition base-free skipped"
        );
    }

    // =========================================================================
    // Genesis tranche G2a (`spec/CONTRACT_GENESIS_G2A_SETTINGS.md`): the two
    // major-0 settings setters, `SetCanvasLayoutDefaults` and
    // `SetSpellingPrecedence`, on the `SetMetadata` LWW pattern.
    // =========================================================================

    /// (s1) From-empty authoring: through `reduce_operation_set_onto`, each
    /// new setter produces its authored value in the materialized `Score`.
    ///
    /// **Mutation:** drop the graph write in the setter fn (`score.canvas.
    /// layout_defaults = op.layout_defaults;` / `score.spelling_precedence =
    /// op.precedence.clone();`) -> the field stays at its `Default` while the
    /// effect still reads `Applied`.
    #[test]
    fn from_empty_settings_setters_materialize_the_authored_value() {
        let identity = IdentityContext::new(ReplicaId(1));
        let layout = crate::valuegen::canvas_layout_defaults(1);
        let precedence = crate::valuegen::spelling_precedence(1);
        let set_layout = prim_env(
            1,
            0,
            10,
            CausalContext::new(),
            OperationKind::SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp {
                layout_defaults: layout,
            }),
        );
        let set_precedence = prim_env(
            1,
            1,
            11,
            seen_r1(0),
            OperationKind::SetSpellingPrecedence(SetSpellingPrecedenceOp {
                precedence: precedence.clone(),
            }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![set_layout.clone(), set_precedence.clone()]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        assert_eq!(
            out.score.canvas.layout_defaults, layout,
            "SetCanvasLayoutDefaults materializes in the graph"
        );
        assert_eq!(
            out.score.spelling_precedence, precedence,
            "SetSpellingPrecedence materializes in the graph"
        );
        assert_eq!(effect_at(&out.state, 0), Some(&OperationEffect::Applied));
        assert_eq!(effect_at(&out.state, 1), Some(&OperationEffect::Applied));
    }

    /// (s2) LWW: two concurrent differing writes (neither sees the other)
    /// resolve to the later in canonical order, recording **no** conflict —
    /// matching `SetMetadata` (`ops/tests/graph_reduction.rs:1408`).
    ///
    /// **Mutation:** *not* a reversed comparison — `set_canvas_layout_
    /// defaults`/`set_spelling_precedence` contain no comparison at all; they
    /// record and overwrite unconditionally. Mutate setter-locally to
    /// first-write-wins instead (skip the record-and-overwrite when the chain
    /// already holds a write) -> the earlier value survives and this test
    /// dies.
    #[test]
    fn concurrent_differing_settings_setters_are_advisory_lww_no_conflict() {
        let identity = IdentityContext::new(ReplicaId(1));
        let layout_a = crate::valuegen::canvas_layout_defaults(1);
        let layout_b = crate::valuegen::canvas_layout_defaults(2);
        assert_ne!(layout_a, layout_b);
        // Neither sees the other: both start from an empty causal context, so
        // they are genuinely concurrent.
        let a = prim_env(
            1,
            0,
            10,
            CausalContext::new(),
            OperationKind::SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp {
                layout_defaults: layout_a,
            }),
        );
        let b = prim_env(
            2,
            0,
            20,
            CausalContext::new(),
            OperationKind::SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp {
                layout_defaults: layout_b,
            }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![a.clone(), b.clone()]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        assert!(
            out.state.conflicts.records().is_empty(),
            "concurrent differing SetCanvasLayoutDefaults is advisory — no conflict"
        );
        assert!(
            out.state.is_clean(),
            "an advisory layout-defaults edit keeps the materialized state clean"
        );
        // `b` has the later physical time, so canonical order places it last;
        // its value must be the one that survives.
        assert_eq!(
            out.score.canvas.layout_defaults, layout_b,
            "the later-in-canonical-order write wins"
        );
    }

    /// (s3) A re-write of an identical value is a **new write**, not a
    /// no-op. This test exists because pin 5 is the most likely thing for a
    /// subagent to get wrong by pattern-matching on `create_staff`'s mint
    /// discipline.
    ///
    /// The contract requires proving **both** halves: that the effect is
    /// `Applied`, *and* that the write chain grew. Asserting effects alone is
    /// insufficient — a mutant that returns `Applied` while skipping
    /// `WriteChain::record` for an unchanged value passes an effects-only
    /// test, and the damage surfaces only later, when undoing the earlier
    /// transaction restores the base instead of reporting that the identical
    /// later write superseded it. So the two writes here sit in **different
    /// transactions**, and a strict undo of the first must report
    /// supersession naming the second.
    ///
    /// **Mutations, both required:** (a) add an `AlreadyApplied`
    /// short-circuit to the setter fn -> the effect half dies; (b) keep
    /// `Applied` but skip `record` when the value is unchanged -> the
    /// supersession half dies while the effect half stays green.
    #[test]
    fn rewriting_an_identical_settings_value_is_a_new_write_not_a_no_op() {
        let identity = IdentityContext::new(ReplicaId(1));
        let precedence = crate::valuegen::spelling_precedence(1);
        let first = prim_env(
            1,
            0,
            10,
            CausalContext::new(),
            OperationKind::SetSpellingPrecedence(SetSpellingPrecedenceOp {
                precedence: precedence.clone(),
            }),
        );
        let second = prim_env(
            1,
            1,
            11,
            seen_r1(0),
            OperationKind::SetSpellingPrecedence(SetSpellingPrecedenceOp {
                precedence: precedence.clone(),
            }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![first.clone(), second.clone()]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity.clone()));

        assert_eq!(
            effect_at(&out.state, 0),
            Some(&OperationEffect::Applied),
            "the first write applies"
        );
        assert_eq!(
            effect_at(&out.state, 1),
            Some(&OperationEffect::Applied),
            "a byte-identical re-write is still a new Applied write, not AlreadyApplied"
        );

        // The chain-growth half. Effects alone cannot see a mutant that
        // returns `Applied` without recording, so put the two identical
        // writes in different transactions and strict-undo the first: the
        // chain must report the identical second write as superseding it.
        let tx_a = TransactionId::from_raw(91);
        let tx_b = TransactionId::from_raw(92);
        let declare_a = declare_transaction(1, 0, 10, CausalContext::new(), tx_a);
        let declare_b = declare_transaction(1, 2, 30, seen_r1(1), tx_b);
        let mut write_a = prim_env(
            1,
            1,
            20,
            seen_r1(0),
            OperationKind::SetSpellingPrecedence(SetSpellingPrecedenceOp {
                precedence: precedence.clone(),
            }),
        );
        write_a.transaction = Some(tx_a);
        let mut write_b = prim_env(
            1,
            3,
            40,
            seen_r1(2),
            OperationKind::SetSpellingPrecedence(SetSpellingPrecedenceOp {
                precedence: precedence.clone(),
            }),
        );
        write_b.transaction = Some(tx_b);
        let strict = undo_env(1, 4, 50, seen_r1(3), tx_a, UndoPolicy::StrictInverse);
        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_a,
            write_a,
            declare_b,
            write_b.clone(),
            strict.clone(),
        ]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        assert!(
            matches!(
                effect_at(&out.state, 4),
                Some(OperationEffect::Conflicted { .. })
            ),
            "the identical later write must supersede tx_a's strict undo — if \
             this passes as Applied, the second write was never recorded"
        );
        let record = out
            .state
            .conflicts
            .records()
            .iter()
            .find(|record| record.caused_by.contains(&strict.id))
            .expect("the strict undo records a conflict");
        assert!(
            record.caused_by.contains(&write_b.id),
            "the supersession must name the identical second write"
        );
    }

    /// (s4) Value-restoring undo reaches the seeded base — run both
    /// from-empty (base = `Default`) and onto a loaded base with a
    /// non-default value, so the test distinguishes "restored the base" from
    /// "restored the type default".
    ///
    /// **Mutation:** remove the `.seed(...)` calls in `seed_from_graph` ->
    /// the undo produces `Restore(None)` and the field does not move (it
    /// stays at the transaction's authored value instead of reverting).
    #[test]
    fn value_restoring_undo_of_settings_setters_reaches_the_seeded_base() {
        // Case A: from-empty. Base = Score::empty, so the seed is the type
        // Default.
        {
            let identity = IdentityContext::new(ReplicaId(1));
            let tx = TransactionId::from_raw(1);
            let authored = crate::valuegen::canvas_layout_defaults(3);
            let envelopes = vec![
                declare_transaction(1, 0, 10, CausalContext::new(), tx),
                tx_member(
                    1,
                    1,
                    11,
                    seen_r1(0),
                    tx,
                    OperationKind::SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp {
                        layout_defaults: authored,
                    }),
                ),
                undo_env(1, 2, 12, seen_r1(1), tx, UndoPolicy::StrictInverse),
            ];
            let mut set = OperationSet::new();
            set.accept_all(envelopes);
            let out = reduce_operation_set_onto(&set, &Score::empty(identity));
            assert_eq!(
                out.score.canvas.layout_defaults,
                CanvasLayoutDefaults::default(),
                "from-empty undo restores the seeded type Default"
            );
        }

        // Case B: onto a loaded base whose value is already non-default —
        // undo must restore *that* value, not the type Default.
        {
            let mut base = Score::empty(IdentityContext::new(ReplicaId(1)));
            let base_value = crate::valuegen::spelling_precedence(1);
            base.spelling_precedence = base_value.clone();
            assert_ne!(base_value, SpellingPrecedence::default());

            let tx = TransactionId::from_raw(2);
            let authored = crate::valuegen::spelling_precedence(2);
            let envelopes = vec![
                declare_transaction(1, 0, 10, CausalContext::new(), tx),
                tx_member(
                    1,
                    1,
                    11,
                    seen_r1(0),
                    tx,
                    OperationKind::SetSpellingPrecedence(SetSpellingPrecedenceOp {
                        precedence: authored,
                    }),
                ),
                undo_env(1, 2, 12, seen_r1(1), tx, UndoPolicy::StrictInverse),
            ];
            let mut set = OperationSet::new();
            set.accept_all(envelopes);
            let out = reduce_operation_set_onto(&set, &base);
            assert_eq!(
                out.score.spelling_precedence, base_value,
                "undo onto a loaded base restores the base's own value, not the type Default"
            );
        }
    }

    // =========================================================================
    // Genesis tranche G2b (`spec/CONTRACT_GENESIS_G2B_TUNING.md`): the sole
    // genesis payload born at schema major 3, `SetTuningContext`.
    // =========================================================================

    /// (t5) **The pin's whole reason for existing** (contract §1): an op
    /// authored **live** and the same op reloaded **from bytes** must
    /// reduce to identical graph states, with a pre-existing non-empty
    /// `accidental_extensions` preserved across both. This is what the
    /// subset type (pin 1) makes structurally impossible to get wrong — a
    /// full-value `SetTuningContext(ScoreTuningContext)` would diverge here,
    /// because `OperationSet::accept` stores the authored envelope as a
    /// **value** (live path keeps whatever `accidental_extensions` the
    /// constructor set) while a decoded envelope always reconstructs it as
    /// empty (the wire drops it).
    ///
    /// **Mutation:** make the payload carry the full `ScoreTuningContext`
    /// instead of the subset `TuningContextSettings`; must fail. Performed
    /// and reversed live for this rung (see the report) rather than left in
    /// the tree, since it requires the type-level change pin 1 forbids.
    #[test]
    fn t5_live_authored_and_reloaded_from_bytes_agree_with_extensions_preserved() {
        use epiphany_core::{AccidentalRegistryId, ScoreAccidentalExtensions};

        // A base graph with a pre-existing, non-empty accidental_extensions —
        // the field the op never carries and reduction must leave untouched.
        let mut base = Score::empty(IdentityContext::new(ReplicaId(1)));
        let pre_existing = vec![ScoreAccidentalExtensions {
            base: AccidentalRegistryId::new("heji"),
            additions: Vec::new(),
            overrides: Vec::new(),
        }];
        base.tuning_context.accidental_extensions = pre_existing.clone();

        let settings = crate::valuegen::tuning_context_settings(3);
        let live_env = prim_env(
            1,
            0,
            10,
            CausalContext::new(),
            OperationKind::SetTuningContext(crate::payload::SetTuningContextOp {
                settings: settings.clone(),
            }),
        );

        // Path A: authored live — the envelope object itself, never touching
        // bytes.
        let mut live_set = OperationSet::new();
        live_set.accept_all(vec![live_env.clone()]);
        let live_out = reduce_operation_set_onto(&live_set, &base);

        // Path B: the identical envelope, round-tripped through canonical
        // bytes and decoded back before reduction.
        let bytes = live_env.to_canonical_bytes();
        let reloaded_env = crate::envdecode::decode_envelope(&bytes).expect("the envelope decodes");
        let mut reloaded_set = OperationSet::new();
        reloaded_set.accept_all(vec![reloaded_env]);
        let reloaded_out = reduce_operation_set_onto(&reloaded_set, &base);

        // The two graph states are identical.
        assert_eq!(
            live_out.score.tuning_context, reloaded_out.score.tuning_context,
            "an op authored live and the same op reloaded from bytes must reduce identically"
        );
        // Both apply the authored five-field settings...
        assert_eq!(
            live_out.score.tuning_context.default_pitch_space,
            settings.default_pitch_space
        );
        assert_eq!(live_out.score.tuning_context.reference, settings.reference);
        // ...and both preserve the base's pre-existing accidental_extensions,
        // untouched — the field the payload cannot carry.
        assert_eq!(
            live_out.score.tuning_context.accidental_extensions, pre_existing,
            "live path: accidental_extensions preserved"
        );
        assert_eq!(
            reloaded_out.score.tuning_context.accidental_extensions, pre_existing,
            "reloaded path: accidental_extensions preserved"
        );
    }

    /// (t6) Undo restores the previous (chain-predecessor) five-field value —
    /// not the seeded base, and not the type default. Two `SetTuningContext`
    /// writes in two separate transactions; undoing the *second* must restore
    /// the *first*'s authored value.
    ///
    /// **Mutation:** in the `TuningContext` restoration-apply arm, restore
    /// the default `TuningContextSettings` instead of the chain predecessor
    /// (or drop the field writes entirely); must fail.
    #[test]
    fn t6_undo_restores_the_chain_predecessor_tuning_settings() {
        let identity = IdentityContext::new(ReplicaId(1));
        let first = crate::valuegen::tuning_context_settings(1);
        let second = crate::valuegen::tuning_context_settings(2);
        assert_ne!(first, second);

        let tx2 = TransactionId::from_raw(2);
        let envelopes = vec![
            prim_env(
                1,
                0,
                10,
                CausalContext::new(),
                OperationKind::SetTuningContext(crate::payload::SetTuningContextOp {
                    settings: first.clone(),
                }),
            ),
            declare_transaction(1, 1, 20, seen_r1(0), tx2),
            tx_member(
                1,
                2,
                21,
                seen_r1(1),
                tx2,
                OperationKind::SetTuningContext(crate::payload::SetTuningContextOp {
                    settings: second,
                }),
            ),
            undo_env(1, 3, 22, seen_r1(2), tx2, UndoPolicy::StrictInverse),
        ];
        let mut set = OperationSet::new();
        set.accept_all(envelopes);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        assert_eq!(
            out.score.tuning_context.default_pitch_space,
            first.default_pitch_space
        );
        assert_eq!(
            out.score.tuning_context.default_tuning_system,
            first.default_tuning_system
        );
        assert_eq!(out.score.tuning_context.reference, first.reference);
        assert_eq!(out.score.tuning_context.smufl, first.smufl);
        assert_eq!(
            out.score.tuning_context.overrides, first.overrides,
            "undo of the second write restores the first write's value"
        );
    }

    /// (t7) Undo of the **first** authoring restores the **seeded base**
    /// settings, identically whether the seed was the type default or a
    /// non-default value — the never-authored / authored-to-default
    /// distinction stays unobservable (contract pin 5, and plan trap 5's
    /// withdrawal). `accidental_extensions` is untouched throughout: it is
    /// not part of the carried subset type, so undo cannot move it, and this
    /// test proves the base's own extensions survive both the write and the
    /// undo unchanged.
    ///
    /// **Mutation:** skip `tuning_context_chain.seed(...)` in
    /// `seed_from_graph` -> the first undo sees `NotWritten` (no predecessor
    /// recorded) instead of `Restore(Base(seeded))`, and the field is left at
    /// the authored value instead of reverting; must fail.
    #[test]
    fn t7_undo_of_first_authoring_restores_the_seeded_base_default_or_not() {
        // Both cases run through the exact same assertion shape below — no
        // branch distinguishes "the seed happened to be the type default"
        // from "the seed was a genuine non-default value". That uniformity is
        // itself the proof the distinction is unobservable, per pin 5's
        // explicit instruction not to write code that tells them apart.
        // A pre-existing, non-empty `accidental_extensions` fixture, built
        // directly (its constructor is `pub(crate)` in `epiphany-core`, so
        // this crate cannot reuse the core fixture helper).
        let default_extensions = || {
            vec![epiphany_core::ScoreAccidentalExtensions {
                base: epiphany_core::AccidentalRegistryId::new("heji"),
                additions: Vec::new(),
                overrides: Vec::new(),
            }]
        };

        for (case, base) in [
            ("case A: from-empty, default seed", {
                let mut b = Score::empty(IdentityContext::new(ReplicaId(1)));
                b.tuning_context.accidental_extensions = default_extensions();
                b
            }),
            ("case B: loaded base, non-default seed", {
                let mut b = Score::empty(IdentityContext::new(ReplicaId(1)));
                let non_default = crate::valuegen::tuning_context_settings(9);
                b.tuning_context.default_pitch_space = non_default.default_pitch_space;
                b.tuning_context.default_tuning_system = non_default.default_tuning_system;
                b.tuning_context.reference = non_default.reference;
                b.tuning_context.smufl = non_default.smufl;
                b.tuning_context.overrides = non_default.overrides;
                b.tuning_context.accidental_extensions = default_extensions();
                b
            }),
        ] {
            let seeded = base.tuning_context.clone();
            let tx = TransactionId::from_raw(3);
            let authored = crate::valuegen::tuning_context_settings(20);
            let envelopes = vec![
                declare_transaction(1, 0, 10, CausalContext::new(), tx),
                tx_member(
                    1,
                    1,
                    11,
                    seen_r1(0),
                    tx,
                    OperationKind::SetTuningContext(crate::payload::SetTuningContextOp {
                        settings: authored,
                    }),
                ),
                undo_env(1, 2, 12, seen_r1(1), tx, UndoPolicy::StrictInverse),
            ];
            let mut set = OperationSet::new();
            set.accept_all(envelopes);
            let out = reduce_operation_set_onto(&set, &base);

            assert_eq!(
                out.score.tuning_context.default_pitch_space, seeded.default_pitch_space,
                "{case}: undo restores the seeded default_pitch_space"
            );
            assert_eq!(
                out.score.tuning_context.default_tuning_system, seeded.default_tuning_system,
                "{case}: undo restores the seeded default_tuning_system"
            );
            assert_eq!(
                out.score.tuning_context.reference, seeded.reference,
                "{case}: undo restores the seeded reference"
            );
            assert_eq!(
                out.score.tuning_context.smufl, seeded.smufl,
                "{case}: undo restores the seeded smufl"
            );
            assert_eq!(
                out.score.tuning_context.overrides, seeded.overrides,
                "{case}: undo restores the seeded overrides"
            );
            assert_eq!(
                out.score.tuning_context.accidental_extensions, seeded.accidental_extensions,
                "{case}: accidental_extensions is untouched throughout — it is not part \
                 of the carried subset type, so undo cannot move it"
            );
        }
    }

    /// (s7) Transaction rollback discards the write — and the assertion must
    /// not be on the field. `WorkingSnapshot` (`:7480`) is the transaction
    /// **rollback** mechanism: snapshot before, restore on failure. But
    /// `restore` reassigns the whole graph independently of every write
    /// chain, so a setter's *field* rolls back whether or not its chain was
    /// snapshotted — an assertion on the field alone cannot see a missing
    /// chain in the snapshot/restore pair.
    ///
    /// Shaped so the stale chain is observable: author inside a **failed**
    /// transaction, then perform a **successful** write in a second
    /// transaction, then **undo that second transaction** and assert it
    /// restores the genuine predecessor — the pre-failure value, not the
    /// rolled-back one.
    ///
    /// **Mutation:** omit `canvas_layout_defaults_chain` /
    /// `spelling_precedence_chain` from the snapshot/restore pair (`:7480`
    /// `snapshot`, `:7518` `restore`) -> the failed transaction's write
    /// survives in the chain and the second undo restores it instead of the
    /// true (pre-failure) predecessor.
    #[test]
    fn transaction_rollback_discards_the_write_from_the_chain_not_just_the_field() {
        let identity = IdentityContext::new(ReplicaId(1));
        let pre_failure = crate::valuegen::canvas_layout_defaults(1);
        let failed_tx_value = crate::valuegen::canvas_layout_defaults(2);
        let second_tx_value = crate::valuegen::canvas_layout_defaults(3);
        assert_ne!(pre_failure, failed_tx_value);
        assert_ne!(pre_failure, second_tx_value);
        assert_ne!(failed_tx_value, second_tx_value);

        let fail_tx = TransactionId::from_raw(10);
        let ok_tx = TransactionId::from_raw(11);

        // 1: a genuine, successful pre-failure write (not itself part of any
        // transaction) — this is the predecessor the final undo must reach.
        let pre = prim_env(
            1,
            0,
            10,
            CausalContext::new(),
            OperationKind::SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp {
                layout_defaults: pre_failure,
            }),
        );
        // 2: a transaction whose only member operation targets a missing
        // staff instance, so the transaction as a whole fails and rolls
        // back — `WorkingSnapshot` restores the graph, but a chain missing
        // from the snapshot/restore pair would leak this write into the
        // chain regardless.
        let missing_instance = StaffInstanceId::new(ReplicaId(1), 99);
        let fail_decl = declare_transaction(1, 1, 11, seen_r1(0), fail_tx);
        let fail_write = tx_member(
            1,
            2,
            12,
            seen_r1(1),
            fail_tx,
            OperationKind::SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp {
                layout_defaults: failed_tx_value,
            }),
        );
        let fail_doomed = tx_member(
            1,
            3,
            13,
            seen_r1(2),
            fail_tx,
            OperationKind::SetStaffLayout(SetStaffLayoutOp {
                staff_instance: missing_instance,
                instrument_override: None,
                staff_lines_override: None,
                visible: true,
            }),
        );
        // 3: a second, successful transaction that writes again.
        let ok_decl = declare_transaction(1, 4, 14, seen_r1(3), ok_tx);
        let ok_write = tx_member(
            1,
            5,
            15,
            seen_r1(4),
            ok_tx,
            OperationKind::SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp {
                layout_defaults: second_tx_value,
            }),
        );
        // 4: undo the second (successful) transaction.
        let undo = undo_env(1, 6, 16, seen_r1(5), ok_tx, UndoPolicy::StrictInverse);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            pre,
            fail_decl,
            fail_write,
            fail_doomed,
            ok_decl,
            ok_write,
            undo,
        ]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        assert_eq!(
            out.score.canvas.layout_defaults, pre_failure,
            "undo of the second transaction must restore the genuine (pre-failure) \
             predecessor, not the rolled-back transaction's write"
        );
    }

    // =========================================================================
    // Genesis tranche G3a (`spec/CONTRACT_GENESIS_G3A_ENTITIES.md`): the four
    // remaining root-level `Score` entity mints.
    // =========================================================================

    fn staff_group_env(
        replica: u64,
        counter: u64,
        physical: i64,
        ctx: CausalContext,
        group: epiphany_core::StaffGroup,
    ) -> OperationEnvelope {
        prim_env(
            replica,
            counter,
            physical,
            ctx,
            OperationKind::CreateStaffGroup(CreateStaffGroupOp { group }),
        )
    }

    fn part_definition_env(
        replica: u64,
        counter: u64,
        physical: i64,
        ctx: CausalContext,
        part: epiphany_core::PartDefinition,
    ) -> OperationEnvelope {
        prim_env(
            replica,
            counter,
            physical,
            ctx,
            OperationKind::CreatePartDefinition(CreatePartDefinitionOp { part }),
        )
    }

    fn analysis_layer_env(
        replica: u64,
        counter: u64,
        physical: i64,
        ctx: CausalContext,
        layer: epiphany_core::AnalysisLayer,
    ) -> OperationEnvelope {
        prim_env(
            replica,
            counter,
            physical,
            ctx,
            OperationKind::CreateAnalysisLayer(CreateAnalysisLayerOp { layer }),
        )
    }

    fn view_env(
        replica: u64,
        counter: u64,
        physical: i64,
        ctx: CausalContext,
        view: epiphany_core::ViewDefinition,
    ) -> OperationEnvelope {
        prim_env(
            replica,
            counter,
            physical,
            ctx,
            OperationKind::CreateView(CreateViewOp { view }),
        )
    }

    /// One representative sample of each G3a kind, in §Scope order.
    fn g3a_sample_kinds() -> [OperationKind; 4] {
        [
            OperationKind::CreateStaffGroup(CreateStaffGroupOp {
                group: crate::valuegen::staff_group(StaffGroupId::new(ReplicaId(1), 1), vec![]),
            }),
            OperationKind::CreatePartDefinition(CreatePartDefinitionOp {
                part: crate::valuegen::part_definition(
                    PartDefinitionId::new(ReplicaId(1), 1),
                    vec![],
                ),
            }),
            OperationKind::CreateAnalysisLayer(CreateAnalysisLayerOp {
                layer: crate::valuegen::analysis_layer(AnalysisLayerId::new(ReplicaId(1), 1)),
            }),
            OperationKind::CreateView(CreateViewOp {
                view: crate::valuegen::view(ViewId::new(ReplicaId(1), 1), vec![]),
            }),
        ]
    }

    /// (t1) Genesis tranche G3a: kinds and tags are 35–38, in **both**
    /// spaces, and the discriminant byte leads each canonical encoding
    /// (contract pin 1).
    ///
    /// **Mutation:** move `OperationKind::CreateStaffGroup`'s discriminant to
    /// 39 (in `discriminant()`); must fail. Then, separately, move
    /// `OperationKindTag::CreateStaffGroup`'s tag to 39 (in the vocabulary
    /// macro); must fail too — the two spaces are asserted independently.
    #[test]
    fn t1_g3a_kinds_and_tags_are_35_to_38_in_both_spaces() {
        use crate::payload::OperationKindTag;
        let kinds = g3a_sample_kinds();
        for (kind, expected_disc, expected_tag) in [
            (&kinds[0], 35u8, OperationKindTag::CreateStaffGroup),
            (&kinds[1], 36, OperationKindTag::CreatePartDefinition),
            (&kinds[2], 37, OperationKindTag::CreateAnalysisLayer),
            (&kinds[3], 38, OperationKindTag::CreateView),
        ] {
            assert_eq!(kind.tag(), expected_tag);
            assert_eq!(kind.tag().discriminant(), expected_disc);
            let mut bytes = Vec::new();
            kind.encode_canonical(&mut bytes);
            assert_eq!(
                bytes[0], expected_disc,
                "the discriminant byte must lead the canonical encoding"
            );
        }
    }

    /// (t2) Genesis tranche G3a: `schema_major()` returns 0 for all four
    /// kinds — the catch-all `_ => 0` arm is correct (pin 2).
    ///
    /// **Mutation:** add the four G3a kinds to the `=> 2` arm; must fail
    /// (pin 2's stated bug).
    #[test]
    fn t2_g3a_schema_major_is_zero_for_all_four() {
        for kind in g3a_sample_kinds() {
            assert_eq!(
                kind.schema_major(),
                0,
                "{:?} must be schema major 0",
                kind.tag()
            );
        }
    }

    /// (t3) A block containing all four G3a kinds stamps schema major 0; the
    /// op-block accept-set is untouched at 3 (no `epiphany-bundle` change of
    /// any kind — verified structurally, since this crate does not depend on
    /// `epiphany-bundle`).
    ///
    /// **Mutation:** make one kind report major 2; must fail.
    #[test]
    fn t3_a_block_with_all_four_g3a_kinds_stamps_major_zero() {
        let kinds = g3a_sample_kinds();
        let major = kinds.iter().map(|k| k.schema_major()).max().unwrap();
        assert_eq!(
            major, 0,
            "a block carrying only the four G3a mints stamps major 0"
        );
    }

    /// (t5) Genesis tranche G3a: re-carrying a live id with a
    /// byte-identical value is `AlreadyApplied`; with a differing value is
    /// `RecreateContentMismatch` — `create_staff`'s discipline, for all four
    /// ops (pin 4).
    ///
    /// **Mutation:** in `create_staff_group`, return `OperationEffect::Applied`
    /// for the differing-value case instead of the `RecreateContentMismatch`
    /// no-op; must fail.
    #[test]
    fn t5_g3a_recarry_discipline_applied_alreadyapplied_or_recreatecontentmismatch() {
        fn effect_of(state: &MaterializedState, id: OperationId) -> Option<OperationEffect> {
            state
                .effects
                .iter()
                .find(|(e, _)| *e == id)
                .map(|(_, eff)| eff.clone())
        }
        let already_applied = Some(OperationEffect::NoOp {
            reason: NoOpReason::AlreadyApplied,
        });
        let mismatch = Some(OperationEffect::NoOp {
            reason: NoOpReason::PreconditionFailedUnderReduction {
                reason: PreconditionFailureReason::RecreateContentMismatch,
            },
        });

        // CreateStaffGroup.
        let group_value = crate::valuegen::staff_group(StaffGroupId::new(ReplicaId(9), 1), vec![]);
        let create = staff_group_env(1, 0, 10, CausalContext::new(), group_value.clone());
        let identical = staff_group_env(2, 0, 20, CausalContext::new(), group_value.clone());
        let mut differing_value = group_value;
        differing_value.name = Some(String::from("something else"));
        let differing = staff_group_env(3, 0, 30, CausalContext::new(), differing_value);
        let mut set = OperationSet::new();
        set.accept_all(vec![differing.clone(), identical.clone(), create.clone()]);
        let state = set.reduce();
        assert_eq!(effect_of(&state, create.id), Some(OperationEffect::Applied));
        assert_eq!(effect_of(&state, identical.id), already_applied);
        assert_eq!(effect_of(&state, differing.id), mismatch);

        // CreatePartDefinition.
        let part_value =
            crate::valuegen::part_definition(PartDefinitionId::new(ReplicaId(9), 1), vec![]);
        let create = part_definition_env(1, 1, 10, CausalContext::new(), part_value.clone());
        let identical = part_definition_env(2, 1, 20, CausalContext::new(), part_value.clone());
        let mut differing_value = part_value;
        differing_value.name = String::from("something else");
        let differing = part_definition_env(3, 1, 30, CausalContext::new(), differing_value);
        let mut set = OperationSet::new();
        set.accept_all(vec![differing.clone(), identical.clone(), create.clone()]);
        let state = set.reduce();
        assert_eq!(effect_of(&state, create.id), Some(OperationEffect::Applied));
        assert_eq!(effect_of(&state, identical.id), already_applied);
        assert_eq!(effect_of(&state, differing.id), mismatch);

        // CreateAnalysisLayer.
        let layer_value = crate::valuegen::analysis_layer(AnalysisLayerId::new(ReplicaId(9), 1));
        let create = analysis_layer_env(1, 2, 10, CausalContext::new(), layer_value.clone());
        let identical = analysis_layer_env(2, 2, 20, CausalContext::new(), layer_value.clone());
        let mut differing_value = layer_value;
        differing_value.name = String::from("something else");
        let differing = analysis_layer_env(3, 2, 30, CausalContext::new(), differing_value);
        let mut set = OperationSet::new();
        set.accept_all(vec![differing.clone(), identical.clone(), create.clone()]);
        let state = set.reduce();
        assert_eq!(effect_of(&state, create.id), Some(OperationEffect::Applied));
        assert_eq!(effect_of(&state, identical.id), already_applied);
        assert_eq!(effect_of(&state, differing.id), mismatch);

        // CreateView.
        let view_value = crate::valuegen::view(ViewId::new(ReplicaId(9), 1), vec![]);
        let create = view_env(1, 3, 10, CausalContext::new(), view_value.clone());
        let identical = view_env(2, 3, 20, CausalContext::new(), view_value.clone());
        let mut differing_value = view_value;
        differing_value.name = String::from("something else");
        let differing = view_env(3, 3, 30, CausalContext::new(), differing_value);
        let mut set = OperationSet::new();
        set.accept_all(vec![differing.clone(), identical.clone(), create.clone()]);
        let state = set.reduce();
        assert_eq!(effect_of(&state, create.id), Some(OperationEffect::Applied));
        assert_eq!(effect_of(&state, identical.id), already_applied);
        assert_eq!(effect_of(&state, differing.id), mismatch);
    }

    /// (t5b, t13 baseline) Re-carry against a *base*-derived entity: reduce
    /// `new_onto` a score whose four G3a vectors are already populated, then
    /// re-carry each byte-identically and get `AlreadyApplied`. A re-carry
    /// test that only ever reduces from empty (t5) cannot see a missing base
    /// seed at all (pin 4a, site 4) — this is why this row is separate from
    /// t5.
    ///
    /// **Mutation (t13, four separate sub-mutations, each run alone):** skip
    /// seeding `staff_group_values` / `part_definition_values` /
    /// `analysis_layer_values` / `view_values` in `seed_from_graph`, one at a
    /// time. Each must make the corresponding assertion below misreport
    /// `RecreateContentMismatch` instead of `AlreadyApplied`.
    #[test]
    fn t5b_base_recarry_is_idempotent_for_all_four_g3a_families() {
        let group = crate::valuegen::staff_group(StaffGroupId::new(ReplicaId(1), 1), vec![]);
        let part = crate::valuegen::part_definition(PartDefinitionId::new(ReplicaId(1), 2), vec![]);
        let layer = crate::valuegen::analysis_layer(AnalysisLayerId::new(ReplicaId(1), 3));
        let view = crate::valuegen::view(ViewId::new(ReplicaId(1), 4), vec![]);

        let mut base = Score::empty(IdentityContext::new(ReplicaId(1)));
        base.staff_groups.push(group.clone());
        base.parts.push(part.clone());
        base.analysis_layers.push(layer.clone());
        base.views.push(view.clone());

        let recreate_group = staff_group_env(2, 0, 10, CausalContext::new(), group);
        let recreate_part = part_definition_env(2, 1, 11, CausalContext::new(), part);
        let recreate_layer = analysis_layer_env(2, 2, 12, CausalContext::new(), layer);
        let recreate_view = view_env(2, 3, 13, CausalContext::new(), view);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            recreate_group.clone(),
            recreate_part.clone(),
            recreate_layer.clone(),
            recreate_view.clone(),
        ]);
        let out = reduce_operation_set_onto(&set, &base);

        let effect_of = |id: OperationId| {
            out.state
                .effects
                .iter()
                .find(|(e, _)| *e == id)
                .map(|(_, eff)| eff.clone())
        };
        let already_applied = Some(OperationEffect::NoOp {
            reason: NoOpReason::AlreadyApplied,
        });
        assert_eq!(
            effect_of(recreate_group.id),
            already_applied,
            "StaffGroup base re-carry must be idempotent (pin 4a site 4)"
        );
        assert_eq!(
            effect_of(recreate_part.id),
            already_applied,
            "PartDefinition base re-carry must be idempotent (pin 4a site 4)"
        );
        assert_eq!(
            effect_of(recreate_layer.id),
            already_applied,
            "AnalysisLayer base re-carry must be idempotent (pin 4a site 4)"
        );
        assert_eq!(
            effect_of(recreate_view.id),
            already_applied,
            "View base re-carry must be idempotent (pin 4a site 4)"
        );

        assert_eq!(out.score.staff_groups.len(), 1, "no duplicate group minted");
        assert_eq!(out.score.parts.len(), 1, "no duplicate part minted");
        assert_eq!(
            out.score.analysis_layers.len(),
            1,
            "no duplicate layer minted"
        );
        assert_eq!(out.score.views.len(), 1, "no duplicate view minted");
    }

    /// (t6) Genesis tranche G3a: all three referential loops refuse under a
    /// graph, each asserted separately: `CreateStaffGroup.members`,
    /// `CreatePartDefinition.staves`, and `CreateView.active_layers` naming a
    /// non-live target are each `TargetMissing`.
    ///
    /// **Mutation (three separate sub-mutations, each run alone):** drop the
    /// members loop from `create_staff_group`; drop the staves loop from
    /// `create_part_definition`; drop the active-layers loop from
    /// `create_view`. Each must fail on its own row.
    #[test]
    fn t6_g3a_referential_loops_refuse_a_dangling_target_under_a_graph() {
        let target_missing = Some(OperationEffect::NoOp {
            reason: NoOpReason::PreconditionFailedUnderReduction {
                reason: PreconditionFailureReason::TargetMissing,
            },
        });

        // CreateStaffGroup.members naming a non-live staff.
        let dangling_staff = StaffId::new(ReplicaId(1), 99);
        let group =
            crate::valuegen::staff_group(StaffGroupId::new(ReplicaId(1), 1), vec![dangling_staff]);
        let group_env = staff_group_env(2, 0, 10, CausalContext::new(), group);
        let mut set = OperationSet::new();
        set.accept_all(vec![group_env.clone()]);
        let out =
            reduce_operation_set_onto(&set, &Score::empty(IdentityContext::new(ReplicaId(2))));
        assert_eq!(
            out.state
                .effects
                .iter()
                .find(|(e, _)| *e == group_env.id)
                .map(|(_, eff)| eff.clone()),
            target_missing,
            "CreateStaffGroup.members naming a non-live staff must refuse TargetMissing"
        );

        // CreatePartDefinition.staves naming a non-live staff.
        let part = crate::valuegen::part_definition(
            PartDefinitionId::new(ReplicaId(1), 1),
            vec![dangling_staff],
        );
        let part_env = part_definition_env(3, 0, 10, CausalContext::new(), part);
        let mut set = OperationSet::new();
        set.accept_all(vec![part_env.clone()]);
        let out =
            reduce_operation_set_onto(&set, &Score::empty(IdentityContext::new(ReplicaId(3))));
        assert_eq!(
            out.state
                .effects
                .iter()
                .find(|(e, _)| *e == part_env.id)
                .map(|(_, eff)| eff.clone()),
            target_missing,
            "CreatePartDefinition.staves naming a non-live staff must refuse TargetMissing"
        );

        // CreateView.active_layers naming a non-live analysis layer.
        let dangling_layer = AnalysisLayerId::new(ReplicaId(1), 99);
        let view = crate::valuegen::view(ViewId::new(ReplicaId(1), 1), vec![dangling_layer]);
        let view_env_ = view_env(4, 0, 10, CausalContext::new(), view);
        let mut set = OperationSet::new();
        set.accept_all(vec![view_env_.clone()]);
        let out =
            reduce_operation_set_onto(&set, &Score::empty(IdentityContext::new(ReplicaId(4))));
        assert_eq!(
            out.state
                .effects
                .iter()
                .find(|(e, _)| *e == view_env_.id)
                .map(|(_, eff)| eff.clone()),
            target_missing,
            "CreateView.active_layers naming a non-live analysis layer must refuse TargetMissing"
        );
    }

    /// (t7) Genesis tranche G3a: those same referential preconditions are
    /// **not** enforced base-free — base-free reduction has no universe to
    /// check against.
    ///
    /// **Mutation:** remove the `if self.graph.is_some()` guard from
    /// `create_staff_group`; must fail — the dangling member now refuses even
    /// base-free.
    #[test]
    fn t7_g3a_referential_preconditions_are_not_enforced_base_free() {
        let dangling_staff = StaffId::new(ReplicaId(1), 99);
        let group =
            crate::valuegen::staff_group(StaffGroupId::new(ReplicaId(1), 1), vec![dangling_staff]);
        let group_env = staff_group_env(2, 0, 10, CausalContext::new(), group);
        let mut set = OperationSet::new();
        set.accept_all(vec![group_env.clone()]);
        let state = set.reduce(); // base-free
        assert_eq!(
            state
                .effects
                .iter()
                .find(|(e, _)| *e == group_env.id)
                .map(|(_, eff)| eff.clone()),
            Some(OperationEffect::Applied),
            "base-free reduction has no staff universe to check the dangling member against"
        );
    }

    /// (t8) From empty, `CreateInstrument` -> `CreateStaffGroup` ->
    /// `CreateStaff` **with `group: Some(...)`** succeeds and reaches a note
    /// — i.e. `CreateStaff`'s group precondition becomes **satisfiable**.
    /// **Claim narrowed per §1.1**: this asserts satisfiability, NOT that a
    /// bidirectionally consistent group is authorable.
    ///
    /// **Mutation:** replace the `CreateStaffGroup` dispatch arm with
    /// `OperationKind::CreateStaffGroup(_) => OperationEffect::Applied`,
    /// keeping the match exhaustive; must fail at the grouped-staff assertion
    /// while the spine stays applied.
    #[test]
    fn t8_create_staff_group_then_create_staff_makes_the_group_precondition_satisfiable() {
        let instrument_id = InstrumentId::new(ReplicaId(1), 1);
        let group_id = StaffGroupId::new(ReplicaId(1), 3);
        let staff_id = StaffId::new(ReplicaId(1), 5);

        let create_instrument = prim_env(
            1,
            0,
            10,
            CausalContext::new(),
            OperationKind::CreateInstrument(CreateInstrumentOp {
                instrument: crate::valuegen::instrument(instrument_id),
            }),
        );
        let create_group = staff_group_env(
            1,
            2,
            20,
            CausalContext::new(),
            crate::valuegen::staff_group(group_id, vec![]),
        );
        let mut staff = crate::valuegen::staff(staff_id, instrument_id);
        staff.group = Some(group_id);
        let create_staff = prim_env(
            1,
            4,
            30,
            CausalContext::new(),
            OperationKind::CreateStaff(CreateStaffOp { staff }),
        );

        let mut set = OperationSet::new();
        set.accept_all(vec![create_instrument, create_group, create_staff]);
        let out =
            reduce_operation_set_onto(&set, &Score::empty(IdentityContext::new(ReplicaId(1))));

        for counter in [0, 2, 4] {
            assert_eq!(
                effect_at(&out.state, counter),
                Some(&OperationEffect::Applied),
                "spine operation at counter {counter} must apply"
            );
        }
        let staff = out
            .score
            .staves
            .iter()
            .find(|s| s.id == staff_id)
            .expect("staff minted");
        assert_eq!(
            staff.group,
            Some(group_id),
            "the staff's group precondition is now satisfiable"
        );
    }

    /// (t8b) Both permitted stale forms (§1.1, disposition B) are pinned:
    /// the **missing** form (`CreateStaffGroup(g, [])` ->
    /// `CreateStaff(s, Some(g))` ⟹ `s.group == Some(g)`, `g.members == []`)
    /// and the **spurious** form (`CreateStaff(s, None)` ->
    /// `CreateStaffGroup(g, [s])` ⟹ `g.members == [s]`, `s.group == None`).
    /// Both asserted to **hold**, as states the ruling permits.
    ///
    /// **Mutation 1 (missing form; mutate `create_staff`, which runs SECOND
    /// in this order):** when `group` is `Some(g)`, append the newly minted
    /// staff to `g.members` (disposition A's maintenance rule); the
    /// missing-form assertion must fail.
    ///
    /// **Mutation 2 (spurious form; mutate `create_staff_group`, which runs
    /// SECOND in this order):** reject or normalize away a non-empty carried
    /// `members`; the spurious-form assertion must fail.
    ///
    /// An earlier draft assigned these the other way round, which is
    /// impossible in both directions: `create_staff_group` runs first in the
    /// missing order and cannot append a staff that does not exist yet, and
    /// `create_staff` runs first in the spurious order and has no later group
    /// to repair.
    #[test]
    fn t8b_both_permitted_stale_forms_hold() {
        let instrument_id = InstrumentId::new(ReplicaId(1), 1);

        // Missing form: CreateStaffGroup(g, []) -> CreateStaff(s, Some(g)).
        let group_id = StaffGroupId::new(ReplicaId(1), 3);
        let staff_id = StaffId::new(ReplicaId(1), 5);
        let create_instrument = prim_env(
            1,
            0,
            10,
            CausalContext::new(),
            OperationKind::CreateInstrument(CreateInstrumentOp {
                instrument: crate::valuegen::instrument(instrument_id),
            }),
        );
        let create_group = staff_group_env(
            1,
            2,
            20,
            CausalContext::new(),
            crate::valuegen::staff_group(group_id, vec![]),
        );
        let mut staff = crate::valuegen::staff(staff_id, instrument_id);
        staff.group = Some(group_id);
        let create_staff = prim_env(
            1,
            4,
            30,
            CausalContext::new(),
            OperationKind::CreateStaff(CreateStaffOp { staff }),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![create_instrument, create_group, create_staff]);
        let out =
            reduce_operation_set_onto(&set, &Score::empty(IdentityContext::new(ReplicaId(1))));
        let staff = out
            .score
            .staves
            .iter()
            .find(|s| s.id == staff_id)
            .expect("staff minted");
        assert_eq!(
            staff.group,
            Some(group_id),
            "missing form: s.group == Some(g)"
        );
        let group = out
            .score
            .staff_groups
            .iter()
            .find(|g| g.id == group_id)
            .expect("group minted");
        assert_eq!(
            group.members,
            Vec::<StaffId>::new(),
            "missing form: g.members stays empty (stored, not maintained)"
        );

        // Spurious form: CreateStaff(s, None) -> CreateStaffGroup(g, [s]).
        let group_id2 = StaffGroupId::new(ReplicaId(2), 3);
        let staff_id2 = StaffId::new(ReplicaId(2), 5);
        let create_instrument2 = prim_env(
            2,
            0,
            10,
            CausalContext::new(),
            OperationKind::CreateInstrument(CreateInstrumentOp {
                instrument: crate::valuegen::instrument(instrument_id),
            }),
        );
        let staff2 = crate::valuegen::staff(staff_id2, instrument_id);
        let create_staff2 = prim_env(
            2,
            2,
            20,
            CausalContext::new(),
            OperationKind::CreateStaff(CreateStaffOp { staff: staff2 }),
        );
        let create_group2 = staff_group_env(
            2,
            4,
            30,
            CausalContext::new(),
            crate::valuegen::staff_group(group_id2, vec![staff_id2]),
        );
        let mut set2 = OperationSet::new();
        set2.accept_all(vec![create_instrument2, create_staff2, create_group2]);
        let out2 =
            reduce_operation_set_onto(&set2, &Score::empty(IdentityContext::new(ReplicaId(2))));
        let group2 = out2
            .score
            .staff_groups
            .iter()
            .find(|g| g.id == group_id2)
            .expect("group minted");
        assert_eq!(
            group2.members,
            vec![staff_id2],
            "spurious form: g.members == [s]"
        );
        let staff2 = out2
            .score
            .staves
            .iter()
            .find(|s| s.id == staff_id2)
            .expect("staff minted");
        assert_eq!(staff2.group, None, "spurious form: s.group == None");
    }

    /// (t9) A score reduced from empty through all four G3a ops **passes
    /// `check_invariants`**, and each skipped reducer check **independently**
    /// makes invariant 10 fire (pin 5). The fixture is constant across all
    /// mutations: it already attempts a dangling reference in each of the
    /// three referential loops, and passes only because the reducer refuses
    /// them.
    ///
    /// **Mutation (three separate sub-mutations, each run alone; mutate
    /// production only):** drop the members loop from `create_staff_group` /
    /// the staves loop from `create_part_definition` / the active-layers loop
    /// from `create_view`. Each must let its dangling reference through and
    /// make invariant 10 fire.
    #[test]
    fn t9_from_empty_through_all_four_g3a_ops_passes_check_invariants() {
        let dangling_staff_a = StaffId::new(ReplicaId(1), 90);
        let dangling_staff_b = StaffId::new(ReplicaId(1), 91);
        let dangling_layer = AnalysisLayerId::new(ReplicaId(1), 92);

        let create_group = staff_group_env(
            1,
            0,
            10,
            CausalContext::new(),
            crate::valuegen::staff_group(
                StaffGroupId::new(ReplicaId(1), 1),
                vec![dangling_staff_a],
            ),
        );
        let create_part = part_definition_env(
            1,
            2,
            20,
            CausalContext::new(),
            crate::valuegen::part_definition(
                PartDefinitionId::new(ReplicaId(1), 2),
                vec![dangling_staff_b],
            ),
        );
        let create_view = view_env(
            1,
            4,
            30,
            CausalContext::new(),
            crate::valuegen::view(ViewId::new(ReplicaId(1), 3), vec![dangling_layer]),
        );
        let create_layer = analysis_layer_env(
            1,
            6,
            40,
            CausalContext::new(),
            crate::valuegen::analysis_layer(AnalysisLayerId::new(ReplicaId(1), 4)),
        );

        let mut set = OperationSet::new();
        set.accept_all(vec![create_group, create_part, create_view, create_layer]);
        let out =
            reduce_operation_set_onto(&set, &Score::empty(IdentityContext::new(ReplicaId(1))));

        // Baseline: the reducer refused all three dangling references, so the
        // reduced score passes invariant 10 (and every other invariant).
        assert!(
            epiphany_core::check_invariants(&out.score).is_empty(),
            "baseline: the reducer's refusals must keep the score invariant-clean: {:?}",
            epiphany_core::check_invariants(&out.score)
        );
        let target_missing = Some(&OperationEffect::NoOp {
            reason: NoOpReason::PreconditionFailedUnderReduction {
                reason: PreconditionFailureReason::TargetMissing,
            },
        });
        assert_eq!(
            effect_at(&out.state, 0),
            target_missing,
            "CreateStaffGroup with a dangling member must refuse"
        );
        assert_eq!(
            effect_at(&out.state, 2),
            target_missing,
            "CreatePartDefinition with a dangling staff must refuse"
        );
        assert_eq!(
            effect_at(&out.state, 4),
            target_missing,
            "CreateView with a dangling active layer must refuse"
        );
        assert_eq!(
            effect_at(&out.state, 6),
            Some(&OperationEffect::Applied),
            "CreateAnalysisLayer has no referential precondition and applies"
        );
    }

    /// (t10) Genesis tranche G3a: all four kinds carry epoch 11, and a block
    /// containing them stamps schema minor 11.
    ///
    /// **Mutation:** assign epoch 10 to one kind (e.g. `CreateStaffGroup`) in
    /// `introduced_minor`; must fail. Run against **both** epoch sites
    /// separately (the vocabulary annotation, and the s1 table in
    /// `payload.rs`) — each must be independently able to fail.
    #[test]
    fn t10_g3a_kinds_carry_epoch_11() {
        let kinds = g3a_sample_kinds();
        for kind in &kinds {
            assert_eq!(kind.introduced_minor(), Some(11), "{:?}", kind.tag());
            assert_eq!(kind.tag().introduced_minor(), Some(11), "{:?}", kind.tag());
        }
        let env = prim_env(1, 1, 1, CausalContext::new(), kinds[0].clone());
        assert_eq!(
            crate::payload::operation_block_introduced_minor(&[env]),
            Some(11),
            "a block containing a G3a kind stamps minor 11"
        );
    }

    // =========================================================================
    // The G3a undo repair (`spec/CONTRACT_GENESIS_G3A_UNDO_REPAIR.md`, Packet
    // A): the five `materialize_graph_tombstones` removal arms (pin A1) and
    // the three `undo_strand_block` inbound-reference guards (pins A2-A6)
    // this packet adds, plus the pin A7 re-create ordering they make correct.
    // =========================================================================

    fn instrument_env(
        replica: u64,
        counter: u64,
        physical: i64,
        ctx: CausalContext,
        instrument: epiphany_core::Instrument,
    ) -> OperationEnvelope {
        prim_env(
            replica,
            counter,
            physical,
            ctx,
            OperationKind::CreateInstrument(CreateInstrumentOp { instrument }),
        )
    }

    fn staff_env(
        replica: u64,
        counter: u64,
        physical: i64,
        ctx: CausalContext,
        staff: epiphany_core::Staff,
    ) -> OperationEnvelope {
        prim_env(
            replica,
            counter,
            physical,
            ctx,
            OperationKind::CreateStaff(CreateStaffOp { staff }),
        )
    }

    // --- u1a-u1e: removal and tombstoning (pin A1). -------------------------

    /// (u1a) Undoing a `StaffGroup` mint removes it from `Score.staff_groups`
    /// and tombstones it in `objects` (pin A1, table row 1).
    ///
    /// **Mutation:** delete the `StaffGroup` arm from
    /// `materialize_graph_tombstones` (pin A1's table). Assertion (i) must
    /// fail — the value stays in `Score.staff_groups`.
    #[test]
    fn u1a_undo_of_a_staff_group_mint_removes_it_and_tombstones() {
        let identity = IdentityContext::new(ReplicaId(1));
        let group_id = StaffGroupId::new(ReplicaId(1), 1);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::CreateStaffGroup(CreateStaffGroupOp {
                    group: crate::valuegen::staff_group(group_id, vec![]),
                }),
            ),
            undo_env(1, 2, 12, seen_r1(1), tx, UndoPolicy::StrictInverse),
        ]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        assert!(
            !out.score.staff_groups.iter().any(|g| g.id == group_id),
            "(i) undo must remove the minted StaffGroup from Score.staff_groups"
        );
        assert!(
            matches!(
                out.state.objects.get(&TypedObjectId::StaffGroup(group_id)),
                Some(ObjectState::Tombstoned { .. })
            ),
            "(ii) undo must tombstone the minted StaffGroup in objects"
        );
    }

    /// (u1b) Undoing a `PartDefinition` mint removes it from `Score.parts`
    /// and tombstones it in `objects` (pin A1, table row 2).
    ///
    /// **Mutation:** delete the `PartDefinition` arm from
    /// `materialize_graph_tombstones`. Assertion (i) must fail.
    #[test]
    fn u1b_undo_of_a_part_definition_mint_removes_it_and_tombstones() {
        let identity = IdentityContext::new(ReplicaId(1));
        let part_id = PartDefinitionId::new(ReplicaId(1), 1);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::CreatePartDefinition(CreatePartDefinitionOp {
                    part: crate::valuegen::part_definition(part_id, vec![]),
                }),
            ),
            undo_env(1, 2, 12, seen_r1(1), tx, UndoPolicy::StrictInverse),
        ]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        assert!(
            !out.score.parts.iter().any(|p| p.id == part_id),
            "(i) undo must remove the minted PartDefinition from Score.parts"
        );
        assert!(
            matches!(
                out.state
                    .objects
                    .get(&TypedObjectId::PartDefinition(part_id)),
                Some(ObjectState::Tombstoned { .. })
            ),
            "(ii) undo must tombstone the minted PartDefinition in objects"
        );
    }

    /// (u1c) Undoing an `AnalysisLayer` mint removes it from
    /// `Score.analysis_layers` and tombstones it in `objects` (pin A1, table
    /// row 3).
    ///
    /// **Mutation:** delete the `AnalysisLayer` arm from
    /// `materialize_graph_tombstones`. Assertion (i) must fail.
    #[test]
    fn u1c_undo_of_an_analysis_layer_mint_removes_it_and_tombstones() {
        let identity = IdentityContext::new(ReplicaId(1));
        let layer_id = AnalysisLayerId::new(ReplicaId(1), 1);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::CreateAnalysisLayer(CreateAnalysisLayerOp {
                    layer: crate::valuegen::analysis_layer(layer_id),
                }),
            ),
            undo_env(1, 2, 12, seen_r1(1), tx, UndoPolicy::StrictInverse),
        ]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        assert!(
            !out.score.analysis_layers.iter().any(|l| l.id == layer_id),
            "(i) undo must remove the minted AnalysisLayer from Score.analysis_layers"
        );
        assert!(
            matches!(
                out.state
                    .objects
                    .get(&TypedObjectId::AnalysisLayer(layer_id)),
                Some(ObjectState::Tombstoned { .. })
            ),
            "(ii) undo must tombstone the minted AnalysisLayer in objects"
        );
    }

    /// (u1d) Undoing a `View` mint removes it from `Score.views` and
    /// tombstones it in `objects` (pin A1, table row 4).
    ///
    /// **Mutation:** delete the `View` arm from
    /// `materialize_graph_tombstones`. Assertion (i) must fail.
    #[test]
    fn u1d_undo_of_a_view_mint_removes_it_and_tombstones() {
        let identity = IdentityContext::new(ReplicaId(1));
        let view_id = ViewId::new(ReplicaId(1), 1);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::CreateView(CreateViewOp {
                    view: crate::valuegen::view(view_id, vec![]),
                }),
            ),
            undo_env(1, 2, 12, seen_r1(1), tx, UndoPolicy::StrictInverse),
        ]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        assert!(
            !out.score.views.iter().any(|v| v.id == view_id),
            "(i) undo must remove the minted View from Score.views"
        );
        assert!(
            matches!(
                out.state.objects.get(&TypedObjectId::View(view_id)),
                Some(ObjectState::Tombstoned { .. })
            ),
            "(ii) undo must tombstone the minted View in objects"
        );
    }

    /// (u1e) Undoing an `Instrument` mint removes it from `Score.instruments`
    /// and tombstones it in `objects` (pin A1, table row 5; pin A8 —
    /// `Instrument` is in scope as collateral).
    ///
    /// **Mutation:** delete the `Instrument` arm from
    /// `materialize_graph_tombstones`. Assertion (i) must fail.
    #[test]
    fn u1e_undo_of_an_instrument_mint_removes_it_and_tombstones() {
        let identity = IdentityContext::new(ReplicaId(1));
        let instrument_id = InstrumentId::new(ReplicaId(1), 1);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::CreateInstrument(CreateInstrumentOp {
                    instrument: crate::valuegen::instrument(instrument_id),
                }),
            ),
            undo_env(1, 2, 12, seen_r1(1), tx, UndoPolicy::StrictInverse),
        ]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        assert!(
            !out.score.instruments.iter().any(|i| i.id == instrument_id),
            "(i) undo must remove the minted Instrument from Score.instruments"
        );
        assert!(
            matches!(
                out.state
                    .objects
                    .get(&TypedObjectId::Instrument(instrument_id)),
                Some(ObjectState::Tombstoned { .. })
            ),
            "(ii) undo must tombstone the minted Instrument in objects"
        );
    }

    // --- u2a-u2c: a live outside referencer blocks the undo (pin A2). -------

    /// (u2a) A live `Staff` naming a minted `StaffGroup` blocks the group's
    /// strict undo, and the group survives (pin A2, table row 1).
    ///
    /// **Mutation:** delete the `StaffGroup` arm from `undo_strand_block`
    /// (pin A2's table). The effect becomes `Applied` and the reference
    /// strands.
    #[test]
    fn u2a_a_live_staff_naming_the_group_blocks_its_undo() {
        let identity = IdentityContext::new(ReplicaId(1));
        let instrument_id = InstrumentId::new(ReplicaId(9), 1);
        let mut base = Score::empty(identity);
        base.instruments
            .push(crate::valuegen::instrument(instrument_id));

        let group_id = StaffGroupId::new(ReplicaId(1), 1);
        let staff_id = StaffId::new(ReplicaId(2), 1);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut staff_value = crate::valuegen::staff(staff_id, instrument_id);
        staff_value.group = Some(group_id);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::CreateStaffGroup(CreateStaffGroupOp {
                    group: crate::valuegen::staff_group(group_id, vec![]),
                }),
            ),
            staff_env(2, 0, 20, CausalContext::new(), staff_value),
            undo_env(1, 2, 30, seen_r1(1), tx, UndoPolicy::StrictInverse),
        ]);
        let out = reduce_operation_set_onto(&set, &base);

        assert!(
            matches!(
                effect_at(&out.state, 2),
                Some(OperationEffect::Conflicted { .. })
            ),
            "a live staff naming the group must block strict undo"
        );
        assert!(
            out.score.staff_groups.iter().any(|g| g.id == group_id),
            "the group must remain since undo was blocked"
        );
    }

    /// (u2b) A live `ViewDefinition` naming a minted `AnalysisLayer` blocks
    /// the layer's strict undo, and the layer survives (pin A2, table row
    /// 2).
    ///
    /// **Mutation:** delete the `AnalysisLayer` arm from `undo_strand_block`.
    /// The effect becomes `Applied` and the reference strands.
    #[test]
    fn u2b_a_live_view_naming_the_layer_blocks_its_undo() {
        let identity = IdentityContext::new(ReplicaId(1));
        let layer_id = AnalysisLayerId::new(ReplicaId(1), 1);
        let view_id = ViewId::new(ReplicaId(2), 1);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::CreateAnalysisLayer(CreateAnalysisLayerOp {
                    layer: crate::valuegen::analysis_layer(layer_id),
                }),
            ),
            view_env(
                2,
                0,
                20,
                CausalContext::new(),
                crate::valuegen::view(view_id, vec![layer_id]),
            ),
            undo_env(1, 2, 30, seen_r1(1), tx, UndoPolicy::StrictInverse),
        ]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        assert!(
            matches!(
                effect_at(&out.state, 2),
                Some(OperationEffect::Conflicted { .. })
            ),
            "a live view naming the layer must block strict undo"
        );
        assert!(
            out.score.analysis_layers.iter().any(|l| l.id == layer_id),
            "the layer must remain since undo was blocked"
        );
    }

    /// (u2c) A live `Staff` naming a minted `Instrument` blocks the
    /// instrument's strict undo, and the instrument survives (pin A2, table
    /// row 3).
    ///
    /// **Mutation:** delete the `Instrument` arm from `undo_strand_block`.
    /// The effect becomes `Applied` and the reference strands.
    #[test]
    fn u2c_a_live_staff_naming_the_instrument_blocks_its_undo() {
        let identity = IdentityContext::new(ReplicaId(1));
        let instrument_id = InstrumentId::new(ReplicaId(1), 1);
        let staff_id = StaffId::new(ReplicaId(2), 1);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::CreateInstrument(CreateInstrumentOp {
                    instrument: crate::valuegen::instrument(instrument_id),
                }),
            ),
            staff_env(
                2,
                0,
                20,
                CausalContext::new(),
                crate::valuegen::staff(staff_id, instrument_id),
            ),
            undo_env(1, 2, 30, seen_r1(1), tx, UndoPolicy::StrictInverse),
        ]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        assert!(
            matches!(
                effect_at(&out.state, 2),
                Some(OperationEffect::Conflicted { .. })
            ),
            "a live staff naming the instrument must block strict undo"
        );
        assert!(
            out.score.instruments.iter().any(|i| i.id == instrument_id),
            "the instrument must remain since undo was blocked"
        );
    }

    // --- u2bf-a-u2bf-c: the guards hold base-free (signs pin A3). -----------

    /// (u2bf-a) The `StaffGroup` guard holds under `reduce_operation_set`
    /// (no base `Score`): base-free reduction skips `create_staff`'s
    /// referential preconditions entirely, so the referencing staff mints
    /// unconditionally and the ledger alone must refuse the group's undo.
    ///
    /// **Mutation:** wrap the `StaffGroup` guard arm in
    /// `if self.graph.is_some() { .. } else { None }`. This row must go red
    /// while u2a stays green — run both in the same pass and record both
    /// observations.
    #[test]
    fn u2bf_a_the_staff_group_guard_holds_base_free() {
        // Never minted; base-free reduction has no universe to check it
        // against, so `create_staff` never looks.
        let instrument_id = InstrumentId::new(ReplicaId(9), 1);
        let group_id = StaffGroupId::new(ReplicaId(1), 1);
        let staff_id = StaffId::new(ReplicaId(2), 1);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut staff_value = crate::valuegen::staff(staff_id, instrument_id);
        staff_value.group = Some(group_id);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::CreateStaffGroup(CreateStaffGroupOp {
                    group: crate::valuegen::staff_group(group_id, vec![]),
                }),
            ),
            staff_env(2, 0, 20, CausalContext::new(), staff_value),
            undo_env(1, 2, 30, seen_r1(1), tx, UndoPolicy::StrictInverse),
        ]);
        let state = reduce_operation_set(&set);

        assert!(
            matches!(
                effect_at(&state, 2),
                Some(OperationEffect::Conflicted { .. })
            ),
            "pin A3: the StaffGroup guard must hold base-free — the ledger alone \
             knows the reference, with no graph to check against"
        );
    }

    /// (u2bf-b) The `AnalysisLayer` guard holds base-free.
    ///
    /// **Mutation:** wrap the `AnalysisLayer` guard arm in
    /// `if self.graph.is_some() { .. } else { None }`. This row must go red
    /// while u2b stays green — run both in the same pass.
    #[test]
    fn u2bf_b_the_analysis_layer_guard_holds_base_free() {
        let layer_id = AnalysisLayerId::new(ReplicaId(1), 1);
        let view_id = ViewId::new(ReplicaId(2), 1);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::CreateAnalysisLayer(CreateAnalysisLayerOp {
                    layer: crate::valuegen::analysis_layer(layer_id),
                }),
            ),
            view_env(
                2,
                0,
                20,
                CausalContext::new(),
                crate::valuegen::view(view_id, vec![layer_id]),
            ),
            undo_env(1, 2, 30, seen_r1(1), tx, UndoPolicy::StrictInverse),
        ]);
        let state = reduce_operation_set(&set);

        assert!(
            matches!(
                effect_at(&state, 2),
                Some(OperationEffect::Conflicted { .. })
            ),
            "pin A3: the AnalysisLayer guard must hold base-free — the ledger alone \
             knows the reference, with no graph to check against"
        );
    }

    /// (u2bf-c) The `Instrument` guard holds base-free.
    ///
    /// **Mutation:** wrap the `Instrument` guard arm in
    /// `if self.graph.is_some() { .. } else { None }`. This row must go red
    /// while u2c stays green — run both in the same pass.
    #[test]
    fn u2bf_c_the_instrument_guard_holds_base_free() {
        let instrument_id = InstrumentId::new(ReplicaId(1), 1);
        let staff_id = StaffId::new(ReplicaId(2), 1);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::CreateInstrument(CreateInstrumentOp {
                    instrument: crate::valuegen::instrument(instrument_id),
                }),
            ),
            staff_env(
                2,
                0,
                20,
                CausalContext::new(),
                crate::valuegen::staff(staff_id, instrument_id),
            ),
            undo_env(1, 2, 30, seen_r1(1), tx, UndoPolicy::StrictInverse),
        ]);
        let state = reduce_operation_set(&set);

        assert!(
            matches!(
                effect_at(&state, 2),
                Some(OperationEffect::Conflicted { .. })
            ),
            "pin A3: the Instrument guard must hold base-free — the ledger alone \
             knows the reference, with no graph to check against"
        );
    }

    // --- u2tomb-a-u2tomb-c: a tombstoned referencer does not block (signs
    // pin A4). -----------------------------------------------------------

    /// (u2tomb-a) T1 mints `StaffGroup g`; T2 mints a `Staff s` naming it.
    /// Undoing T2 first tombstones `s` (its value stays in `staff_values`,
    /// pin A7); undoing T1 next must then proceed, since a tombstoned
    /// referencer does not block (pin A4).
    ///
    /// **Mutation:** delete the
    /// `matches!(self.objects.get(&sobj), Some(ObjectState::Live))` conjunct
    /// from the `StaffGroup` guard arm. The dead referencer blocks; T1's
    /// undo becomes `Conflicted`.
    #[test]
    fn u2tomb_a_a_tombstoned_referencing_staff_does_not_block_the_groups_undo() {
        let identity = IdentityContext::new(ReplicaId(1));
        let instrument_id = InstrumentId::new(ReplicaId(9), 1);
        let mut base = Score::empty(identity);
        base.instruments
            .push(crate::valuegen::instrument(instrument_id));

        let group_id = StaffGroupId::new(ReplicaId(1), 1);
        let staff_id = StaffId::new(ReplicaId(1), 2);
        let tx1 = TransactionId::new(ReplicaId(1), 900);
        let tx2 = TransactionId::new(ReplicaId(1), 901);

        let mut staff_value = crate::valuegen::staff(staff_id, instrument_id);
        staff_value.group = Some(group_id);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx1),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx1,
                OperationKind::CreateStaffGroup(CreateStaffGroupOp {
                    group: crate::valuegen::staff_group(group_id, vec![]),
                }),
            ),
            declare_transaction(1, 2, 20, seen_r1(1), tx2),
            tx_member(
                1,
                3,
                21,
                seen_r1(2),
                tx2,
                OperationKind::CreateStaff(CreateStaffOp { staff: staff_value }),
            ),
            undo_env(1, 4, 30, seen_r1(3), tx2, UndoPolicy::StrictInverse),
            undo_env(1, 5, 40, seen_r1(4), tx1, UndoPolicy::StrictInverse),
        ]);
        let out = reduce_operation_set_onto(&set, &base);

        assert!(
            matches!(
                out.state.objects.get(&TypedObjectId::Staff(staff_id)),
                Some(ObjectState::Tombstoned { .. })
            ),
            "T2's undo must tombstone the referencing staff"
        );
        assert!(
            !out.score.staves.iter().any(|s| s.id == staff_id),
            "the tombstoned staff leaves Score.staves"
        );
        assert!(
            matches!(
                effect_at(&out.state, 5),
                Some(OperationEffect::Applied) | Some(OperationEffect::AppliedWithRepair { .. })
            ),
            "with the referencer already tombstoned, T1's undo must proceed"
        );
        assert!(
            !out.score.staff_groups.iter().any(|g| g.id == group_id),
            "the group leaves Score.staff_groups once T1's undo proceeds"
        );
    }

    /// (u2tomb-b) T1 mints `AnalysisLayer l`; T2 mints a `ViewDefinition v`
    /// naming it. Undoing T2 first tombstones `v`; undoing T1 next must then
    /// proceed.
    ///
    /// **Mutation:** delete the liveness conjunct from the `AnalysisLayer`
    /// guard arm. T1's undo becomes `Conflicted`.
    #[test]
    fn u2tomb_b_a_tombstoned_referencing_view_does_not_block_the_layers_undo() {
        let identity = IdentityContext::new(ReplicaId(1));
        let layer_id = AnalysisLayerId::new(ReplicaId(1), 1);
        let view_id = ViewId::new(ReplicaId(1), 2);
        let tx1 = TransactionId::new(ReplicaId(1), 900);
        let tx2 = TransactionId::new(ReplicaId(1), 901);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx1),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx1,
                OperationKind::CreateAnalysisLayer(CreateAnalysisLayerOp {
                    layer: crate::valuegen::analysis_layer(layer_id),
                }),
            ),
            declare_transaction(1, 2, 20, seen_r1(1), tx2),
            tx_member(
                1,
                3,
                21,
                seen_r1(2),
                tx2,
                OperationKind::CreateView(CreateViewOp {
                    view: crate::valuegen::view(view_id, vec![layer_id]),
                }),
            ),
            undo_env(1, 4, 30, seen_r1(3), tx2, UndoPolicy::StrictInverse),
            undo_env(1, 5, 40, seen_r1(4), tx1, UndoPolicy::StrictInverse),
        ]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        assert!(
            matches!(
                out.state.objects.get(&TypedObjectId::View(view_id)),
                Some(ObjectState::Tombstoned { .. })
            ),
            "T2's undo must tombstone the referencing view"
        );
        assert!(
            !out.score.views.iter().any(|v| v.id == view_id),
            "the tombstoned view leaves Score.views"
        );
        assert!(
            matches!(
                effect_at(&out.state, 5),
                Some(OperationEffect::Applied) | Some(OperationEffect::AppliedWithRepair { .. })
            ),
            "with the referencer already tombstoned, T1's undo must proceed"
        );
        assert!(
            !out.score.analysis_layers.iter().any(|l| l.id == layer_id),
            "the layer leaves Score.analysis_layers once T1's undo proceeds"
        );
    }

    /// (u2tomb-c) T1 mints `Instrument i`; T2 mints a `Staff s` naming it.
    /// Undoing T2 first tombstones `s`; undoing T1 next must then proceed.
    ///
    /// **Mutation:** delete the liveness conjunct from the `Instrument`
    /// guard arm. T1's undo becomes `Conflicted`.
    #[test]
    fn u2tomb_c_a_tombstoned_referencing_staff_does_not_block_the_instruments_undo() {
        let identity = IdentityContext::new(ReplicaId(1));
        let instrument_id = InstrumentId::new(ReplicaId(1), 1);
        let staff_id = StaffId::new(ReplicaId(1), 2);
        let tx1 = TransactionId::new(ReplicaId(1), 900);
        let tx2 = TransactionId::new(ReplicaId(1), 901);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx1),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx1,
                OperationKind::CreateInstrument(CreateInstrumentOp {
                    instrument: crate::valuegen::instrument(instrument_id),
                }),
            ),
            declare_transaction(1, 2, 20, seen_r1(1), tx2),
            tx_member(
                1,
                3,
                21,
                seen_r1(2),
                tx2,
                OperationKind::CreateStaff(CreateStaffOp {
                    staff: crate::valuegen::staff(staff_id, instrument_id),
                }),
            ),
            undo_env(1, 4, 30, seen_r1(3), tx2, UndoPolicy::StrictInverse),
            undo_env(1, 5, 40, seen_r1(4), tx1, UndoPolicy::StrictInverse),
        ]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        assert!(
            matches!(
                out.state.objects.get(&TypedObjectId::Staff(staff_id)),
                Some(ObjectState::Tombstoned { .. })
            ),
            "T2's undo must tombstone the referencing staff"
        );
        assert!(
            !out.score.staves.iter().any(|s| s.id == staff_id),
            "the tombstoned staff leaves Score.staves"
        );
        assert!(
            matches!(
                effect_at(&out.state, 5),
                Some(OperationEffect::Applied) | Some(OperationEffect::AppliedWithRepair { .. })
            ),
            "with the referencer already tombstoned, T1's undo must proceed"
        );
        assert!(
            !out.score.instruments.iter().any(|i| i.id == instrument_id),
            "the instrument leaves Score.instruments once T1's undo proceeds"
        );
    }

    // --- u3a-u3c: same-transaction teardown is allowed (signs pin A5). -----

    /// (u3a) Minting `StaffGroup g` and a `Staff s` naming it inside the
    /// *same* transaction undoes whole — the same-transaction exemption
    /// (pin A5).
    ///
    /// **Mutation:** drop the `!targets.contains(&sobj)` conjunct from the
    /// `StaffGroup` guard arm. The undo becomes `Conflicted`.
    #[test]
    fn u3a_minting_the_group_and_its_referencing_staff_in_one_transaction_undoes_whole() {
        let identity = IdentityContext::new(ReplicaId(1));
        let instrument_id = InstrumentId::new(ReplicaId(9), 1);
        let mut base = Score::empty(identity);
        base.instruments
            .push(crate::valuegen::instrument(instrument_id));

        let group_id = StaffGroupId::new(ReplicaId(1), 1);
        let staff_id = StaffId::new(ReplicaId(1), 2);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut staff_value = crate::valuegen::staff(staff_id, instrument_id);
        staff_value.group = Some(group_id);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::CreateStaffGroup(CreateStaffGroupOp {
                    group: crate::valuegen::staff_group(group_id, vec![]),
                }),
            ),
            tx_member(
                1,
                2,
                12,
                seen_r1(1),
                tx,
                OperationKind::CreateStaff(CreateStaffOp { staff: staff_value }),
            ),
            undo_env(1, 3, 20, seen_r1(2), tx, UndoPolicy::StrictInverse),
        ]);
        let out = reduce_operation_set_onto(&set, &base);

        assert!(
            matches!(
                effect_at(&out.state, 3),
                Some(OperationEffect::Applied) | Some(OperationEffect::AppliedWithRepair { .. })
            ),
            "a transaction that mints both the group and its referencing staff must undo whole"
        );
        assert!(
            !out.score.staff_groups.iter().any(|g| g.id == group_id),
            "the group leaves Score.staff_groups"
        );
        assert!(
            !out.score.staves.iter().any(|s| s.id == staff_id),
            "the staff leaves Score.staves"
        );
    }

    /// (u3b) Minting `AnalysisLayer l` and a `ViewDefinition v` naming it
    /// inside the same transaction undoes whole.
    ///
    /// **Mutation:** drop the `!targets.contains(&vobj)` conjunct from the
    /// `AnalysisLayer` guard arm. The undo becomes `Conflicted`.
    #[test]
    fn u3b_minting_the_layer_and_its_referencing_view_in_one_transaction_undoes_whole() {
        let identity = IdentityContext::new(ReplicaId(1));
        let layer_id = AnalysisLayerId::new(ReplicaId(1), 1);
        let view_id = ViewId::new(ReplicaId(1), 2);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::CreateAnalysisLayer(CreateAnalysisLayerOp {
                    layer: crate::valuegen::analysis_layer(layer_id),
                }),
            ),
            tx_member(
                1,
                2,
                12,
                seen_r1(1),
                tx,
                OperationKind::CreateView(CreateViewOp {
                    view: crate::valuegen::view(view_id, vec![layer_id]),
                }),
            ),
            undo_env(1, 3, 20, seen_r1(2), tx, UndoPolicy::StrictInverse),
        ]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        assert!(
            matches!(
                effect_at(&out.state, 3),
                Some(OperationEffect::Applied) | Some(OperationEffect::AppliedWithRepair { .. })
            ),
            "a transaction that mints both the layer and its referencing view must undo whole"
        );
        assert!(
            !out.score.analysis_layers.iter().any(|l| l.id == layer_id),
            "the layer leaves Score.analysis_layers"
        );
        assert!(
            !out.score.views.iter().any(|v| v.id == view_id),
            "the view leaves Score.views"
        );
    }

    /// (u3c) Minting `Instrument i` and a `Staff s` naming it inside the same
    /// transaction undoes whole.
    ///
    /// **Mutation:** drop the `!targets.contains(&sobj)` conjunct from the
    /// `Instrument` guard arm. The undo becomes `Conflicted`.
    #[test]
    fn u3c_minting_the_instrument_and_its_referencing_staff_in_one_transaction_undoes_whole() {
        let identity = IdentityContext::new(ReplicaId(1));
        let instrument_id = InstrumentId::new(ReplicaId(1), 1);
        let staff_id = StaffId::new(ReplicaId(1), 2);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::CreateInstrument(CreateInstrumentOp {
                    instrument: crate::valuegen::instrument(instrument_id),
                }),
            ),
            tx_member(
                1,
                2,
                12,
                seen_r1(1),
                tx,
                OperationKind::CreateStaff(CreateStaffOp {
                    staff: crate::valuegen::staff(staff_id, instrument_id),
                }),
            ),
            undo_env(1, 3, 20, seen_r1(2), tx, UndoPolicy::StrictInverse),
        ]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        assert!(
            matches!(
                effect_at(&out.state, 3),
                Some(OperationEffect::Applied) | Some(OperationEffect::AppliedWithRepair { .. })
            ),
            "a transaction that mints both the instrument and its referencing staff must undo whole"
        );
        assert!(
            !out.score.instruments.iter().any(|i| i.id == instrument_id),
            "the instrument leaves Score.instruments"
        );
        assert!(
            !out.score.staves.iter().any(|s| s.id == staff_id),
            "the staff leaves Score.staves"
        );
    }

    // --- u4a-u4e: objects outranks the retained value map (signs pin A7). --

    /// (u4a) After u1a's undo, a byte-identical re-carry of the same
    /// `CreateStaffGroup` must report `TargetTombstoned`, not
    /// `AlreadyApplied` — `objects` outranks `staff_group_values` (pin A7).
    ///
    /// **Mutation:** in `create_staff_group`, make the
    /// `Some(ObjectState::Tombstoned { .. })` arm fall through to the
    /// value-map identity check instead of returning `TargetTombstoned`. The
    /// row must observe `AlreadyApplied`.
    #[test]
    fn u4a_a_recreate_of_a_tombstoned_staff_group_reports_target_tombstoned() {
        let identity = IdentityContext::new(ReplicaId(1));
        let group_id = StaffGroupId::new(ReplicaId(1), 1);
        let group_value = crate::valuegen::staff_group(group_id, vec![]);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::CreateStaffGroup(CreateStaffGroupOp {
                    group: group_value.clone(),
                }),
            ),
            undo_env(1, 2, 12, seen_r1(1), tx, UndoPolicy::StrictInverse),
            staff_group_env(2, 0, 20, CausalContext::new(), group_value),
        ]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        let recreate_effect = out
            .state
            .effects
            .iter()
            .find(|(id, _)| *id == OperationId::new(ReplicaId(2), 0))
            .map(|(_, e)| e.clone())
            .expect("recreate effect recorded");
        assert_eq!(
            recreate_effect,
            OperationEffect::NoOp {
                reason: NoOpReason::TargetTombstoned
            },
            "objects' Tombstoned state must outrank the retained staff_group_values \
             entry, got {recreate_effect:?}"
        );
    }

    /// (u4b) After u1b's undo, a byte-identical re-carry of the same
    /// `CreatePartDefinition` must report `TargetTombstoned`, not
    /// `AlreadyApplied`.
    ///
    /// **Mutation:** in `create_part_definition`, make the
    /// `Some(ObjectState::Tombstoned { .. })` arm fall through to the
    /// value-map identity check. The row must observe `AlreadyApplied`.
    #[test]
    fn u4b_a_recreate_of_a_tombstoned_part_definition_reports_target_tombstoned() {
        let identity = IdentityContext::new(ReplicaId(1));
        let part_id = PartDefinitionId::new(ReplicaId(1), 1);
        let part_value = crate::valuegen::part_definition(part_id, vec![]);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::CreatePartDefinition(CreatePartDefinitionOp {
                    part: part_value.clone(),
                }),
            ),
            undo_env(1, 2, 12, seen_r1(1), tx, UndoPolicy::StrictInverse),
            part_definition_env(2, 0, 20, CausalContext::new(), part_value),
        ]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        let recreate_effect = out
            .state
            .effects
            .iter()
            .find(|(id, _)| *id == OperationId::new(ReplicaId(2), 0))
            .map(|(_, e)| e.clone())
            .expect("recreate effect recorded");
        assert_eq!(
            recreate_effect,
            OperationEffect::NoOp {
                reason: NoOpReason::TargetTombstoned
            },
            "objects' Tombstoned state must outrank the retained part_definition_values \
             entry, got {recreate_effect:?}"
        );
    }

    /// (u4c) After u1c's undo, a byte-identical re-carry of the same
    /// `CreateAnalysisLayer` must report `TargetTombstoned`, not
    /// `AlreadyApplied`.
    ///
    /// **Mutation:** in `create_analysis_layer`, make the
    /// `Some(ObjectState::Tombstoned { .. })` arm fall through to the
    /// value-map identity check. The row must observe `AlreadyApplied`.
    #[test]
    fn u4c_a_recreate_of_a_tombstoned_analysis_layer_reports_target_tombstoned() {
        let identity = IdentityContext::new(ReplicaId(1));
        let layer_id = AnalysisLayerId::new(ReplicaId(1), 1);
        let layer_value = crate::valuegen::analysis_layer(layer_id);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::CreateAnalysisLayer(CreateAnalysisLayerOp {
                    layer: layer_value.clone(),
                }),
            ),
            undo_env(1, 2, 12, seen_r1(1), tx, UndoPolicy::StrictInverse),
            analysis_layer_env(2, 0, 20, CausalContext::new(), layer_value),
        ]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        let recreate_effect = out
            .state
            .effects
            .iter()
            .find(|(id, _)| *id == OperationId::new(ReplicaId(2), 0))
            .map(|(_, e)| e.clone())
            .expect("recreate effect recorded");
        assert_eq!(
            recreate_effect,
            OperationEffect::NoOp {
                reason: NoOpReason::TargetTombstoned
            },
            "objects' Tombstoned state must outrank the retained analysis_layer_values \
             entry, got {recreate_effect:?}"
        );
    }

    /// (u4d) After u1d's undo, a byte-identical re-carry of the same
    /// `CreateView` must report `TargetTombstoned`, not `AlreadyApplied`.
    ///
    /// **Mutation:** in `create_view`, make the
    /// `Some(ObjectState::Tombstoned { .. })` arm fall through to the
    /// value-map identity check. The row must observe `AlreadyApplied`.
    #[test]
    fn u4d_a_recreate_of_a_tombstoned_view_reports_target_tombstoned() {
        let identity = IdentityContext::new(ReplicaId(1));
        let view_id = ViewId::new(ReplicaId(1), 1);
        let view_value = crate::valuegen::view(view_id, vec![]);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::CreateView(CreateViewOp {
                    view: view_value.clone(),
                }),
            ),
            undo_env(1, 2, 12, seen_r1(1), tx, UndoPolicy::StrictInverse),
            view_env(2, 0, 20, CausalContext::new(), view_value),
        ]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        let recreate_effect = out
            .state
            .effects
            .iter()
            .find(|(id, _)| *id == OperationId::new(ReplicaId(2), 0))
            .map(|(_, e)| e.clone())
            .expect("recreate effect recorded");
        assert_eq!(
            recreate_effect,
            OperationEffect::NoOp {
                reason: NoOpReason::TargetTombstoned
            },
            "objects' Tombstoned state must outrank the retained view_values entry, \
             got {recreate_effect:?}"
        );
    }

    /// (u4e) After u1e's undo, a byte-identical re-carry of the same
    /// `CreateInstrument` must report `TargetTombstoned`, not
    /// `AlreadyApplied` (pin A8 — `Instrument` is in scope as collateral).
    ///
    /// **Mutation:** in `create_instrument`, make the
    /// `Some(ObjectState::Tombstoned { .. })` arm fall through to the
    /// value-map identity check. The row must observe `AlreadyApplied`.
    #[test]
    fn u4e_a_recreate_of_a_tombstoned_instrument_reports_target_tombstoned() {
        let identity = IdentityContext::new(ReplicaId(1));
        let instrument_id = InstrumentId::new(ReplicaId(1), 1);
        let instrument_value = crate::valuegen::instrument(instrument_id);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let mut set = OperationSet::new();
        set.accept_all(vec![
            declare_transaction(1, 0, 10, CausalContext::new(), tx),
            tx_member(
                1,
                1,
                11,
                seen_r1(0),
                tx,
                OperationKind::CreateInstrument(CreateInstrumentOp {
                    instrument: instrument_value.clone(),
                }),
            ),
            undo_env(1, 2, 12, seen_r1(1), tx, UndoPolicy::StrictInverse),
            instrument_env(2, 0, 20, CausalContext::new(), instrument_value),
        ]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        let recreate_effect = out
            .state
            .effects
            .iter()
            .find(|(id, _)| *id == OperationId::new(ReplicaId(2), 0))
            .map(|(_, e)| e.clone())
            .expect("recreate effect recorded");
        assert_eq!(
            recreate_effect,
            OperationEffect::NoOp {
                reason: NoOpReason::TargetTombstoned
            },
            "objects' Tombstoned state must outrank the retained instrument_values \
             entry, got {recreate_effect:?}"
        );
    }

    // =========================================================================
    // Genesis tranche G3b (`spec/CONTRACT_GENESIS_G3B_MEASURE.md`): CreateMeasure,
    // the comparable relation (pin 6), the musical delta (pin 6b), and the
    // effective-grid oracle (pin 6c).
    // =========================================================================

    fn g3b_measure_env(
        replica: u64,
        counter: u64,
        physical: i64,
        instance: StaffInstanceId,
        measure: Measure,
    ) -> OperationEnvelope {
        prim_env(
            replica,
            counter,
            physical,
            CausalContext::new(),
            OperationKind::CreateMeasure(CreateMeasureOp { instance, measure }),
        )
    }

    fn g3b_region_and_instance_envs(
        replica: u64,
        region: RegionId,
        instance: StaffInstanceId,
        staff: StaffId,
    ) -> Vec<OperationEnvelope> {
        vec![
            prim_env(
                replica,
                0,
                0,
                CausalContext::new(),
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region),
                }),
            ),
            prim_env(
                replica,
                1,
                1,
                CausalContext::new(),
                OperationKind::CreateStaffInstance(CreateStaffInstanceOp {
                    region,
                    instance: crate::valuegen::staff_instance(instance, staff),
                }),
            ),
        ]
    }

    fn g3b_wallclock_measure(id: MeasureId, nanos: i64) -> Measure {
        Measure {
            id,
            start: TimeAnchor::WallClock {
                time: WallClockTime(nanos),
            },
            time_signature: None,
            explicit_number: None,
            number_visibility: epiphany_core::MeasureNumberVisibility::Auto,
        }
    }

    fn g3b_effect_of(state: &MaterializedState, id: OperationId) -> Option<OperationEffect> {
        state
            .effects
            .iter()
            .find(|(e, _)| *e == id)
            .map(|(_, eff)| eff.clone())
    }

    /// (M16, M17, M18 base-free leg) `CreateMeasure`'s mint discipline: fresh
    /// id mints; a byte-identical re-carry under the SAME parent is
    /// idempotent (`AlreadyApplied`); a differing value under a live id is a
    /// precondition no-op (`RecreateContentMismatch`, M16); the SAME value
    /// under a DIFFERENT parent is ALSO `RecreateContentMismatch` — the
    /// parent is part of identity (pin 5, M17); a dead parent refuses
    /// (`TargetMissing`) base-free too (M18's ungated leg).
    #[test]
    fn g3b_create_measure_mint_discipline_base_free() {
        let region = RegionId::new(ReplicaId(1), 1);
        let instance_a = StaffInstanceId::new(ReplicaId(1), 2);
        let instance_b = StaffInstanceId::new(ReplicaId(1), 3);
        let staff = StaffId::new(ReplicaId(1), 4);
        let mut envs = g3b_region_and_instance_envs(1, region, instance_a, staff);
        envs.push(prim_env(
            1,
            2,
            2,
            CausalContext::new(),
            OperationKind::CreateStaffInstance(CreateStaffInstanceOp {
                region,
                instance: crate::valuegen::staff_instance(instance_b, staff),
            }),
        ));

        let measure_id = MeasureId::new(ReplicaId(1), 10);
        let measure = g3b_wallclock_measure(measure_id, 1_000);
        let mut differing = measure.clone();
        differing.explicit_number = Some(99);

        let create = g3b_measure_env(1, 10, 10, instance_a, measure.clone());
        let recarry_identical = g3b_measure_env(1, 11, 11, instance_a, measure.clone());
        let recarry_differing = g3b_measure_env(1, 12, 12, instance_a, differing);
        let recarry_other_parent = g3b_measure_env(1, 13, 13, instance_b, measure);
        let dead_parent = g3b_measure_env(
            1,
            14,
            14,
            StaffInstanceId::new(ReplicaId(1), 999),
            g3b_wallclock_measure(MeasureId::new(ReplicaId(1), 11), 2_000),
        );

        envs.extend([
            create.clone(),
            recarry_identical.clone(),
            recarry_differing.clone(),
            recarry_other_parent.clone(),
            dead_parent.clone(),
        ]);
        let mut set = OperationSet::new();
        set.accept_all(envs);
        let state = set.reduce();

        assert_eq!(
            g3b_effect_of(&state, create.id),
            Some(OperationEffect::Applied)
        );
        assert_eq!(
            g3b_effect_of(&state, recarry_identical.id),
            Some(OperationEffect::NoOp {
                reason: NoOpReason::AlreadyApplied
            })
        );
        assert_eq!(
            g3b_effect_of(&state, recarry_differing.id),
            Some(OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::RecreateContentMismatch
                }
            })
        );
        assert_eq!(
            g3b_effect_of(&state, recarry_other_parent.id),
            Some(OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::RecreateContentMismatch
                }
            }),
            "the parent is part of identity (pin 5): a re-carry under a different \
             parent must not be AlreadyApplied"
        );
        assert_eq!(
            g3b_effect_of(&state, dead_parent.id),
            Some(OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetMissing
                }
            }),
            "a dead parent must refuse base-free too (pin 8.1, ungated)"
        );
    }

    /// (M18 graph-aware leg) A dead parent refuses under a graph too.
    #[test]
    fn g3b_create_measure_dead_parent_graph_aware() {
        let identity = IdentityContext::new(ReplicaId(1));
        let dead_parent = g3b_measure_env(
            1,
            0,
            0,
            StaffInstanceId::new(ReplicaId(1), 999),
            g3b_wallclock_measure(MeasureId::new(ReplicaId(1), 1), 1_000),
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![dead_parent.clone()]);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));
        assert_eq!(
            g3b_effect_of(&out.state, dead_parent.id),
            Some(OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::TargetMissing
                }
            })
        );
    }

    /// (M19, M20 x3) Reference-resolution preconditions are graph-aware:
    /// `time_signature: Some(id)` must resolve (M19); `start`'s referent must
    /// resolve for each non-`WallClock` variant — `Event`, `Measure`,
    /// `Region` (M20, three observations).
    #[test]
    fn g3b_create_measure_referential_preconditions_graph_aware() {
        let identity = IdentityContext::new(ReplicaId(1));
        let region = RegionId::new(ReplicaId(1), 1);
        let instance = StaffInstanceId::new(ReplicaId(1), 2);
        let staff = StaffId::new(ReplicaId(1), 3);
        let instrument = epiphany_core::InstrumentId::new(ReplicaId(1), 4);
        // Graph-aware mode preconditions CreateStaffInstance on a live
        // Staff, which in turn preconditions a live Instrument — mint both
        // first so the parent instance genuinely becomes Live, otherwise
        // every CreateMeasure below would refuse on pin 8.1 (parent
        // liveness) before ever reaching pins 8.2/8.3.
        let mut envs = vec![
            prim_env(
                1,
                0,
                0,
                CausalContext::new(),
                OperationKind::CreateInstrument(CreateInstrumentOp {
                    instrument: crate::valuegen::instrument(instrument),
                }),
            ),
            prim_env(
                1,
                1,
                1,
                CausalContext::new(),
                OperationKind::CreateStaff(CreateStaffOp {
                    staff: crate::valuegen::staff(staff, instrument),
                }),
            ),
            prim_env(
                1,
                2,
                2,
                CausalContext::new(),
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region),
                }),
            ),
            prim_env(
                1,
                3,
                3,
                CausalContext::new(),
                OperationKind::CreateStaffInstance(CreateStaffInstanceOp {
                    region,
                    instance: crate::valuegen::staff_instance(instance, staff),
                }),
            ),
        ];

        // M19: an unresolvable time_signature.
        let bad_signature = g3b_measure_env(
            1,
            10,
            10,
            instance,
            Measure {
                id: MeasureId::new(ReplicaId(1), 20),
                start: TimeAnchor::WallClock {
                    time: WallClockTime(1),
                },
                time_signature: Some(TimeSignatureId::new(ReplicaId(1), 999)),
                explicit_number: None,
                number_visibility: epiphany_core::MeasureNumberVisibility::Auto,
            },
        );
        // M20 (Event): an unresolvable Event referent.
        let bad_event = g3b_measure_env(
            1,
            11,
            11,
            instance,
            Measure {
                id: MeasureId::new(ReplicaId(1), 21),
                start: TimeAnchor::Event {
                    id: EventId::new(ReplicaId(1), 999),
                    offset: AnchorOffset::Zero,
                },
                time_signature: None,
                explicit_number: None,
                number_visibility: epiphany_core::MeasureNumberVisibility::Auto,
            },
        );
        // M20 (Measure): an unresolvable Measure referent.
        let bad_measure_ref = g3b_measure_env(
            1,
            12,
            12,
            instance,
            Measure {
                id: MeasureId::new(ReplicaId(1), 22),
                start: TimeAnchor::Measure {
                    id: MeasureId::new(ReplicaId(1), 999),
                    position: MeasurePosition::Start,
                    offset: AnchorOffset::Zero,
                },
                time_signature: None,
                explicit_number: None,
                number_visibility: epiphany_core::MeasureNumberVisibility::Auto,
            },
        );
        // M20 (Region): an unresolvable Region referent.
        let bad_region_ref = g3b_measure_env(
            1,
            13,
            13,
            instance,
            Measure {
                id: MeasureId::new(ReplicaId(1), 23),
                start: TimeAnchor::Region {
                    id: RegionId::new(ReplicaId(1), 999),
                    edge: RegionEdge::Start,
                    offset: AnchorOffset::Zero,
                },
                time_signature: None,
                explicit_number: None,
                number_visibility: epiphany_core::MeasureNumberVisibility::Auto,
            },
        );

        envs.extend([
            bad_signature.clone(),
            bad_event.clone(),
            bad_measure_ref.clone(),
            bad_region_ref.clone(),
        ]);
        let mut set = OperationSet::new();
        set.accept_all(envs);
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        let target_missing = Some(OperationEffect::NoOp {
            reason: NoOpReason::PreconditionFailedUnderReduction {
                reason: PreconditionFailureReason::TargetMissing,
            },
        });
        assert_eq!(
            g3b_effect_of(&out.state, bad_signature.id),
            target_missing,
            "M19: an unresolvable time_signature must refuse graph-aware"
        );
        assert_eq!(
            g3b_effect_of(&out.state, bad_event.id),
            target_missing,
            "M20 (Event): an unresolvable start referent must refuse graph-aware"
        );
        assert_eq!(
            g3b_effect_of(&out.state, bad_measure_ref.id),
            target_missing,
            "M20 (Measure): an unresolvable start referent must refuse graph-aware"
        );
        assert_eq!(
            g3b_effect_of(&out.state, bad_region_ref.id),
            target_missing,
            "M20 (Region): an unresolvable start referent must refuse graph-aware"
        );
    }

    /// (M15) A byte-identical re-carry against a *base*-seeded measure is
    /// idempotent — a re-carry test that only ever reduces from empty cannot
    /// see a missing `measure_values` base seed at all.
    #[test]
    fn g3b_create_measure_base_recarry_is_idempotent() {
        let measure = g3b_wallclock_measure(MeasureId::new(ReplicaId(1), 1), 5_000);
        let instance_id = StaffInstanceId::new(ReplicaId(1), 2);
        let mut instance =
            crate::valuegen::staff_instance(instance_id, StaffId::new(ReplicaId(1), 3));
        instance.measures.push(measure.clone());
        let mut region = crate::valuegen::region(RegionId::new(ReplicaId(1), 4));
        if let epiphany_core::RegionContent::StaffBased(content) = &mut region.content {
            content.staff_instances.push(instance);
        } else {
            panic!("valuegen::region is staff-based");
        }
        let mut base = Score::empty(IdentityContext::new(ReplicaId(1)));
        base.canvas.regions.push(region);

        let recarry = g3b_measure_env(2, 0, 10, instance_id, measure);
        let mut set = OperationSet::new();
        set.accept_all(vec![recarry.clone()]);
        let out = reduce_operation_set_onto(&set, &base);
        assert_eq!(
            g3b_effect_of(&out.state, recarry.id),
            Some(OperationEffect::NoOp {
                reason: NoOpReason::AlreadyApplied
            }),
            "a base-seeded measure re-carried byte-identically must be AlreadyApplied \
             (pin 5 site 4 — the G1 instrument_values hazard)"
        );
    }

    /// (M23–M26) Pin 6's comparable relation, exactly the five shapes; pin
    /// 6b's musical delta. Exercised directly on a bare `Reducer` (a
    /// white-box test of the shared, reusable predicates — invariant 20,
    /// packet 2, reuses these same functions).
    #[test]
    fn g3b_comparable_offsets_and_anchor_shapes() {
        let ev_a = EventId::new(ReplicaId(1), 1);
        let ev_b = EventId::new(ReplicaId(1), 2);
        let m_a = MeasureId::new(ReplicaId(1), 10);
        let m_b = MeasureId::new(ReplicaId(1), 11);
        let rg_a = RegionId::new(ReplicaId(1), 20);
        let rg_b = RegionId::new(ReplicaId(1), 21);
        let instance = StaffInstanceId::new(ReplicaId(1), 99);

        // Repair 1 (spec/CONTRACT_GENESIS_G3B_MEASURE.md, review fix): the
        // base-free c3 branch now reads real minter envelopes' stamp
        // reduction tuples, so the op set must actually carry them — a
        // stamp order that AGREES with OperationId order here (replica 1,
        // counters 1 then 2, physical 1_000 then 2_000), so this base case
        // does not itself distinguish the two orderings (that is
        // `g3b_c3_order_follows_stamp_not_operation_id`, below).
        let measure_a = g3b_wallclock_measure(m_a, 1_000);
        let measure_b = g3b_wallclock_measure(m_b, 2_000);
        let mut op_set = OperationSet::new();
        op_set.accept_all(vec![
            g3b_measure_env(1, 1, 1_000, instance, measure_a.clone()),
            g3b_measure_env(1, 2, 2_000, instance, measure_b.clone()),
        ]);
        let mut r = Reducer::new(&op_set);
        r.objects
            .insert(TypedObjectId::Measure(m_a), ObjectState::Live);
        r.objects
            .insert(TypedObjectId::Measure(m_b), ObjectState::Live);
        r.minted_by.insert(
            TypedObjectId::Measure(m_a),
            OperationId::new(ReplicaId(1), 1),
        );
        r.minted_by.insert(
            TypedObjectId::Measure(m_b),
            OperationId::new(ReplicaId(1), 2),
        );
        r.measure_values.insert(m_a, (instance, measure_a));
        r.measure_values.insert(m_b, (instance, measure_b));

        // c1: same Event id, comparable by offset.
        let e1 = TimeAnchor::Event {
            id: ev_a,
            offset: AnchorOffset::Musical(MusicalDuration(RationalTime::from_int(1))),
        };
        let e2 = TimeAnchor::Event {
            id: ev_a,
            offset: AnchorOffset::Musical(MusicalDuration(RationalTime::from_int(2))),
        };
        assert_eq!(r.anchors_comparable_order(&e1, &e2), Some(Ordering::Less));
        assert_eq!(
            r.anchor_musical_delta(&e1, &e2),
            Some(MusicalDuration(RationalTime::from_int(1)))
        );
        // Never two Events with different ids.
        let e3 = TimeAnchor::Event {
            id: ev_b,
            offset: AnchorOffset::Musical(MusicalDuration(RationalTime::from_int(1))),
        };
        assert_eq!(r.anchors_comparable_order(&e1, &e3), None);

        // M23: Musical vs WallClock offsets are never comparable, even under
        // the same Event id.
        let e_wc = TimeAnchor::Event {
            id: ev_a,
            offset: AnchorOffset::WallClock(WallClockDuration(5)),
        };
        assert_eq!(
            r.anchors_comparable_order(&e1, &e_wc),
            None,
            "M23: Musical against WallClock must never be comparable"
        );

        // c2: same Measure id AND same pos, comparable by offset.
        let ms1 = TimeAnchor::Measure {
            id: m_a,
            position: MeasurePosition::Start,
            offset: AnchorOffset::Zero,
        };
        let ms2 = TimeAnchor::Measure {
            id: m_a,
            position: MeasurePosition::Start,
            offset: AnchorOffset::Musical(MusicalDuration(RationalTime::from_int(3))),
        };
        assert_eq!(r.anchors_comparable_order(&ms1, &ms2), Some(Ordering::Less));
        assert_eq!(
            r.anchor_musical_delta(&ms1, &ms2),
            Some(MusicalDuration(RationalTime::from_int(3)))
        );
        // Same id but DIFFERING pos: never comparable (the selector must be
        // identical — never ordered).
        let ms_end = TimeAnchor::Measure {
            id: m_a,
            position: MeasurePosition::End,
            offset: AnchorOffset::Zero,
        };
        assert_eq!(r.anchors_comparable_order(&ms1, &ms_end), None);
        assert_eq!(r.anchor_musical_delta(&ms1, &ms_end), None);

        // c3: distinct Measure ids, both Start+Zero, in the same instance's
        // (base-free) mint order — via the minters' stamp reduction-tuple
        // comparison (Repair 1: NOT `OperationId`'s own `Ord`, and both
        // measures must share the SAME `StaffInstanceId` in `measure_values`
        // and be Live — see `g3b_c3_requires_same_staff_instance` and
        // `g3b_c3_requires_live_measures` below for the negative cases).
        let c3_a = TimeAnchor::Measure {
            id: m_a,
            position: MeasurePosition::Start,
            offset: AnchorOffset::Zero,
        };
        let c3_b = TimeAnchor::Measure {
            id: m_b,
            position: MeasurePosition::Start,
            offset: AnchorOffset::Zero,
        };
        assert_eq!(
            r.anchors_comparable_order(&c3_a, &c3_b),
            Some(Ordering::Less),
            "c3: distinct measure ids, Start+Zero, order by mint sequence"
        );
        assert_eq!(
            r.anchor_musical_delta(&c3_a, &c3_b),
            None,
            "c3 supplies no delta — a vector index gives order, never distance"
        );

        // M24: widening c3 to admit a nonzero offset or an `End` position
        // must NOT be comparable (a nonzero offset or End can carry the
        // point past its neighbour).
        let c3_nonzero = TimeAnchor::Measure {
            id: m_b,
            position: MeasurePosition::Start,
            offset: AnchorOffset::Musical(MusicalDuration(RationalTime::from_int(1))),
        };
        assert_eq!(
            r.anchors_comparable_order(&c3_a, &c3_nonzero),
            None,
            "M24: a nonzero-offset measure anchor must not be c3-comparable"
        );
        let c3_end = TimeAnchor::Measure {
            id: m_b,
            position: MeasurePosition::End,
            offset: AnchorOffset::Zero,
        };
        // (Same-pos guard already forces None here since c3_a is Start; this
        // documents that End never qualifies for c3 even at Zero offset.)
        assert_eq!(r.anchors_comparable_order(&c3_a, &c3_end), None);

        // c4: same Region id AND same edge, comparable by offset.
        let rg1 = TimeAnchor::Region {
            id: rg_a,
            edge: RegionEdge::Start,
            offset: AnchorOffset::Zero,
        };
        let rg2 = TimeAnchor::Region {
            id: rg_a,
            edge: RegionEdge::Start,
            offset: AnchorOffset::Musical(MusicalDuration(RationalTime::from_int(4))),
        };
        assert_eq!(r.anchors_comparable_order(&rg1, &rg2), Some(Ordering::Less));
        assert_eq!(
            r.anchor_musical_delta(&rg1, &rg2),
            Some(MusicalDuration(RationalTime::from_int(4)))
        );
        // Never Region<->Region with different ids.
        let rg3 = TimeAnchor::Region {
            id: rg_b,
            edge: RegionEdge::Start,
            offset: AnchorOffset::Zero,
        };
        assert_eq!(r.anchors_comparable_order(&rg1, &rg3), None);

        // M25/M26: same Region id, DIFFERING edge (Start vs End) — never
        // comparable, and never a delta, regardless of offset magnitude.
        // Draft 3's `Start < End` ordering (and its offset subtraction) was
        // unsound: with a nonzero offset the selector does not bound the
        // point without the region's own (deferred) length.
        let rg_start_100 = TimeAnchor::Region {
            id: rg_a,
            edge: RegionEdge::Start,
            offset: AnchorOffset::Musical(MusicalDuration(RationalTime::from_int(100))),
        };
        let rg_end_0 = TimeAnchor::Region {
            id: rg_a,
            edge: RegionEdge::End,
            offset: AnchorOffset::Zero,
        };
        assert_eq!(
            r.anchors_comparable_order(&rg_start_100, &rg_end_0),
            None,
            "M25: Region{{Start, Musical(100)}} vs Region{{End, Zero}} must be unverifiable"
        );
        assert_eq!(
            r.anchor_musical_delta(&rg_start_100, &rg_end_0),
            None,
            "M26: the delta across differing edges must not be computable"
        );

        // Never Event<->Measure, never Measure<->Region.
        assert_eq!(r.anchors_comparable_order(&e1, &ms1), None);
        assert_eq!(r.anchors_comparable_order(&ms1, &rg1), None);

        // c5: WallClock, no referent id, comparable by time.
        let wc1 = TimeAnchor::WallClock {
            time: WallClockTime(1),
        };
        let wc2 = TimeAnchor::WallClock {
            time: WallClockTime(2),
        };
        assert_eq!(r.anchors_comparable_order(&wc1, &wc2), Some(Ordering::Less));
        // c5 offers no offsets to subtract; WallClock deltas are never
        // musical durations.
        assert_eq!(r.anchor_musical_delta(&wc1, &wc2), None);
    }

    /// Repair 1 regression (spec/CONTRACT_GENESIS_G3B_MEASURE.md pin 6 c3):
    /// two measures anchored via `Measure{pos: Start, off: Zero}` are NOT
    /// c3-comparable when `measure_values` records them under DIFFERENT
    /// `StaffInstanceId`s — the graph-aware branch enforces "same instance"
    /// implicitly (it only returns from within one instance's `Vec`); the
    /// base-free branch must check it explicitly.
    ///
    /// **Mutation:** drop the `parent_a != parent_b` check from
    /// `measure_vector_order`'s base-free branch. This row must observe red.
    #[test]
    fn g3b_c3_requires_same_staff_instance() {
        let m_a = MeasureId::new(ReplicaId(1), 30);
        let m_b = MeasureId::new(ReplicaId(1), 31);
        let instance_a = StaffInstanceId::new(ReplicaId(1), 199);
        let instance_b = StaffInstanceId::new(ReplicaId(1), 200);

        let measure_a = g3b_wallclock_measure(m_a, 1_000);
        let measure_b = g3b_wallclock_measure(m_b, 2_000);
        let mut op_set = OperationSet::new();
        op_set.accept_all(vec![
            g3b_measure_env(1, 1, 1_000, instance_a, measure_a.clone()),
            g3b_measure_env(1, 2, 2_000, instance_b, measure_b.clone()),
        ]);
        let mut r = Reducer::new(&op_set);
        r.objects
            .insert(TypedObjectId::Measure(m_a), ObjectState::Live);
        r.objects
            .insert(TypedObjectId::Measure(m_b), ObjectState::Live);
        r.minted_by.insert(
            TypedObjectId::Measure(m_a),
            OperationId::new(ReplicaId(1), 1),
        );
        r.minted_by.insert(
            TypedObjectId::Measure(m_b),
            OperationId::new(ReplicaId(1), 2),
        );
        // The load-bearing part of this fixture: the two measures are
        // recorded under DIFFERENT parent instances.
        r.measure_values.insert(m_a, (instance_a, measure_a));
        r.measure_values.insert(m_b, (instance_b, measure_b));

        let c3_a = TimeAnchor::Measure {
            id: m_a,
            position: MeasurePosition::Start,
            offset: AnchorOffset::Zero,
        };
        let c3_b = TimeAnchor::Measure {
            id: m_b,
            position: MeasurePosition::Start,
            offset: AnchorOffset::Zero,
        };
        assert_eq!(
            r.anchors_comparable_order(&c3_a, &c3_b),
            None,
            "c3: measures anchored in DIFFERENT StaffInstances must not be comparable"
        );
    }

    /// Repair 1 regression: a c3 comparison against a measure that is not
    /// `Live` (e.g. retained-but-tombstoned, pin 10.4's retention
    /// discipline) must not contribute to the ordering.
    ///
    /// **Mutation:** drop the `Live` conjunct from `measure_vector_order`'s
    /// base-free branch. This row must observe red.
    #[test]
    fn g3b_c3_requires_live_measures() {
        let m_a = MeasureId::new(ReplicaId(1), 32);
        let m_b = MeasureId::new(ReplicaId(1), 33);
        let instance = StaffInstanceId::new(ReplicaId(1), 201);

        let measure_a = g3b_wallclock_measure(m_a, 1_000);
        let measure_b = g3b_wallclock_measure(m_b, 2_000);
        let mut op_set = OperationSet::new();
        op_set.accept_all(vec![
            g3b_measure_env(1, 1, 1_000, instance, measure_a.clone()),
            g3b_measure_env(1, 2, 2_000, instance, measure_b.clone()),
        ]);
        let mut r = Reducer::new(&op_set);
        r.objects
            .insert(TypedObjectId::Measure(m_a), ObjectState::Live);
        // b is tombstoned, not live, but its value is still retained (pin
        // 10.4's uniform retention discipline).
        r.objects.insert(
            TypedObjectId::Measure(m_b),
            ObjectState::Tombstoned {
                deleted_by: OperationId::new(ReplicaId(9), 9),
                minted_by: OperationId::new(ReplicaId(1), 2),
            },
        );
        r.minted_by.insert(
            TypedObjectId::Measure(m_a),
            OperationId::new(ReplicaId(1), 1),
        );
        r.minted_by.insert(
            TypedObjectId::Measure(m_b),
            OperationId::new(ReplicaId(1), 2),
        );
        r.measure_values.insert(m_a, (instance, measure_a));
        r.measure_values.insert(m_b, (instance, measure_b));

        let c3_a = TimeAnchor::Measure {
            id: m_a,
            position: MeasurePosition::Start,
            offset: AnchorOffset::Zero,
        };
        let c3_b = TimeAnchor::Measure {
            id: m_b,
            position: MeasurePosition::Start,
            offset: AnchorOffset::Zero,
        };
        assert_eq!(
            r.anchors_comparable_order(&c3_a, &c3_b),
            None,
            "c3: a Tombstoned measure must not contribute to the ordering"
        );
    }

    /// Repair 1 regression: `measure_vector_order`'s base-free branch must
    /// order by the minters' canonical reduction-order STAMP tuple, not by
    /// `OperationId`'s own `(replica, counter)` `Ord` (ids.rs:409). Here `m_a`
    /// was minted with the LARGER counter but the EARLIER physical stamp, and
    /// `m_b` with the SMALLER counter but the LATER physical stamp — the two
    /// orderings disagree, so this is the only fixture that distinguishes
    /// them.
    ///
    /// **Mutation:** revert the base-free branch to `oa.cmp(ob)` on the raw
    /// `OperationId`s. This row must observe red (it would report
    /// `Some(Ordering::Greater)`, the opposite of the correct answer).
    #[test]
    fn g3b_c3_order_follows_stamp_not_operation_id() {
        let m_a = MeasureId::new(ReplicaId(1), 34);
        let m_b = MeasureId::new(ReplicaId(1), 35);
        let instance = StaffInstanceId::new(ReplicaId(1), 202);

        let measure_a = g3b_wallclock_measure(m_a, 1_000);
        let measure_b = g3b_wallclock_measure(m_b, 2_000);
        let mut op_set = OperationSet::new();
        op_set.accept_all(vec![
            // m_a: OperationId counter 2, but the EARLIER physical stamp.
            g3b_measure_env(1, 2, 100, instance, measure_a.clone()),
            // m_b: OperationId counter 1, but the LATER physical stamp.
            g3b_measure_env(1, 1, 200, instance, measure_b.clone()),
        ]);
        let mut r = Reducer::new(&op_set);
        r.objects
            .insert(TypedObjectId::Measure(m_a), ObjectState::Live);
        r.objects
            .insert(TypedObjectId::Measure(m_b), ObjectState::Live);
        r.minted_by.insert(
            TypedObjectId::Measure(m_a),
            OperationId::new(ReplicaId(1), 2),
        );
        r.minted_by.insert(
            TypedObjectId::Measure(m_b),
            OperationId::new(ReplicaId(1), 1),
        );
        r.measure_values.insert(m_a, (instance, measure_a));
        r.measure_values.insert(m_b, (instance, measure_b));

        let c3_a = TimeAnchor::Measure {
            id: m_a,
            position: MeasurePosition::Start,
            offset: AnchorOffset::Zero,
        };
        let c3_b = TimeAnchor::Measure {
            id: m_b,
            position: MeasurePosition::Start,
            offset: AnchorOffset::Zero,
        };
        // OperationId order says m_b (counter 1) < m_a (counter 2); stamp
        // order says m_a (physical 100) < m_b (physical 200). The correct
        // answer follows the stamp: c3_a (m_a) is Less than c3_b (m_b).
        assert_eq!(
            r.anchors_comparable_order(&c3_a, &c3_b),
            Some(Ordering::Less),
            "c3 ordering must follow the minters' stamp reduction tuple, not OperationId::cmp"
        );
    }

    fn g3b_region_anchor(region: RegionId, n: i32) -> TimeAnchor {
        TimeAnchor::Region {
            id: region,
            edge: RegionEdge::Start,
            offset: AnchorOffset::Musical(MusicalDuration(RationalTime::from_int(n))),
        }
    }

    /// (M27, M28, M29) Pin 6c steps 0–3, direct on a bare `Reducer`.
    #[test]
    fn g3b_grid_oracle_governing_selection() {
        let op_set = OperationSet::new();
        let r = Reducer::new(&op_set);
        let region = RegionId::new(ReplicaId(1), 1);
        let sig_a = TimeSignatureId::new(ReplicaId(1), 10);
        let sig_b = TimeSignatureId::new(ReplicaId(1), 11);

        // M29: a genuinely empty sequence is vacuous, not indeterminate.
        assert_eq!(
            r.governing_by_anchor(
                &g3b_region_anchor(region, 0),
                Vec::<(TimeSignatureId, &TimeAnchor)>::new()
            ),
            GoverningElement::None,
            "M29: an empty candidate set must be vacuous"
        );

        // Step 0 / M28: a change incomparable to the reference makes the
        // WHOLE selection indeterminate, even though the (comparable-only)
        // candidate set is empty. Use an Event-anchored change against a
        // Region-anchored reference (never comparable, c1 vs c4).
        let incomparable_anchor = TimeAnchor::Event {
            id: EventId::new(ReplicaId(1), 1),
            offset: AnchorOffset::Zero,
        };
        assert_eq!(
            r.governing_by_anchor(
                &g3b_region_anchor(region, 0),
                vec![(sig_a, &incomparable_anchor)]
            ),
            GoverningElement::Indeterminate,
            "M28: an incomparable change must be indeterminate, not vacuous \
             (it is unplaced, not absent, and might have governed)"
        );

        // A unique maximum not-after the reference.
        let a0 = g3b_region_anchor(region, 0);
        let a2 = g3b_region_anchor(region, 2);
        let reference = g3b_region_anchor(region, 5);
        assert_eq!(
            r.governing_by_anchor(&reference, vec![(sig_a, &a0), (sig_b, &a2)]),
            GoverningElement::Unique(sig_b),
            "the later not-after candidate must govern"
        );

        // M27: two maxima, mutually incomparable to each other (but each
        // individually comparable to the reference) — via one c4 (Region)
        // and one c1 (Event) candidate that each happen to also be
        // comparable to a WallClock reference... Simpler: two candidates at
        // the exact SAME resolved point via different, mutually-incomparable
        // shapes is hard to stage without a synthetic reference; instead
        // stage the canonical "tie" case pin 6c step 3 names directly: two
        // Region-anchored candidates at the SAME offset (so both are
        // `Ordering::Equal` to each other — neither dominates the other, so
        // neither is uniquely maximal) is not directly expressible with two
        // *distinct* MeterChanges at hand here without a c3-style id split;
        // use the simplest faithful staging: a WallClock reference cannot
        // relate to a Region candidate, so instead compare two candidates
        // that are each comparable to the reference via c4 but not to each
        // other because they are anchored to two DIFFERENT regions that
        // BOTH happen to be "comparable to the reference" only through an
        // artificial helper — not expressible under pin 6's real shapes.
        // The faithful staging pin 6c step 3 describes is two maxima tied at
        // Equal: both anchors identical in content to each other but
        // reported as two distinct entries (a duplicate write at the same
        // key from two different signatures is the realistic shape).
        let tie_a = g3b_region_anchor(region, 3);
        let tie_b = g3b_region_anchor(region, 3);
        assert_eq!(
            r.governing_by_anchor(&reference, vec![(sig_a, &tie_a), (sig_b, &tie_b)]),
            GoverningElement::Indeterminate,
            "M27: tied (mutually non-dominating) maxima must be indeterminate, \
             never picked by document order"
        );
    }

    /// (M30, M31) `instance_grid`'s base seed, and the local override
    /// winning over the region default.
    #[test]
    fn g3b_grid_oracle_instance_override_wins_and_base_seed() {
        let op_set = OperationSet::new();
        let mut r = Reducer::new(&op_set);
        let instance = StaffInstanceId::new(ReplicaId(1), 1);
        let region = RegionId::new(ReplicaId(1), 2);
        let sig_local = TimeSignatureId::new(ReplicaId(1), 10);
        let sig_region = TimeSignatureId::new(ReplicaId(1), 11);

        let local_grid = MetricGrid {
            meter_sequence: vec![MeterChange {
                anchor: g3b_region_anchor(region, 0),
                time_signature: sig_local,
            }],
        };
        r.instance_grid.insert(instance, Some(local_grid.clone()));

        let mut whole_chain = WriteChain::new();
        whole_chain.seed(Some(MetricGrid {
            meter_sequence: vec![MeterChange {
                anchor: g3b_region_anchor(region, 0),
                time_signature: sig_region,
            }],
        }));
        r.metric_grid_chain.insert(region, whole_chain);

        assert_eq!(
            r.effective_grid(instance, Some(region), None, &BTreeMap::new()),
            local_grid.meter_sequence,
            "M31: an authored local override must win over the region default"
        );

        // M30 (seed_from_graph): base-seeded, from-empty parity is exercised
        // end-to-end by `g3b_create_measure_base_recarry_is_idempotent`
        // and the `instance_grid` seeding in `seed_from_graph` (contract
        // pin 6c, disposition A) — here confirmed directly: an instance
        // with NO recorded local override (the seed never having run) falls
        // through to the region default.
        r.instance_grid.remove(&instance);
        assert_eq!(
            r.effective_grid(instance, Some(region), None, &BTreeMap::new()),
            vec![MeterChange {
                anchor: g3b_region_anchor(region, 0),
                time_signature: sig_region,
            }],
            "with no instance_grid entry at all, the region default must govern"
        );
    }

    /// (M30) `instance_grid`'s BASE seed (`seed_from_graph`), end-to-end: a
    /// base Score whose `StaffInstance.local_metric_grid` is `Some(...)`
    /// must be visible to a `CreateMeasure` reduced onto it, distinguishing
    /// override from the region's (disagreeing) default — without this seed,
    /// the override is invisible and the region default wins wrongly.
    #[test]
    fn g3b_grid_oracle_instance_grid_base_seed_end_to_end() {
        let instance_id = StaffInstanceId::new(ReplicaId(1), 1);
        let region_id = RegionId::new(ReplicaId(1), 2);
        let sig_local = TimeSignatureId::new(ReplicaId(1), 10);
        let sig_region = TimeSignatureId::new(ReplicaId(1), 11);

        let mut instance =
            crate::valuegen::staff_instance(instance_id, StaffId::new(ReplicaId(1), 3));
        instance.local_metric_grid = Some(MetricGrid {
            meter_sequence: vec![MeterChange {
                anchor: g3b_region_anchor(region_id, 0),
                time_signature: sig_local,
            }],
        });
        let mut region = crate::valuegen::region(region_id);
        if let epiphany_core::RegionContent::StaffBased(content) = &mut region.content {
            content.staff_instances.push(instance);
            content.default_metric_grid = Some(MetricGrid {
                meter_sequence: vec![MeterChange {
                    anchor: g3b_region_anchor(region_id, 0),
                    time_signature: sig_region,
                }],
            });
        }
        let mut base = Score::empty(IdentityContext::new(ReplicaId(1)));
        base.time_signatures
            .push(crate::valuegen::time_signature(sig_local, 3));
        base.time_signatures
            .push(crate::valuegen::time_signature(sig_region, 5));
        base.canvas.regions.push(region);

        // Agree with the LOCAL override (sig_local) — must Apply only if the
        // base seed made the override visible; otherwise the region default
        // (sig_region) governs and this disagrees.
        let measure = g3b_measure_env(
            2,
            0,
            0,
            instance_id,
            Measure {
                id: MeasureId::new(ReplicaId(1), 100),
                start: g3b_region_anchor(region_id, 0),
                time_signature: Some(sig_local),
                explicit_number: None,
                number_visibility: epiphany_core::MeasureNumberVisibility::Auto,
            },
        );
        let mut set = OperationSet::new();
        set.accept_all(vec![measure.clone()]);
        let out = reduce_operation_set_onto(&set, &base);
        assert_eq!(
            g3b_effect_of(&out.state, measure.id),
            Some(OperationEffect::Applied),
            "M30: the base-seeded local override must be visible, not the region default"
        );
    }

    /// (M31a) A prospective grid/meter-change override — the grid a
    /// restoration WOULD install — must govern the reconstruction, standing
    /// in for the chain's own (older) recorded state without mutating it.
    #[test]
    fn g3b_grid_oracle_prospective_overrides_govern() {
        let op_set = OperationSet::new();
        let mut r = Reducer::new(&op_set);
        let region = RegionId::new(ReplicaId(1), 1);
        let instance = StaffInstanceId::new(ReplicaId(1), 2);
        let sig_current = TimeSignatureId::new(ReplicaId(1), 10);
        let sig_prospective = TimeSignatureId::new(ReplicaId(1), 11);

        let mut whole_chain = WriteChain::new();
        whole_chain.seed(Some(MetricGrid {
            meter_sequence: vec![MeterChange {
                anchor: g3b_region_anchor(region, 0),
                time_signature: sig_current,
            }],
        }));
        r.metric_grid_chain.insert(region, whole_chain);

        let prospective_sequence = vec![MeterChange {
            anchor: g3b_region_anchor(region, 0),
            time_signature: sig_prospective,
        }];
        let prospective_grid = Some(MetricGrid {
            meter_sequence: prospective_sequence.clone(),
        });
        let with_override = r.effective_grid(
            instance,
            Some(region),
            Some(&prospective_grid),
            &BTreeMap::new(),
        );
        assert_eq!(
            with_override, prospective_sequence,
            "M31a: the prospective whole-grid override must govern the reconstruction"
        );

        // The chain itself is untouched — a second call with no override
        // still sees the CURRENT (unrestored) state.
        let without_override = r.effective_grid(instance, Some(region), None, &BTreeMap::new());
        assert_eq!(
            without_override,
            vec![MeterChange {
                anchor: g3b_region_anchor(region, 0),
                time_signature: sig_current,
            }],
            "a prospective override must not mutate the chain"
        );

        // Prospective per-key override, same idea.
        let key = MusicalPosition(RationalTime::from_int(0));
        let mut overrides = BTreeMap::new();
        overrides.insert(
            key,
            Some(MeterChange {
                anchor: g3b_region_anchor(region, 0),
                time_signature: sig_prospective,
            }),
        );
        let with_key_override = r.effective_grid(instance, Some(region), None, &overrides);
        assert_eq!(
            with_key_override,
            vec![MeterChange {
                anchor: g3b_region_anchor(region, 0),
                time_signature: sig_prospective,
            }],
            "M31a: a prospective per-key override must also govern"
        );
    }

    /// The shared G3b aggregate-tie fixture (repair 4,
    /// `spec/CONTRACT_GENESIS_G3B_MEASURE.md` pin 6c): every envelope needed
    /// to reach a SINGLE undo that restores both a whole-grid write and a
    /// per-key meter-change write at the SAME position, under the SAME undo
    /// operation id.
    ///
    /// **Every counter is contiguous from 0 — no gaps.** The prior fixture
    /// jumped 3 → 10 → 11 → 12 → 20 while still asserting `seen_r1` up
    /// through those higher counters; `compute_pending`'s
    /// missing-vector-predecessor rule (`reduce.rs` `first_missing_vector_predecessor`,
    /// ~8857ff) then held every op past a gap PENDING, so ops 11, 12 and 20
    /// (the transaction members and the undo) never reduced at all. The
    /// fixture that test built its "genuinely restored" claim on had, in
    /// fact, never run the transaction or the undo.
    ///
    /// **The full referential prerequisite chain is present.**
    /// `CreateInstrument` → `CreateStaff` → `CreateRegion` →
    /// `CreateStaffInstance`: `create_staff_instance` requires the carried
    /// instance's `staff` to be live once a graph is present
    /// (`reduce.rs:4129`ff), and `create_staff` in turn requires its
    /// `instrument` to be live (`reduce.rs:4236`ff). Skipping either left the
    /// prior fixture's `CreateStaffInstance` a silent `TargetMissing`.
    ///
    /// **Every `TimeSignature` a `SetMetricGrid` names in its literal grid is
    /// pre-minted.** `set_metric_grid` refuses a grid naming an undeclared
    /// signature (`reduce.rs:3137`ff), and `SetTimeSignature` is the only op
    /// that mints one — `SetMetricGrid`'s own literal content never does.
    /// `sig_whole_baseline` and `sig_whole_new` are minted (and then
    /// immediately cleared again) at a THROWAWAY position, distinct from
    /// `pos0`, so no residue survives into the grid content the two proof
    /// tests compare against.
    fn g3b_aggregate_tie_fixture() -> G3bAggregateFixture {
        let region = RegionId::new(ReplicaId(1), 1);
        let instance = StaffInstanceId::new(ReplicaId(1), 2);
        let staff = StaffId::new(ReplicaId(1), 3);
        let instrument = InstrumentId::new(ReplicaId(1), 4);
        let sig_whole_baseline = TimeSignatureId::new(ReplicaId(1), 10);
        let sig_perkey_baseline = TimeSignatureId::new(ReplicaId(1), 11);
        let sig_whole_new = TimeSignatureId::new(ReplicaId(1), 12);
        let sig_perkey_new = TimeSignatureId::new(ReplicaId(1), 13);
        let pos0 = g3b_region_anchor(region, 0);
        let throwaway = g3b_region_anchor(region, 1000);
        let tx = TransactionId::new(ReplicaId(1), 900);

        let create_instrument = prim_env(
            1,
            0,
            0,
            CausalContext::new(),
            OperationKind::CreateInstrument(CreateInstrumentOp {
                instrument: crate::valuegen::instrument(instrument),
            }),
        );
        let create_staff = prim_env(
            1,
            1,
            1,
            seen_r1(0),
            OperationKind::CreateStaff(CreateStaffOp {
                staff: crate::valuegen::staff(staff, instrument),
            }),
        );
        let create_region = prim_env(
            1,
            2,
            2,
            seen_r1(1),
            OperationKind::CreateRegion(CreateRegionOp {
                region: crate::valuegen::region(region),
            }),
        );
        let create_instance = prim_env(
            1,
            3,
            3,
            seen_r1(2),
            OperationKind::CreateStaffInstance(CreateStaffInstanceOp {
                region,
                instance: crate::valuegen::staff_instance(instance, staff),
            }),
        );
        // Mint `sig_whole_baseline`, `sig_whole_new`, and `sig_perkey_new`,
        // all at a THROWAWAY position distinct from `pos0` — then clear that
        // position back to `None` so none leaves a residual entry in the
        // region's default grid. Each `TimeSignature` object stays live once
        // minted regardless of whether its meter-change write is later
        // cleared.
        //
        // `sig_perkey_new` is pre-minted here (not left for the transaction
        // member below to mint fresh) so the transaction mints NOTHING:
        // `set_time_signature`'s mint step is a no-op re-carry once the
        // SAME `TimeSignature` value is already live (`reduce.rs:5180`ff,
        // the `identical` branch), so `tx_set_time_sig`'s later carry of
        // this exact value registers no `tx_minted` target. With nothing
        // minted inside the transaction, its undo has nothing to
        // tombstone/cascade-delete, and reduces to a clean `Applied` rather
        // than `AppliedWithRepair` — the fixture's own assertions require
        // exact equality with `Applied`, not merely "applied in some form".
        let perkey_new_value = crate::valuegen::time_signature(sig_perkey_new, 5);
        let mint_whole_baseline = prim_env(
            1,
            4,
            4,
            seen_r1(3),
            OperationKind::SetTimeSignature(SetTimeSignatureOp {
                region,
                anchor: throwaway.clone(),
                time_signature: Some(crate::valuegen::time_signature(sig_whole_baseline, 4)),
            }),
        );
        let mint_whole_new = prim_env(
            1,
            5,
            5,
            seen_r1(4),
            OperationKind::SetTimeSignature(SetTimeSignatureOp {
                region,
                anchor: throwaway.clone(),
                time_signature: Some(crate::valuegen::time_signature(sig_whole_new, 6)),
            }),
        );
        let mint_perkey_new = prim_env(
            1,
            6,
            6,
            seen_r1(5),
            OperationKind::SetTimeSignature(SetTimeSignatureOp {
                region,
                anchor: throwaway.clone(),
                time_signature: Some(perkey_new_value.clone()),
            }),
        );
        let clear_throwaway = prim_env(
            1,
            7,
            7,
            seen_r1(6),
            OperationKind::SetTimeSignature(SetTimeSignatureOp {
                region,
                anchor: throwaway.clone(),
                time_signature: None,
            }),
        );

        // Pre-transaction baseline: a whole-grid write, then a per-key write
        // that overlays it at pos0 — these establish the PREDECESSORS the
        // undo below will restore to.
        let set_grid_baseline = prim_env(
            1,
            8,
            8,
            seen_r1(7),
            OperationKind::SetMetricGrid(SetMetricGridOp {
                region,
                grid: Some(MetricGrid {
                    meter_sequence: vec![MeterChange {
                        anchor: pos0.clone(),
                        time_signature: sig_whole_baseline,
                    }],
                }),
            }),
        );
        let set_time_sig_baseline = prim_env(
            1,
            9,
            9,
            seen_r1(8),
            OperationKind::SetTimeSignature(SetTimeSignatureOp {
                region,
                anchor: pos0.clone(),
                time_signature: Some(crate::valuegen::time_signature(sig_perkey_baseline, 3)),
            }),
        );

        // The transaction: overwrites BOTH the whole grid and the per-key
        // change, at the SAME position, in one undoable unit.
        let decl = declare_transaction(1, 10, 10, seen_r1(9), tx);
        let tx_set_grid = tx_member(
            1,
            11,
            11,
            seen_r1(10),
            tx,
            OperationKind::SetMetricGrid(SetMetricGridOp {
                region,
                grid: Some(MetricGrid {
                    meter_sequence: vec![MeterChange {
                        anchor: pos0.clone(),
                        time_signature: sig_whole_new,
                    }],
                }),
            }),
        );
        let tx_set_time_sig = tx_member(
            1,
            12,
            12,
            seen_r1(11),
            tx,
            OperationKind::SetTimeSignature(SetTimeSignatureOp {
                region,
                anchor: pos0.clone(),
                time_signature: Some(perkey_new_value),
            }),
        );
        let undo = undo_env(1, 13, 13, seen_r1(12), tx, UndoPolicy::StrictInverse);

        G3bAggregateFixture {
            create_instrument,
            create_staff,
            create_region,
            create_instance,
            mint_whole_baseline,
            mint_whole_new,
            mint_perkey_new,
            clear_throwaway,
            set_grid_baseline,
            set_time_sig_baseline,
            decl,
            tx_set_grid,
            tx_set_time_sig,
            undo,
            region,
            instance,
            sig_whole_baseline,
            sig_perkey_baseline,
            pos0,
        }
    }

    /// The G3b aggregate-tie fixture's envelopes plus the identifiers a
    /// caller needs to make assertions about the reduction — see
    /// [`g3b_aggregate_tie_fixture`].
    struct G3bAggregateFixture {
        create_instrument: OperationEnvelope,
        create_staff: OperationEnvelope,
        create_region: OperationEnvelope,
        create_instance: OperationEnvelope,
        mint_whole_baseline: OperationEnvelope,
        mint_whole_new: OperationEnvelope,
        mint_perkey_new: OperationEnvelope,
        clear_throwaway: OperationEnvelope,
        set_grid_baseline: OperationEnvelope,
        set_time_sig_baseline: OperationEnvelope,
        decl: OperationEnvelope,
        tx_set_grid: OperationEnvelope,
        tx_set_time_sig: OperationEnvelope,
        undo: OperationEnvelope,
        region: RegionId,
        instance: StaffInstanceId,
        sig_whole_baseline: TimeSignatureId,
        sig_perkey_baseline: TimeSignatureId,
        pos0: TimeAnchor,
    }

    impl G3bAggregateFixture {
        /// All fourteen envelopes in delivery order, each labeled for
        /// per-op failure messages — used to assert every one of them
        /// actually applied (not merely "not `TransactionConflict`") before
        /// any grid or oracle claim is trusted.
        fn labeled_envelopes(&self) -> Vec<(&'static str, OperationEnvelope)> {
            vec![
                ("CreateInstrument", self.create_instrument.clone()),
                ("CreateStaff", self.create_staff.clone()),
                ("CreateRegion", self.create_region.clone()),
                ("CreateStaffInstance", self.create_instance.clone()),
                (
                    "mint sig_whole_baseline (throwaway)",
                    self.mint_whole_baseline.clone(),
                ),
                (
                    "mint sig_whole_new (throwaway)",
                    self.mint_whole_new.clone(),
                ),
                (
                    "mint sig_perkey_new (throwaway)",
                    self.mint_perkey_new.clone(),
                ),
                ("clear throwaway per-key slot", self.clear_throwaway.clone()),
                ("SetMetricGrid baseline", self.set_grid_baseline.clone()),
                (
                    "SetTimeSignature baseline",
                    self.set_time_sig_baseline.clone(),
                ),
                ("DeclareTransaction", self.decl.clone()),
                ("tx SetMetricGrid member", self.tx_set_grid.clone()),
                ("tx SetTimeSignature member", self.tx_set_time_sig.clone()),
                ("UndoTransaction (StrictInverse)", self.undo.clone()),
            ]
        }
    }

    /// Asserts the fixture's `labeled` envelopes are ALL `Applied`, that
    /// `out.state.effects` has exactly one entry per accepted envelope (so a
    /// dropped/pending op fails loudly instead of silently vanishing), and
    /// that there are no conflicts and no anomalies. This is the point of
    /// repair 4: a fixture that silently fails to deliver, fails a
    /// prerequisite, conflicts a member, or skips the undo must go RED here
    /// — never pass vacuously on a stale prediction.
    fn g3b_assert_fixture_ran_cleanly(
        out: &GraphMaterialization,
        labeled: &[(&'static str, OperationEnvelope)],
        accepted_count: usize,
    ) {
        for (label, env) in labeled {
            assert_eq!(
                g3b_effect_of(&out.state, env.id),
                Some(OperationEffect::Applied),
                "fixture op `{label}` (id {:?}) must be Applied",
                env.id
            );
        }
        assert_eq!(
            out.state.effects.len(),
            accepted_count,
            "every accepted envelope must produce an effect entry — a \
             dropped (pending) op fails loudly here instead of silently \
             vanishing from the effect log"
        );
        assert!(
            out.state.conflicts.is_empty(),
            "no conflicts: {:?}",
            out.state.conflicts
        );
        assert!(
            out.state.anomalies.is_empty(),
            "no anomalies: {:?}",
            out.state.anomalies
        );
    }

    /// Repair 4 (`spec/CONTRACT_GENESIS_G3B_MEASURE.md` pin 6c): the
    /// PROSPECTIVE half of the aggregate-tie proof, now rebuilt on
    /// [`g3b_aggregate_tie_fixture`] so the "real undo" it compares against
    /// is a genuinely delivered, fully applied restoration — not a fixture
    /// three of whose eight envelopes silently never reduced. Both
    /// restorations tie under `Recency::Prospective` when evaluated in
    /// flight (pin 9c's aggregate safety check, before the undo commits).
    /// The ratified tie-break — on equal NON-`Base` recency, the per-key
    /// write governs — must make that PROSPECTIVE prediction agree with
    /// what restoration ACTUALLY installs once it runs for real: production
    /// code collects and applies every `metric_grid_chain` restoration
    /// before it begins `meter_change_chain` restorations
    /// (`collect_restorations`/`apply_restorations`, `reduce.rs` ~6418ff),
    /// so the per-key predecessor is written to the graph strictly AFTER
    /// the whole-grid predecessor, and must be what's left standing.
    ///
    /// See [`g3b_create_measure_after_undo_agrees_with_restored_per_key`]
    /// for the companion REAL-write proof of the same tie.
    #[test]
    fn g3b_grid_oracle_aggregate_prospective_restoration_matches_real_undo() {
        let fixture = g3b_aggregate_tie_fixture();
        let labeled = fixture.labeled_envelopes();
        let mut set = OperationSet::new();
        let envelopes: Vec<OperationEnvelope> =
            labeled.iter().map(|(_, env)| env.clone()).collect();
        let accepted_count = envelopes.len();
        set.accept_all(envelopes);
        let identity = IdentityContext::new(ReplicaId(1));
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        g3b_assert_fixture_ran_cleanly(&out, &labeled, accepted_count);

        // What restoration ACTUALLY installs: read the materialized graph.
        let region_value = out
            .score
            .canvas
            .regions
            .iter()
            .find(|r| r.id == fixture.region)
            .expect("region present");
        let installed = region_value
            .content
            .staff_based()
            .and_then(|c| c.default_metric_grid.as_ref())
            .expect("a default metric grid after restoration")
            .meter_sequence
            .clone();
        assert_eq!(
            installed,
            vec![MeterChange {
                anchor: fixture.pos0.clone(),
                time_signature: fixture.sig_perkey_baseline
            }],
            "actual restoration installs the whole-grid predecessor, then \
             overlays the per-key predecessor at pos0 (applied strictly \
             after) — the per-key value must be what the graph shows"
        );

        // The oracle's PROSPECTIVE prediction, evaluated as pin 9c's
        // aggregate safety check would (BEFORE the undo commits): both the
        // whole-grid and per-key restorations are simultaneously "in
        // flight" under the SAME undo, so both tie under
        // `Recency::Prospective`.
        let op_set = OperationSet::new();
        let r = Reducer::new(&op_set);
        let prospective_grid = Some(MetricGrid {
            meter_sequence: vec![MeterChange {
                anchor: fixture.pos0.clone(),
                time_signature: fixture.sig_whole_baseline,
            }],
        });
        let key = MusicalPosition(RationalTime::from_int(0));
        let mut meter_change_overrides = BTreeMap::new();
        meter_change_overrides.insert(
            key,
            Some(MeterChange {
                anchor: fixture.pos0.clone(),
                time_signature: fixture.sig_perkey_baseline,
            }),
        );
        let predicted = r.effective_grid(
            fixture.instance,
            Some(fixture.region),
            Some(&prospective_grid),
            &meter_change_overrides,
        );
        assert_eq!(
            predicted, installed,
            "the aggregate prospective evaluation must agree with what \
             restoration actually installs (pin 6c's ratified tie-break: on \
             equal non-Base recency, the per-key write governs — not only \
             for the prospective family; g3b_create_measure_after_undo_\
             agrees_with_restored_per_key proves the identical tie for REAL \
             writes)"
        );
    }

    /// Repair 4 (`spec/CONTRACT_GENESIS_G3B_MEASURE.md` pin 6c): the REAL
    /// half of the aggregate-tie proof — after the undo in
    /// [`g3b_aggregate_tie_fixture`] actually commits, a `CreateMeasure`
    /// whose `time_signature` is the restored PER-KEY signature
    /// (`sig_perkey_baseline`) must apply, exercising `create_measure`'s own
    /// agreement clause (`reduce.rs:5108`ff) against genuinely materialized
    /// state — not a synthetic prediction.
    ///
    /// Both restorations are recorded under the SAME undo operation id:
    /// `apply_restorations` (`reduce.rs:6562`ff) records every restoration
    /// it applies — the whole-grid one and the per-key one alike — with
    /// `env.id`, i.e. the undo's own id. Their `Recency::Write(..)` tuples
    /// are therefore equal too, once the undo has actually run — not merely
    /// while the restoration is still in flight. Only the WIDENED tie-break
    /// (equal NON-`Base` recency, not "equal `Prospective` recency")
    /// resolves this correctly; under the narrowed rule the whole-grid
    /// predecessor (`sig_whole_baseline`) would wrongly govern and this
    /// `CreateMeasure` would refuse `MeasureMeterMismatch`.
    #[test]
    fn g3b_create_measure_after_undo_agrees_with_restored_per_key() {
        let fixture = g3b_aggregate_tie_fixture();
        let labeled = fixture.labeled_envelopes();
        let measure_id = MeasureId::new(ReplicaId(1), 500);
        let measure = Measure {
            id: measure_id,
            // Shape c4 (pin 6): the same region id and `RegionEdge`, a
            // `Musical` offset — the SAME anchor the fixture's meter
            // changes are written at, so it is directly comparable.
            start: fixture.pos0.clone(),
            time_signature: Some(fixture.sig_perkey_baseline),
            explicit_number: None,
            number_visibility: epiphany_core::MeasureNumberVisibility::Auto,
        };
        let create = prim_env(
            1,
            14,
            14,
            seen_r1(13),
            OperationKind::CreateMeasure(CreateMeasureOp {
                instance: fixture.instance,
                measure,
            }),
        );

        let mut envelopes: Vec<OperationEnvelope> =
            labeled.iter().map(|(_, env)| env.clone()).collect();
        envelopes.push(create.clone());
        let accepted_count = envelopes.len();
        let mut set = OperationSet::new();
        set.accept_all(envelopes);
        let identity = IdentityContext::new(ReplicaId(1));
        let out = reduce_operation_set_onto(&set, &Score::empty(identity));

        g3b_assert_fixture_ran_cleanly(&out, &labeled, accepted_count);

        assert_eq!(
            g3b_effect_of(&out.state, create.id),
            Some(OperationEffect::Applied),
            "a CreateMeasure naming the restored PER-KEY signature must \
             apply — a real-write tie, not a synthetic prediction. Under \
             the narrowed (prospective-only) tie-break this refuses \
             MeasureMeterMismatch instead, because the whole-grid \
             predecessor (sig_whole_baseline) would wrongly govern"
        );

        let region_value = out
            .score
            .canvas
            .regions
            .iter()
            .find(|r| r.id == fixture.region)
            .expect("region present");
        let instance_value = region_value
            .content
            .staff_based()
            .and_then(|c| c.staff_instances.iter().find(|i| i.id == fixture.instance))
            .expect("instance present");
        assert!(
            instance_value.measures.iter().any(|m| m.id == measure_id),
            "the measure must reach the graph"
        );
    }

    /// (M30b) The effective-grid oracle consults ONLY the ledgers
    /// (`instance_grid`, `metric_grid_chain`, `meter_change_chain`) — never
    /// `self.graph` — so graph-aware and base-free reduction run the
    /// IDENTICAL reconstruction. Proven by deliberately desynchronizing a
    /// bare `Reducer`'s `graph` from its ledgers (something the real
    /// reduction paths never do — `set_metric_grid`/`create_staff_instance`
    /// always write both together) and confirming the oracle answers from
    /// the ledger, not the graph.
    #[test]
    fn g3b_grid_oracle_never_reads_self_graph() {
        let op_set = OperationSet::new();
        let mut r = Reducer::new(&op_set);
        let region = RegionId::new(ReplicaId(1), 1);
        let instance = StaffInstanceId::new(ReplicaId(1), 2);
        let sig_ledger = TimeSignatureId::new(ReplicaId(1), 10);
        let sig_graph_only = TimeSignatureId::new(ReplicaId(1), 11);

        let mut whole_chain = WriteChain::new();
        whole_chain.seed(Some(MetricGrid {
            meter_sequence: vec![MeterChange {
                anchor: g3b_region_anchor(region, 0),
                time_signature: sig_ledger,
            }],
        }));
        r.metric_grid_chain.insert(region, whole_chain);

        // A graph present, with a DIFFERENT (fictitious) default grid at the
        // same region/position — graph-aware mode's presence alone must not
        // change the answer.
        let mut instance_value =
            crate::valuegen::staff_instance(instance, StaffId::new(ReplicaId(1), 3));
        instance_value.local_metric_grid = None;
        let mut region_value = crate::valuegen::region(region);
        if let epiphany_core::RegionContent::StaffBased(content) = &mut region_value.content {
            content.staff_instances.push(instance_value);
            content.default_metric_grid = Some(MetricGrid {
                meter_sequence: vec![MeterChange {
                    anchor: g3b_region_anchor(region, 0),
                    time_signature: sig_graph_only,
                }],
            });
        }
        let mut score = Score::empty(IdentityContext::new(ReplicaId(1)));
        score.canvas.regions.push(region_value);
        r.graph = Some(score);

        assert_eq!(
            r.effective_grid(instance, Some(region), None, &BTreeMap::new()),
            vec![MeterChange {
                anchor: g3b_region_anchor(region, 0),
                time_signature: sig_ledger,
            }],
            "M30b: the oracle must answer from the ledger, never from self.graph, \
             even when a (deliberately desynchronized) graph is present"
        );
    }

    /// (M30c) Canonical write-order interleaving between `metric_grid_chain`
    /// and `meter_change_chain`, BOTH directions: a `SetTimeSignature`
    /// **before** a later `SetMetricGrid` (the whole-grid write supersedes
    /// the earlier per-key change), and **after** it (the per-key change
    /// overlays). End-to-end through the real operations, so the test does
    /// not encode its own assumptions about internal wiring.
    #[test]
    fn g3b_grid_oracle_canonical_write_order_both_interleavings() {
        let region1 = RegionId::new(ReplicaId(1), 1);
        let instance1 = StaffInstanceId::new(ReplicaId(1), 2);
        let region2 = RegionId::new(ReplicaId(1), 3);
        let instance2 = StaffInstanceId::new(ReplicaId(1), 4);
        let staff = StaffId::new(ReplicaId(1), 5);
        let sig_a = TimeSignatureId::new(ReplicaId(1), 10);
        let sig_b = TimeSignatureId::new(ReplicaId(1), 11);
        let sig_irrelevant = TimeSignatureId::new(ReplicaId(1), 12);

        fn ctx(seen_through: u64) -> CausalContext {
            CausalContext::new().with_seen(ReplicaId(1), seen_through)
        }

        let mut counter = 0u64;
        let mut next = |kind: OperationKind, seen_through: u64| -> (OperationEnvelope, u64) {
            let this_counter = counter;
            let env = prim_env(
                1,
                this_counter,
                this_counter as i64,
                ctx(seen_through),
                kind,
            );
            counter += 1;
            (env, this_counter)
        };

        let mut envs = Vec::new();
        let (env, c) = next(
            OperationKind::CreateRegion(CreateRegionOp {
                region: crate::valuegen::region(region1),
            }),
            0,
        );
        envs.push(env);
        let (env, c) = next(
            OperationKind::CreateStaffInstance(CreateStaffInstanceOp {
                region: region1,
                instance: crate::valuegen::staff_instance(instance1, staff),
            }),
            c,
        );
        envs.push(env);
        let (env, c) = next(
            OperationKind::CreateRegion(CreateRegionOp {
                region: crate::valuegen::region(region2),
            }),
            c,
        );
        envs.push(env);
        let (env, c) = next(
            OperationKind::CreateStaffInstance(CreateStaffInstanceOp {
                region: region2,
                instance: crate::valuegen::staff_instance(instance2, staff),
            }),
            c,
        );
        envs.push(env);
        // Mint sig_irrelevant, sig_a, sig_b once each, at throwaway positions
        // in region1, before the interleaving scenarios begin.
        let (env, c) = next(
            OperationKind::SetTimeSignature(SetTimeSignatureOp {
                region: region1,
                anchor: g3b_region_anchor(region1, 999),
                time_signature: Some(crate::valuegen::time_signature(sig_irrelevant, 3)),
            }),
            c,
        );
        envs.push(env);
        let (env, c) = next(
            OperationKind::SetTimeSignature(SetTimeSignatureOp {
                region: region1,
                anchor: g3b_region_anchor(region1, 998),
                time_signature: Some(crate::valuegen::time_signature(sig_a, 3)),
            }),
            c,
        );
        envs.push(env);
        let (env, c) = next(
            OperationKind::SetTimeSignature(SetTimeSignatureOp {
                region: region1,
                anchor: g3b_region_anchor(region1, 997),
                time_signature: Some(crate::valuegen::time_signature(sig_b, 3)),
            }),
            c,
        );
        envs.push(env);

        // --- Scenario 1 (region1): SetTimeSignature(pos 0, sig_a) BEFORE a
        // later SetMetricGrid(pos 0, sig_b) — the whole-grid write must
        // supersede the earlier per-key change.
        let (s1_set_time_sig, c) = next(
            OperationKind::SetTimeSignature(SetTimeSignatureOp {
                region: region1,
                anchor: g3b_region_anchor(region1, 0),
                time_signature: Some(crate::valuegen::time_signature(sig_a, 3)),
            }),
            c,
        );
        let (s1_set_grid, c) = next(
            OperationKind::SetMetricGrid(SetMetricGridOp {
                region: region1,
                grid: Some(MetricGrid {
                    meter_sequence: vec![MeterChange {
                        anchor: g3b_region_anchor(region1, 0),
                        time_signature: sig_b,
                    }],
                }),
            }),
            c,
        );
        let (s1_measure_expect_b, c) = next(
            OperationKind::CreateMeasure(CreateMeasureOp {
                instance: instance1,
                measure: Measure {
                    id: MeasureId::new(ReplicaId(1), 100),
                    start: g3b_region_anchor(region1, 0),
                    time_signature: Some(sig_b),
                    explicit_number: None,
                    number_visibility: epiphany_core::MeasureNumberVisibility::Auto,
                },
            }),
            c,
        );

        // --- Scenario 2 (region2): SetMetricGrid(pos 0, sig_a) BEFORE a
        // later SetTimeSignature(pos 0, sig_b) — the per-key change must
        // overlay the (now-superseded) whole grid.
        let (s2_set_grid, c) = next(
            OperationKind::SetMetricGrid(SetMetricGridOp {
                region: region2,
                grid: Some(MetricGrid {
                    meter_sequence: vec![MeterChange {
                        anchor: g3b_region_anchor(region2, 0),
                        time_signature: sig_a,
                    }],
                }),
            }),
            c,
        );
        let (s2_set_time_sig, c) = next(
            OperationKind::SetTimeSignature(SetTimeSignatureOp {
                region: region2,
                anchor: g3b_region_anchor(region2, 0),
                time_signature: Some(crate::valuegen::time_signature(sig_b, 3)),
            }),
            c,
        );
        let (s2_measure_expect_b, _c) = next(
            OperationKind::CreateMeasure(CreateMeasureOp {
                instance: instance2,
                measure: Measure {
                    id: MeasureId::new(ReplicaId(1), 101),
                    start: g3b_region_anchor(region2, 0),
                    time_signature: Some(sig_b),
                    explicit_number: None,
                    number_visibility: epiphany_core::MeasureNumberVisibility::Auto,
                },
            }),
            c,
        );

        envs.extend([
            s1_set_time_sig,
            s1_set_grid,
            s1_measure_expect_b.clone(),
            s2_set_grid,
            s2_set_time_sig,
            s2_measure_expect_b.clone(),
        ]);

        let mut set = OperationSet::new();
        set.accept_all(envs);
        let state = set.reduce();

        assert_eq!(
            g3b_effect_of(&state, s1_measure_expect_b.id),
            Some(OperationEffect::Applied),
            "scenario 1 (SetTimeSignature before SetMetricGrid): the LATER \
             whole-grid write (sig_b) must supersede the earlier per-key \
             change (sig_a)"
        );
        assert_eq!(
            g3b_effect_of(&state, s2_measure_expect_b.id),
            Some(OperationEffect::Applied),
            "scenario 2 (SetMetricGrid before SetTimeSignature): the LATER \
             per-key change (sig_b) must overlay the earlier whole-grid write \
             (sig_a)"
        );
    }

    /// (M21, M22, M32, M33) `CreateMeasure`'s append-only ordering (pin 9
    /// clause 1), agreement (clause 2), and boundary-distance (clause 3)
    /// checks — base-free, so only pin 8.1's ungated parent-liveness
    /// precondition applies and referent resolution (pin 8.3) is skipped.
    #[test]
    fn g3b_create_measure_ordering_agreement_boundary() {
        let region = RegionId::new(ReplicaId(1), 1);
        let staff = StaffId::new(ReplicaId(1), 2);
        let mut envs =
            g3b_region_and_instance_envs(1, region, StaffInstanceId::new(ReplicaId(1), 3), staff);

        let sig_a = TimeSignatureId::new(ReplicaId(1), 10);
        let sig_b = TimeSignatureId::new(ReplicaId(1), 11);
        // sig_a's measure_duration is 3/4 (numerator 3 over 4).
        let set_sig_a = prim_env(
            1,
            5,
            5,
            CausalContext::new(),
            OperationKind::SetTimeSignature(SetTimeSignatureOp {
                region,
                anchor: g3b_region_anchor(region, 0),
                time_signature: Some(crate::valuegen::time_signature(sig_a, 3)),
            }),
        );
        let set_sig_b = prim_env(
            1,
            6,
            6,
            CausalContext::new(),
            OperationKind::SetTimeSignature(SetTimeSignatureOp {
                region,
                anchor: g3b_region_anchor(region, 900),
                time_signature: Some(crate::valuegen::time_signature(sig_b, 5)),
            }),
        );
        envs.extend([set_sig_a.clone(), set_sig_b.clone()]);

        // A distinct StaffInstance per sub-scenario, all in the SAME region,
        // so they all see the SAME effective grid (sig_a at position 0,
        // duration 3/4) without interfering with each other's ordering.
        let instances: Vec<StaffInstanceId> = (10..17)
            .map(|n| StaffInstanceId::new(ReplicaId(1), n))
            .collect();
        for (n, id) in instances.iter().enumerate() {
            envs.push(prim_env(
                1,
                20 + n as u64,
                20 + n as i64,
                CausalContext::new(),
                OperationKind::CreateStaffInstance(CreateStaffInstanceOp {
                    region,
                    instance: crate::valuegen::staff_instance(*id, staff),
                }),
            ));
        }

        fn measure(id: u64, start: TimeAnchor, sig: Option<TimeSignatureId>) -> Measure {
            Measure {
                id: MeasureId::new(ReplicaId(1), id),
                start,
                time_signature: sig,
                explicit_number: None,
                number_visibility: epiphany_core::MeasureNumberVisibility::Auto,
            }
        }

        // Scenario 0: the first measure of instances[0] — clauses 1 & 3 are
        // vacuous; agreement (clause 2) still applies and passes.
        let first = g3b_measure_env(
            1,
            40,
            40,
            instances[0],
            measure(200, g3b_region_anchor(region, 0), Some(sig_a)),
        );

        // Scenario A (M21/M22): a second measure whose start is COMPARABLE
        // to the predecessor but not strictly after it — MeasureOutOfOrder.
        let base_first_a = g3b_measure_env(
            1,
            41,
            41,
            instances[1],
            measure(201, g3b_region_anchor(region, 0), Some(sig_a)),
        );
        let reversed = g3b_measure_env(
            1,
            42,
            42,
            instances[1],
            measure(202, g3b_region_anchor(region, -1), None),
        );

        // Scenario B: a second measure INCOMPARABLE to the predecessor
        // (different anchor shape entirely) — MeasureOrderUnverifiable.
        let base_first_b = g3b_measure_env(
            1,
            43,
            43,
            instances[2],
            measure(203, g3b_region_anchor(region, 0), Some(sig_a)),
        );
        let incomparable = g3b_measure_env(
            1,
            44,
            44,
            instances[2],
            measure(
                204,
                TimeAnchor::Event {
                    id: EventId::new(ReplicaId(1), 999),
                    offset: AnchorOffset::Musical(MusicalDuration(RationalTime::from_int(1))),
                },
                None,
            ),
        );

        // Scenario C: correct order, correct distance (3/4), agreeing
        // signature — Applied.
        let base_first_c = g3b_measure_env(
            1,
            45,
            45,
            instances[3],
            measure(205, g3b_region_anchor(region, 0), Some(sig_a)),
        );
        let correct = g3b_measure_env(
            1,
            46,
            46,
            instances[3],
            measure(
                206,
                TimeAnchor::Region {
                    id: region,
                    edge: RegionEdge::Start,
                    offset: AnchorOffset::Musical(MusicalDuration(
                        RationalTime::new(3, 4).unwrap(),
                    )),
                },
                Some(sig_a),
            ),
        );

        // Scenario D (M32): correct order and distance, but a DISAGREEING
        // signature — MeasureMeterMismatch.
        let base_first_d = g3b_measure_env(
            1,
            47,
            47,
            instances[4],
            measure(207, g3b_region_anchor(region, 0), Some(sig_a)),
        );
        let disagreeing = g3b_measure_env(
            1,
            48,
            48,
            instances[4],
            measure(
                208,
                TimeAnchor::Region {
                    id: region,
                    edge: RegionEdge::Start,
                    offset: AnchorOffset::Musical(MusicalDuration(
                        RationalTime::new(3, 4).unwrap(),
                    )),
                },
                Some(sig_b),
            ),
        );

        // Scenario E (M33): correct order, agreeing (`None`, inherits), but
        // the WRONG distance — MeasureMeterMismatch (the immediate-violation
        // gap: comparable, correctly ordered, agreeing, and still wrong).
        let base_first_e = g3b_measure_env(
            1,
            49,
            49,
            instances[5],
            measure(209, g3b_region_anchor(region, 0), Some(sig_a)),
        );
        let wrong_distance = g3b_measure_env(
            1,
            50,
            50,
            instances[5],
            measure(
                210,
                TimeAnchor::Region {
                    id: region,
                    edge: RegionEdge::Start,
                    offset: AnchorOffset::Musical(MusicalDuration(RationalTime::from_int(1))),
                },
                None,
            ),
        );

        envs.extend([
            first.clone(),
            base_first_a.clone(),
            reversed.clone(),
            base_first_b.clone(),
            incomparable.clone(),
            base_first_c.clone(),
            correct.clone(),
            base_first_d.clone(),
            disagreeing.clone(),
            base_first_e.clone(),
            wrong_distance.clone(),
        ]);

        let mut set = OperationSet::new();
        set.accept_all(envs);
        let state = set.reduce();

        assert_eq!(
            g3b_effect_of(&state, first.id),
            Some(OperationEffect::Applied),
            "the first measure of an instance: clauses 1 & 3 are vacuous"
        );
        assert_eq!(
            g3b_effect_of(&state, reversed.id),
            Some(OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::MeasureOutOfOrder
                }
            }),
            "M21/M22: a comparable-but-reversed start must be MeasureOutOfOrder \
             (not silently appended, and not the wrong reason)"
        );
        assert_eq!(
            g3b_effect_of(&state, incomparable.id),
            Some(OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::MeasureOrderUnverifiable
                }
            }),
            "an incomparable start must be MeasureOrderUnverifiable"
        );
        assert_eq!(
            g3b_effect_of(&state, correct.id),
            Some(OperationEffect::Applied),
            "correct order, correct distance, agreeing signature: Applied"
        );
        assert_eq!(
            g3b_effect_of(&state, disagreeing.id),
            Some(OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::MeasureMeterMismatch
                }
            }),
            "M32: a disagreeing signature must be MeasureMeterMismatch"
        );
        assert_eq!(
            g3b_effect_of(&state, wrong_distance.id),
            Some(OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::MeasureMeterMismatch
                }
            }),
            "M33: comparable, correctly ordered, agreeing (None inherits), and \
             STILL the wrong distance must be MeasureMeterMismatch — the \
             immediate-violation gap"
        );
    }

    /// Pin 4 (spec/CONTRACT_P13S19_PARTIAL.md): a pickup's successor is
    /// refused end-to-end, not merely read off the reducer's source. The
    /// pickup itself — first measure of the instance, `time_signature:
    /// None` so the agreement clause (clause 2, which is NOT
    /// predecessor-dependent) is avoided by declaration rather than by any
    /// first-measure exemption — mints `Applied`: clauses 1 and 3 are
    /// vacuous for it (no predecessor). Its successor, ALSO declaring
    /// `time_signature: None` (so its own clause 2 is out of the way and
    /// the refusal below cannot be clause 2's), starts only HALF a
    /// `measure_duration` after the pickup — the pickup's own actual
    /// (unmodelled) content length, not the governing signature's full
    /// whole-note bar — and clause 3 refuses it: `MeasureMeterMismatch`.
    /// The governing signature's own write and the pickup's mint are both
    /// asserted `Applied` before the refusal is asserted, so envelope
    /// counter gaps cannot make either op silently pending and pass the
    /// refusal off as something it isn't.
    #[test]
    fn g3b_create_measure_pickup_successor_refused_end_to_end() {
        let region = RegionId::new(ReplicaId(1), 90);
        let instance = StaffInstanceId::new(ReplicaId(1), 91);
        let staff = StaffId::new(ReplicaId(1), 92);
        let mut envs = g3b_region_and_instance_envs(1, region, instance, staff);

        let sig_a = TimeSignatureId::new(ReplicaId(1), 93);
        // numerator 4 -> measure_duration = 4/4 = one whole note ("a full bar").
        let set_sig_a = prim_env(
            1,
            2,
            2,
            CausalContext::new(),
            OperationKind::SetTimeSignature(SetTimeSignatureOp {
                region,
                anchor: g3b_region_anchor(region, 0),
                time_signature: Some(crate::valuegen::time_signature(sig_a, 4)),
            }),
        );
        envs.push(set_sig_a.clone());

        fn measure(id: u64, start: TimeAnchor, sig: Option<TimeSignatureId>) -> Measure {
            Measure {
                id: MeasureId::new(ReplicaId(1), id),
                start,
                time_signature: sig,
                explicit_number: None,
                number_visibility: epiphany_core::MeasureNumberVisibility::Auto,
            }
        }

        // The pickup: first measure, `None` (pin 4's fixture constraint —
        // `Some` of a disagreeing signature would be refused by clause 2
        // instead, for a reason that has nothing to do with partiality).
        let pickup = g3b_measure_env(
            1,
            3,
            3,
            instance,
            measure(400, g3b_region_anchor(region, 0), None),
        );

        // The successor: also `None`, so ITS clause 2 is equally out of the
        // way. Half a whole note after the pickup — not the full bar sig_a
        // demands.
        let successor = g3b_measure_env(
            1,
            4,
            4,
            instance,
            measure(
                401,
                TimeAnchor::Region {
                    id: region,
                    edge: RegionEdge::Start,
                    offset: AnchorOffset::Musical(MusicalDuration(
                        RationalTime::new(1, 2).unwrap(),
                    )),
                },
                None,
            ),
        );

        envs.extend([pickup.clone(), successor.clone()]);
        let mut set = OperationSet::new();
        set.accept_all(envs);
        let state = set.reduce();

        assert_eq!(
            g3b_effect_of(&state, set_sig_a.id),
            Some(OperationEffect::Applied),
            "the governing signature must itself be applied, or the refusal below proves nothing"
        );
        assert_eq!(
            g3b_effect_of(&state, pickup.id),
            Some(OperationEffect::Applied),
            "pin 1: the pickup itself is neither refused nor flagged — clauses 1 and 3 are \
             vacuous for a first measure, and clause 2 is avoided here by declaring `None`, \
             not by any first-measure exemption"
        );
        assert_eq!(
            g3b_effect_of(&state, successor.id),
            Some(OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::MeasureMeterMismatch
                }
            }),
            "pin 4: the pickup's successor is measured against the governing signature's FULL \
             measure_duration (one whole note), not the pickup's own half-note actual length — \
             clause 3 refuses it MeasureMeterMismatch, and (both sides declaring `None`) this \
             refusal cannot be clause 2's"
        );
    }

    /// Pin 2 (spec/CONTRACT_P13S19_PARTIAL.md): a mid-score partial measure
    /// — index >= 1, so it has no first-measure exemption at all — enters
    /// successfully, because the boundary check run when IT is created only
    /// examines the distance from ITS predecessor (`m0`, a full measure),
    /// never its own eventual length. The failure surfaces one measure
    /// later, on `m1`'s own successor (`m2`), whose distance from `m1`
    /// exposes `m1`'s actual (partial) length against the same governing
    /// signature's full `measure_duration()`.
    #[test]
    fn g3b_create_measure_mid_score_partial_successor_refused_end_to_end() {
        let region = RegionId::new(ReplicaId(1), 94);
        let instance = StaffInstanceId::new(ReplicaId(1), 95);
        let staff = StaffId::new(ReplicaId(1), 96);
        let mut envs = g3b_region_and_instance_envs(1, region, instance, staff);

        let sig_a = TimeSignatureId::new(ReplicaId(1), 97);
        // numerator 4 -> measure_duration = 4/4 = one whole note.
        let set_sig_a = prim_env(
            1,
            2,
            2,
            CausalContext::new(),
            OperationKind::SetTimeSignature(SetTimeSignatureOp {
                region,
                anchor: g3b_region_anchor(region, 0),
                time_signature: Some(crate::valuegen::time_signature(sig_a, 4)),
            }),
        );
        envs.push(set_sig_a.clone());

        fn measure(id: u64, start: TimeAnchor, sig: Option<TimeSignatureId>) -> Measure {
            Measure {
                id: MeasureId::new(ReplicaId(1), id),
                start,
                time_signature: sig,
                explicit_number: None,
                number_visibility: epiphany_core::MeasureNumberVisibility::Auto,
            }
        }

        // m0: an ordinary, FULL first measure — not itself a pickup, so
        // this scenario cannot be mistaken for pin 4's first-measure case.
        let m0 = g3b_measure_env(
            1,
            3,
            3,
            instance,
            measure(410, g3b_region_anchor(region, 0), None),
        );

        // m1: index 1, one full measure_duration after m0 — enters
        // successfully. This validates m0's implied length (full), NOT
        // m1's own eventual length; nothing examines that until m1 gets a
        // successor of its own. m1 is the mid-score partial: it has no
        // exemption from clauses 1/3 (it HAS a predecessor), it merely
        // happens to satisfy them here because m0 was full.
        let m1 = g3b_measure_env(
            1,
            4,
            4,
            instance,
            measure(
                411,
                TimeAnchor::Region {
                    id: region,
                    edge: RegionEdge::Start,
                    offset: AnchorOffset::Musical(MusicalDuration(RationalTime::from_int(1))),
                },
                None,
            ),
        );

        // m2: m1's successor, only HALF a measure_duration after m1 — m1's
        // own actual (partial) length, not sig_a's full bar. This is where
        // the partial duration surfaces, on the measure AFTER the partial
        // one, exactly as pin 2 describes.
        let m2 = g3b_measure_env(
            1,
            5,
            5,
            instance,
            measure(
                412,
                TimeAnchor::Region {
                    id: region,
                    edge: RegionEdge::Start,
                    offset: AnchorOffset::Musical(MusicalDuration(
                        RationalTime::new(3, 2).unwrap(),
                    )),
                },
                None,
            ),
        );

        envs.extend([m0.clone(), m1.clone(), m2.clone()]);
        let mut set = OperationSet::new();
        set.accept_all(envs);
        let state = set.reduce();

        assert_eq!(
            g3b_effect_of(&state, set_sig_a.id),
            Some(OperationEffect::Applied),
            "the governing signature must itself be applied, or nothing below proves anything"
        );
        assert_eq!(
            g3b_effect_of(&state, m0.id),
            Some(OperationEffect::Applied),
            "m0: an ordinary full first measure"
        );
        assert_eq!(
            g3b_effect_of(&state, m1.id),
            Some(OperationEffect::Applied),
            "pin 2: a mid-score partial measure enters successfully — its creation only checks \
             the distance from ITS predecessor (m0, full), never its own eventual length"
        );
        assert_eq!(
            g3b_effect_of(&state, m2.id),
            Some(OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::MeasureMeterMismatch
                }
            }),
            "pin 2: m1's successor is what exposes the partial duration — measured against the \
             governing signature's full measure_duration, not m1's own half-note actual length. \
             m1 has NO first-measure exemption (index 1, it HAS a predecessor); it simply \
             satisfied clause 3 because m0 happened to be full"
        );
    }

    /// Repair 2 (spec/CONTRACT_GENESIS_G3B_MEASURE.md pin 6c case 1 / pin 7):
    /// creating a measure against a WHOLLY EMPTY effective grid — no
    /// `local_metric_grid`, no region `default_metric_grid`, and no
    /// `SetMetricGrid`/`SetTimeSignature` writes anywhere — must Applied. No
    /// active signature means agreement is vacuous and the boundary clause
    /// abstains; neither is a violation.
    ///
    /// The original defect wrongly grouped `GoverningElement::None` with a
    /// disagreeing `Unique` in the agreement match (`MeasureMeterMismatch`),
    /// and collapsed `None` into `Indeterminate` for the boundary clause's
    /// `prev_duration`, so the final `_ => unverifiable()` arm fired
    /// (`MeasureOrderUnverifiable`) once a computable delta met a `None`
    /// duration.
    ///
    /// This is deliberately END-TO-END: the white-box selector test
    /// (`g3b_grid_oracle_governing_selection`) already exercises
    /// `governing_by_anchor`'s `None` outcome correctly in isolation — the
    /// bug was entirely in how `create_measure`'s caller handled that
    /// `None`, so only a real mint through the caller proves the fix.
    #[test]
    fn g3b_create_measure_applies_against_an_empty_effective_grid_end_to_end() {
        let region = RegionId::new(ReplicaId(1), 60);
        let instance = StaffInstanceId::new(ReplicaId(1), 61);
        let staff = StaffId::new(ReplicaId(1), 62);
        // No SetMetricGrid, no SetTimeSignature: the effective grid is
        // empty for the whole life of this test.
        let mut envs = g3b_region_and_instance_envs(1, region, instance, staff);

        fn measure(id: u64, start: TimeAnchor, sig: Option<TimeSignatureId>) -> Measure {
            Measure {
                id: MeasureId::new(ReplicaId(1), id),
                start,
                time_signature: sig,
                explicit_number: None,
                number_visibility: epiphany_core::MeasureNumberVisibility::Auto,
            }
        }

        // The first measure of the instance: clauses 1 & 3 are vacuous for
        // it regardless of Repair 2 (pin 9's pickup exemption), so it does
        // not by itself distinguish the bug from the fix.
        let first = g3b_measure_env(
            1,
            70,
            70,
            instance,
            measure(300, g3b_region_anchor(region, 0), None),
        );
        // The SECOND measure: comparable to, and a nonzero Musical delta
        // from, the first (c4 — same Region id and edge), AND declaring a
        // time signature — even though nothing ever wrote the grid. Under
        // the original bug, the agreement clause alone already refused
        // (`MeasureMeterMismatch`) before the boundary clause was reached;
        // dropping `time_signature` to `None` would additionally exercise
        // the boundary-only half of the same defect.
        let second = g3b_measure_env(
            1,
            71,
            71,
            instance,
            measure(
                301,
                TimeAnchor::Region {
                    id: region,
                    edge: RegionEdge::Start,
                    offset: AnchorOffset::Musical(MusicalDuration(RationalTime::from_int(4))),
                },
                Some(TimeSignatureId::new(ReplicaId(1), 999)),
            ),
        );

        envs.extend([first.clone(), second.clone()]);
        let mut set = OperationSet::new();
        set.accept_all(envs);
        let state = set.reduce();

        assert_eq!(
            g3b_effect_of(&state, first.id),
            Some(OperationEffect::Applied)
        );
        assert_eq!(
            g3b_effect_of(&state, second.id),
            Some(OperationEffect::Applied),
            "an empty effective grid (no active signature anywhere) must be \
             vacuous agreement and an abstaining boundary — NOT \
             MeasureMeterMismatch and NOT MeasureOrderUnverifiable \
             (pin 6c case 1 / pin 7)"
        );
    }

    // =============================================================================
    // Genesis tranche G3b packet 2 (`spec/CONTRACT_GENESIS_G3B_MEASURE.md`):
    // preservation (pin 9c, M41-M47).
    // =============================================================================

    #[cfg(test)]
    mod g3b_preservation_tests {
        use super::*;

        /// A minimal G3b preservation fixture (contract pin 9c): the full
        /// prerequisite chain, one active `TimeSignature` installed at `pos0`
        /// via `SetTimeSignature`, and two measures one whole note apart.
        /// `declared` controls whether the measures declare `Some(active)`
        /// (isolates the agreement clause — the boundary clause holds
        /// trivially, since a same-duration replacement never breaks it) or
        /// `None` (isolates the boundary clause, which `None` does not
        /// exempt). Contiguous counters from 0, `physical` stepped in
        /// lockstep, `seen_r1(prev)` chained, per the fixture discipline.
        struct G3bPreservationFixture {
            labeled: Vec<(&'static str, OperationEnvelope)>,
            region: RegionId,
            /// The id of the `SetTimeSignature`-installed active signature at
            /// `pos0` — not read by every test, but part of the fixture's
            /// documented shape.
            #[allow(dead_code)]
            active: TimeSignatureId,
            next_counter: u64,
            next_causal: CausalContext,
        }

        impl G3bPreservationFixture {
            /// Appends one more envelope, chaining the counter/causal-context
            /// bookkeeping automatically.
            fn push(&mut self, label: &'static str, kind: OperationKind) -> OperationEnvelope {
                let counter = self.next_counter;
                let env = prim_env(1, counter, counter as i64, self.next_causal.clone(), kind);
                self.labeled.push((label, env.clone()));
                self.next_counter += 1;
                self.next_causal = seen_r1(counter);
                env
            }

            /// Runs every envelope pushed so far, asserting every one EXCEPT
            /// the last `unchecked_tail` labeled envelopes is exactly
            /// `Applied` (the fixture discipline), with no conflicts/anomalies
            /// and no dropped (pending) op. Returns the materialization so the
            /// caller can inspect the tail envelopes' own effects.
            fn run(&self, unchecked_tail: usize) -> GraphMaterialization {
                let mut set = OperationSet::new();
                let envelopes: Vec<OperationEnvelope> =
                    self.labeled.iter().map(|(_, e)| e.clone()).collect();
                let accepted_count = envelopes.len();
                set.accept_all(envelopes);
                let identity = IdentityContext::new(ReplicaId(1));
                let out = reduce_operation_set_onto(&set, &Score::empty(identity));
                let clean_len = self.labeled.len() - unchecked_tail;
                g3b_assert_fixture_ran_cleanly(&out, &self.labeled[..clean_len], accepted_count);
                out
            }

            /// Appends one more envelope as a MEMBER of transaction `tx`,
            /// chaining the counter/causal-context bookkeeping exactly like
            /// [`Self::push`].
            fn push_tx(
                &mut self,
                label: &'static str,
                tx: TransactionId,
                kind: OperationKind,
            ) -> OperationEnvelope {
                let counter = self.next_counter;
                let env = tx_member(
                    1,
                    counter,
                    counter as i64,
                    self.next_causal.clone(),
                    tx,
                    kind,
                );
                self.labeled.push((label, env.clone()));
                self.next_counter += 1;
                self.next_causal = seen_r1(counter);
                env
            }

            /// Like [`Self::run`], but WITHOUT the global "no conflicts, no
            /// anomalies" assertion `g3b_assert_fixture_ran_cleanly` makes —
            /// for a fixture whose own TAIL envelope (the undo under test) is
            /// expected to conflict. Every envelope EXCEPT the last
            /// `unchecked_tail` is still asserted `Applied`, and every
            /// accepted envelope is still asserted to have produced an
            /// effect (no silently-dropped/pending op), so a setup failure
            /// still fails loudly — only the conflict-registry assertion is
            /// left to the caller, scoped to whatever it actually expects.
            fn run_allowing_tail_conflict(&self, unchecked_tail: usize) -> GraphMaterialization {
                let mut set = OperationSet::new();
                let envelopes: Vec<OperationEnvelope> =
                    self.labeled.iter().map(|(_, e)| e.clone()).collect();
                let accepted_count = envelopes.len();
                set.accept_all(envelopes);
                let identity = IdentityContext::new(ReplicaId(1));
                let out = reduce_operation_set_onto(&set, &Score::empty(identity));
                let clean_len = self.labeled.len() - unchecked_tail;
                for (label, env) in &self.labeled[..clean_len] {
                    assert_eq!(
                        g3b_effect_of(&out.state, env.id),
                        Some(OperationEffect::Applied),
                        "setup op `{label}` (id {:?}) must be Applied",
                        env.id
                    );
                }
                assert_eq!(
                    out.state.effects.len(),
                    accepted_count,
                    "every accepted envelope must produce an effect entry — a dropped \
                     (pending) op fails loudly here instead of silently vanishing"
                );
                assert!(
                    out.state.anomalies.is_empty(),
                    "no anomalies: {:?}",
                    out.state.anomalies
                );
                out
            }
        }

        fn g3b_preservation_fixture(declared: bool) -> G3bPreservationFixture {
            let region = RegionId::new(ReplicaId(1), 1);
            let instance = StaffInstanceId::new(ReplicaId(1), 2);
            let staff = StaffId::new(ReplicaId(1), 3);
            let instrument = InstrumentId::new(ReplicaId(1), 4);
            let active = TimeSignatureId::new(ReplicaId(1), 10);
            let pos0 = g3b_region_anchor(region, 0);
            let pos1 = g3b_region_anchor(region, 1);

            let mut f = G3bPreservationFixture {
                labeled: Vec::new(),
                region,
                active,
                next_counter: 0,
                next_causal: CausalContext::new(),
            };
            f.push(
                "CreateInstrument",
                OperationKind::CreateInstrument(CreateInstrumentOp {
                    instrument: crate::valuegen::instrument(instrument),
                }),
            );
            f.push(
                "CreateStaff",
                OperationKind::CreateStaff(CreateStaffOp {
                    staff: crate::valuegen::staff(staff, instrument),
                }),
            );
            f.push(
                "CreateRegion",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region),
                }),
            );
            f.push(
                "CreateStaffInstance",
                OperationKind::CreateStaffInstance(CreateStaffInstanceOp {
                    region,
                    instance: crate::valuegen::staff_instance(instance, staff),
                }),
            );
            f.push(
                "SetTimeSignature (install active at pos0)",
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region,
                    anchor: pos0.clone(),
                    time_signature: Some(crate::valuegen::time_signature(active, 4)),
                }),
            );
            let sig = if declared { Some(active) } else { None };
            f.push(
                "CreateMeasure m0",
                OperationKind::CreateMeasure(CreateMeasureOp {
                    instance,
                    measure: Measure {
                        id: MeasureId::new(ReplicaId(1), 100),
                        start: pos0,
                        time_signature: sig,
                        explicit_number: None,
                        number_visibility: Default::default(),
                    },
                }),
            );
            f.push(
                "CreateMeasure m1",
                OperationKind::CreateMeasure(CreateMeasureOp {
                    instance,
                    measure: Measure {
                        id: MeasureId::new(ReplicaId(1), 101),
                        start: pos1,
                        time_signature: sig,
                        explicit_number: None,
                        number_visibility: Default::default(),
                    },
                }),
            );
            f
        }

        fn measure_meter_mismatch_noop() -> OperationEffect {
            OperationEffect::NoOp {
                reason: NoOpReason::PreconditionFailedUnderReduction {
                    reason: PreconditionFailureReason::MeasureMeterMismatch,
                },
            }
        }

        /// M41: `SetMetricGrid`'s agreement precondition. `declared = true`
        /// baseline: m0/m1 both declare `Some(active)`. A whole-grid write
        /// naming a DIFFERENT (but SAME-duration) signature at `pos0` disagrees
        /// with m0's declared signature while leaving boundary distance intact
        /// (same duration) — isolating the agreement clause.
        #[test]
        fn m41_set_metric_grid_preserves_agreement() {
            let mut f = g3b_preservation_fixture(true);
            let replacement = TimeSignatureId::new(ReplicaId(1), 20);
            let throwaway = g3b_region_anchor(f.region, 1000);
            f.push(
                "mint replacement (throwaway)",
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region: f.region,
                    anchor: throwaway.clone(),
                    time_signature: Some(crate::valuegen::time_signature(replacement, 4)),
                }),
            );
            f.push(
                "clear throwaway",
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region: f.region,
                    anchor: throwaway,
                    time_signature: None,
                }),
            );
            let disruptive = f.push(
                "SetMetricGrid (disagreeing whole grid)",
                OperationKind::SetMetricGrid(SetMetricGridOp {
                    region: f.region,
                    grid: Some(MetricGrid {
                        meter_sequence: vec![MeterChange {
                            anchor: g3b_region_anchor(f.region, 0),
                            time_signature: replacement,
                        }],
                    }),
                }),
            );
            let out = f.run(1);
            assert_eq!(
                g3b_effect_of(&out.state, disruptive.id),
                Some(measure_meter_mismatch_noop()),
                "a whole-grid write that disagrees with an existing measure's declared \
             signature must refuse with MeasureMeterMismatch"
            );
        }

        /// M42: `SetMetricGrid`'s boundary precondition. `declared = false`
        /// baseline (agreement can never fire): a whole-grid write installing a
        /// DIFFERENT-DURATION signature at `pos0` makes m0-to-m1's one-whole-note
        /// distance wrong under the new governing duration.
        #[test]
        fn m42_set_metric_grid_preserves_boundary() {
            let mut f = g3b_preservation_fixture(false);
            let short = TimeSignatureId::new(ReplicaId(1), 21);
            let throwaway = g3b_region_anchor(f.region, 1000);
            f.push(
                "mint short-duration replacement (throwaway)",
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region: f.region,
                    anchor: throwaway.clone(),
                    // numerator 2 => measure_duration 2/4 = half a whole note.
                    time_signature: Some(crate::valuegen::time_signature(short, 2)),
                }),
            );
            f.push(
                "clear throwaway",
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region: f.region,
                    anchor: throwaway,
                    time_signature: None,
                }),
            );
            let disruptive = f.push(
                "SetMetricGrid (shorter-duration whole grid)",
                OperationKind::SetMetricGrid(SetMetricGridOp {
                    region: f.region,
                    grid: Some(MetricGrid {
                        meter_sequence: vec![MeterChange {
                            anchor: g3b_region_anchor(f.region, 0),
                            time_signature: short,
                        }],
                    }),
                }),
            );
            let out = f.run(1);
            assert_eq!(
                g3b_effect_of(&out.state, disruptive.id),
                Some(measure_meter_mismatch_noop()),
                "a whole-grid write whose new governing duration no longer matches an \
             existing measure boundary's distance must refuse with MeasureMeterMismatch"
            );
        }

        /// M43: `SetTimeSignature`'s agreement precondition. Same shape as M41,
        /// but the disruptive write is the per-key `SetTimeSignature` itself
        /// (self-minting its replacement — no separate pre-mint needed).
        #[test]
        fn m43_set_time_signature_preserves_agreement() {
            let mut f = g3b_preservation_fixture(true);
            let replacement = TimeSignatureId::new(ReplicaId(1), 22);
            let disruptive = f.push(
                "SetTimeSignature (disagreeing replacement at pos0)",
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region: f.region,
                    anchor: g3b_region_anchor(f.region, 0),
                    time_signature: Some(crate::valuegen::time_signature(replacement, 4)),
                }),
            );
            let out = f.run(1);
            assert_eq!(
                g3b_effect_of(&out.state, disruptive.id),
                Some(measure_meter_mismatch_noop()),
                "a per-key write that disagrees with an existing measure's declared \
             signature must refuse with MeasureMeterMismatch"
            );
        }

        /// M44: `SetTimeSignature`'s boundary precondition. Same shape as M42,
        /// but the disruptive write is the per-key `SetTimeSignature` itself.
        #[test]
        fn m44_set_time_signature_preserves_boundary() {
            let mut f = g3b_preservation_fixture(false);
            let short = TimeSignatureId::new(ReplicaId(1), 23);
            let disruptive = f.push(
                "SetTimeSignature (shorter-duration replacement at pos0)",
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region: f.region,
                    anchor: g3b_region_anchor(f.region, 0),
                    time_signature: Some(crate::valuegen::time_signature(short, 2)),
                }),
            );
            let out = f.run(1);
            assert_eq!(
                g3b_effect_of(&out.state, disruptive.id),
                Some(measure_meter_mismatch_noop()),
                "a per-key write whose new governing duration no longer matches an \
             existing measure boundary's distance must refuse with MeasureMeterMismatch"
            );
        }

        /// M45: every invariant-20 check in `set_time_signature` MUST precede
        /// `mint_time_signature` — a refusal must leave NO RESIDUE: no entry in
        /// `objects`, none in the graph's `time_signatures`. (The third channel,
        /// the carried-value map `time_signature_values`, is private to
        /// `Reducer` and not observable after `run()` consumes it; per this
        /// codebase's ratified value-map discipline — every reader gates on
        /// `self.objects` first — an entry there with no `objects` counterpart
        /// is structurally inert, never read by any future decision.)
        #[test]
        fn m45_refused_set_time_signature_leaves_no_residue() {
            let mut f = g3b_preservation_fixture(true);
            let fresh = TimeSignatureId::new(ReplicaId(1), 999);
            let disruptive = f.push(
                "SetTimeSignature (disagreeing FRESH signature at pos0)",
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region: f.region,
                    anchor: g3b_region_anchor(f.region, 0),
                    time_signature: Some(crate::valuegen::time_signature(fresh, 4)),
                }),
            );
            let out = f.run(1);
            assert_eq!(
                g3b_effect_of(&out.state, disruptive.id),
                Some(measure_meter_mismatch_noop()),
                "the disruptive write must be refused"
            );
            assert!(
                !out.state
                    .objects
                    .contains_key(&TypedObjectId::TimeSignature(fresh)),
                "a refused SetTimeSignature must leave no residue in `objects` -- the fresh \
             signature must never have been minted"
            );
            assert!(
                !out.score.time_signatures.iter().any(|t| t.id == fresh),
                "a refused SetTimeSignature must leave no residue in the graph -- the fresh \
             signature must never have been pushed onto `score.time_signatures`"
            );
        }

        /// M46: aggregate restoration safety under `StrictInverse`/`Cascade`,
        /// evaluated on the WHOLE restoration set together — never
        /// per-restoration. Direct unit tests on `Reducer::aggregate_
        /// restorations_violate_invariant20` (bypassing the full undo/
        /// transaction machinery, whose OWN forward-path preservation checks
        /// -- M41-M44 -- would otherwise refuse a transaction that transiently
        /// disagrees mid-transaction, a different, already-covered concern).
        /// Two `MeterChange` restorations at DIFFERENT resolved positions,
        /// each comparable to the reference (`m0.start`, a `Zero`-offset
        /// anchor -- comparable to any clock) but built so the two directions
        /// below hold.
        #[test]
        fn m46_aggregate_restoration_safety_both_directions() {
            let region = RegionId::new(ReplicaId(1), 1);
            let instance = StaffInstanceId::new(ReplicaId(1), 2);
            let m0 = MeasureId::new(ReplicaId(1), 100);
            let m1 = MeasureId::new(ReplicaId(1), 101);
            let sig1 = TimeSignatureId::new(ReplicaId(1), 10);
            let sig2 = TimeSignatureId::new(ReplicaId(1), 11);
            let reference_start = TimeAnchor::Region {
                id: region,
                edge: RegionEdge::Start,
                offset: AnchorOffset::Zero,
            };
            // m1 one whole note after m0 -- the boundary distance every
            // scenario below checks against.
            let after_start = TimeAnchor::Region {
                id: region,
                edge: RegionEdge::Start,
                offset: AnchorOffset::Musical(MusicalDuration(RationalTime::from_int(1))),
            };

            // ---- Direction 1: individually safe, jointly UNSAFE (must
            // conflict). `sig1` (duration 1, correct) is anchored via a
            // Musical-clock Region anchor at position bucket 0; `sig2`
            // (duration 1, ALSO correct in isolation) via a WallClock-clock
            // Region anchor at position bucket 1. Both are individually
            // comparable to the Zero-offset reference (Zero is the additive
            // identity of whichever clock it is compared against, pin 6), but
            // mutually incomparable to EACH OTHER (Musical vs WallClock, pin
            // 6) -- so admitting only one is an unambiguous unique maximum,
            // while admitting BOTH makes selection indeterminate (pin 6c step
            // 3), which `invariant20_violation` treats as unsafe.
            {
                let op_set = OperationSet::new();
                let mut r = Reducer::new(&op_set);
                r.region_instances.insert(region, [instance].into());
                r.objects
                    .insert(TypedObjectId::StaffInstance(instance), ObjectState::Live);
                for (id, start) in [(m0, reference_start.clone()), (m1, after_start.clone())] {
                    r.objects
                        .insert(TypedObjectId::Measure(id), ObjectState::Live);
                    r.measure_values.insert(
                        id,
                        (
                            instance,
                            Measure {
                                id,
                                start,
                                time_signature: None,
                                explicit_number: None,
                                number_visibility: Default::default(),
                            },
                        ),
                    );
                }
                for sig in [sig1, sig2] {
                    r.objects
                        .insert(TypedObjectId::TimeSignature(sig), ObjectState::Live);
                    r.time_signature_values
                        .insert(sig, crate::valuegen::time_signature(sig, 4));
                }
                let pos0 = MusicalPosition(RationalTime::from_int(0));
                let pos1 = MusicalPosition(RationalTime::from_int(1));
                let restorations = vec![
                    ValueRestoration::MeterChange {
                        region,
                        position: pos0,
                        value: Some(MeterChange {
                            anchor: TimeAnchor::Region {
                                id: region,
                                edge: RegionEdge::Start,
                                offset: AnchorOffset::Musical(MusicalDuration(
                                    RationalTime::from_int(0),
                                )),
                            },
                            time_signature: sig1,
                        }),
                    },
                    ValueRestoration::MeterChange {
                        region,
                        position: pos1,
                        value: Some(MeterChange {
                            anchor: TimeAnchor::Region {
                                id: region,
                                edge: RegionEdge::Start,
                                offset: AnchorOffset::WallClock(WallClockDuration(0)),
                            },
                            time_signature: sig2,
                        }),
                    },
                ];
                assert!(
                    r.aggregate_restorations_violate_invariant20(&restorations),
                    "M46 direction 1: each restoration alone is safe, but the pairing is \
                 mutually incomparable (Musical vs WallClock) -- the WHOLE set, \
                 evaluated jointly, must be flagged unsafe (Indeterminate governing \
                 selection, pin 6c step 3), never accepted by a per-restoration \
                 evaluation"
                );
            }

            // ---- Direction 2: individually UNSAFE, jointly safe (must
            // apply). Each position's REAL current chain content is a
            // wrong-duration signature; each restoration ALONE leaves the
            // OTHER position's bad real content as the sole (and thus
            // governing) candidate -- unsafe. Restoring BOTH (to explicit
            // absence) empties the grid entirely, which is VACUOUS (pin 6c
            // case 1), not a violation.
            {
                let op_set = OperationSet::new();
                let mut r = Reducer::new(&op_set);
                r.region_instances.insert(region, [instance].into());
                r.objects
                    .insert(TypedObjectId::StaffInstance(instance), ObjectState::Live);
                for (id, start) in [(m0, reference_start.clone()), (m1, after_start.clone())] {
                    r.objects
                        .insert(TypedObjectId::Measure(id), ObjectState::Live);
                    r.measure_values.insert(
                        id,
                        (
                            instance,
                            Measure {
                                id,
                                start,
                                time_signature: None,
                                explicit_number: None,
                                number_visibility: Default::default(),
                            },
                        ),
                    );
                }
                r.objects
                    .insert(TypedObjectId::TimeSignature(sig1), ObjectState::Live);
                r.time_signature_values
                    .insert(sig1, crate::valuegen::time_signature(sig1, 2));

                let pos0 = MusicalPosition(RationalTime::from_int(0));
                let pos1 = MusicalPosition(RationalTime::from_int(1));
                let bad_musical = TimeAnchor::Region {
                    id: region,
                    edge: RegionEdge::Start,
                    offset: AnchorOffset::Musical(MusicalDuration(RationalTime::from_int(0))),
                };
                let bad_wallclock = TimeAnchor::Region {
                    id: region,
                    edge: RegionEdge::Start,
                    offset: AnchorOffset::WallClock(WallClockDuration(0)),
                };
                // The REAL (current, pre-undo) chain content at both keys:
                // wrong duration (1/2, not 1), each individually the sole
                // (unambiguous) governor if the OTHER position is restored to
                // absence instead.
                let mut chain0: WriteChain<Option<MeterChange>> = WriteChain::new();
                chain0.record(
                    OperationId::new(ReplicaId(1), 1),
                    None,
                    Some(MeterChange {
                        anchor: bad_musical,
                        time_signature: sig1,
                    }),
                );
                r.meter_change_chain.insert((region, pos0.clone()), chain0);
                let mut chain1: WriteChain<Option<MeterChange>> = WriteChain::new();
                chain1.record(
                    OperationId::new(ReplicaId(1), 2),
                    None,
                    Some(MeterChange {
                        anchor: bad_wallclock,
                        time_signature: sig1,
                    }),
                );
                r.meter_change_chain.insert((region, pos1.clone()), chain1);

                let restorations = vec![
                    ValueRestoration::MeterChange {
                        region,
                        position: pos0,
                        value: None,
                    },
                    ValueRestoration::MeterChange {
                        region,
                        position: pos1,
                        value: None,
                    },
                ];
                assert!(
                    !r.aggregate_restorations_violate_invariant20(&restorations),
                    "M46 direction 2: each restoration ALONE leaves the OTHER position's \
                 wrong-duration REAL content governing (individually unsafe), but \
                 removing BOTH empties the grid -- vacuous, not a violation -- so the \
                 WHOLE set, evaluated jointly, must be SAFE"
                );
            }
        }

        /// M47: `BestEffort`'s canonical-order greedy applies the safe subset.
        /// Reuses M46 direction 1's individually-safe/jointly-unsafe pair: in
        /// canonical (BTreeMap key) order, position 0's restoration is
        /// considered first and admitted (alone, it is clean); position 1's is
        /// considered next and REJECTED, because admitting it on top of the
        /// already-admitted position-0 restoration makes selection
        /// indeterminate. A naive per-restoration filter (each restoration
        /// checked independently, never against what has already been
        /// admitted) would admit BOTH.
        #[test]
        fn m47_best_effort_applies_only_the_documented_safe_subset() {
            let region = RegionId::new(ReplicaId(1), 1);
            let instance = StaffInstanceId::new(ReplicaId(1), 2);
            let m0 = MeasureId::new(ReplicaId(1), 100);
            let m1 = MeasureId::new(ReplicaId(1), 101);
            let sig1 = TimeSignatureId::new(ReplicaId(1), 10);
            let sig2 = TimeSignatureId::new(ReplicaId(1), 11);
            let reference_start = TimeAnchor::Region {
                id: region,
                edge: RegionEdge::Start,
                offset: AnchorOffset::Zero,
            };
            let after_start = TimeAnchor::Region {
                id: region,
                edge: RegionEdge::Start,
                offset: AnchorOffset::Musical(MusicalDuration(RationalTime::from_int(1))),
            };

            let op_set = OperationSet::new();
            let mut r = Reducer::new(&op_set);
            r.region_instances.insert(region, [instance].into());
            r.objects
                .insert(TypedObjectId::StaffInstance(instance), ObjectState::Live);
            for (id, start) in [(m0, reference_start), (m1, after_start)] {
                r.objects
                    .insert(TypedObjectId::Measure(id), ObjectState::Live);
                r.measure_values.insert(
                    id,
                    (
                        instance,
                        Measure {
                            id,
                            start,
                            time_signature: None,
                            explicit_number: None,
                            number_visibility: Default::default(),
                        },
                    ),
                );
            }
            for sig in [sig1, sig2] {
                r.objects
                    .insert(TypedObjectId::TimeSignature(sig), ObjectState::Live);
                r.time_signature_values
                    .insert(sig, crate::valuegen::time_signature(sig, 4));
            }

            let pos0 = MusicalPosition(RationalTime::from_int(0));
            let pos1 = MusicalPosition(RationalTime::from_int(1));
            let restorations = vec![
                ValueRestoration::MeterChange {
                    region,
                    position: pos0,
                    value: Some(MeterChange {
                        anchor: TimeAnchor::Region {
                            id: region,
                            edge: RegionEdge::Start,
                            offset: AnchorOffset::Musical(MusicalDuration(RationalTime::from_int(
                                0,
                            ))),
                        },
                        time_signature: sig1,
                    }),
                },
                ValueRestoration::MeterChange {
                    region,
                    position: pos1,
                    value: Some(MeterChange {
                        anchor: TimeAnchor::Region {
                            id: region,
                            edge: RegionEdge::Start,
                            offset: AnchorOffset::WallClock(WallClockDuration(0)),
                        },
                        time_signature: sig2,
                    }),
                },
            ];
            let safe = r.select_invariant20_safe_restorations(restorations);
            assert_eq!(
                safe.len(),
                1,
                "BestEffort's canonical-order greedy must admit EXACTLY ONE of the two \
             restorations -- a naive independent filter would admit both, since \
             each is individually safe"
            );
            match &safe[0] {
                ValueRestoration::MeterChange {
                    region: r,
                    position,
                    value: Some(change),
                } => {
                    assert_eq!(*r, region);
                    assert_eq!(*position, MusicalPosition(RationalTime::from_int(0)));
                    assert_eq!(
                        change.time_signature, sig1,
                        "the admitted restoration must be the FIRST one in canonical \
                     (position) order -- position 0's, naming sig1"
                    );
                }
                _ => panic!("expected the admitted restoration to be a MeterChange with a value"),
            }
        }

        /// Genesis tranche G3b packet 2, coordinator-directed follow-up:
        /// the direct-`Reducer` M46/M47 tests above sign the ALGORITHMS
        /// (`aggregate_restorations_violate_invariant20`,
        /// `select_invariant20_safe_restorations`), but nothing proved
        /// `undo_transaction` actually CALLS them — deleting the call site
        /// (replacing the `if
        /// self.aggregate_restorations_violate_invariant20(&restorations)`
        /// guard with `if false`, or replacing
        /// `self.select_invariant20_safe_restorations(restorations)` with
        /// the identity) left the whole workspace suite green, since the
        /// existing tests bypass `undo_transaction` entirely. These two
        /// close that gap end-to-end through the normal
        /// envelope/`OperationSet` path.
        ///
        /// Construction (avoids M41-M44's forward-path checks refusing a
        /// transiently-disagreeing transaction member): the measure is
        /// created AFTER the transaction commits, so nothing on the
        /// forward path ever disagrees — only the UNDO's restoration
        /// disagrees with the (already-live) measure. Shape: prerequisite
        /// chain, pre-minted `sig0`/`sig1`, a pre-transaction baseline
        /// whole grid G0 naming `sig0`, a transaction rewriting it to G1
        /// naming `sig1`, then (after the transaction) a `CreateMeasure`
        /// that agrees with G1. Undoing the transaction restores G0, which
        /// disagrees with the live measure.
        fn build_end_to_end_undo_setup() -> (
            G3bPreservationFixture,
            TransactionId,
            TimeSignatureId,
            TimeSignatureId,
        ) {
            let region = RegionId::new(ReplicaId(1), 1);
            let instance = StaffInstanceId::new(ReplicaId(1), 2);
            let staff = StaffId::new(ReplicaId(1), 3);
            let instrument = InstrumentId::new(ReplicaId(1), 4);
            let sig0 = TimeSignatureId::new(ReplicaId(1), 10);
            let sig1 = TimeSignatureId::new(ReplicaId(1), 11);
            let throwaway = g3b_region_anchor(region, 1000);
            let pos0 = g3b_region_anchor(region, 0);
            let tx = TransactionId::new(ReplicaId(1), 700);

            let mut f = G3bPreservationFixture {
                labeled: Vec::new(),
                region,
                active: sig0,
                next_counter: 0,
                next_causal: CausalContext::new(),
            };
            f.push(
                "CreateInstrument",
                OperationKind::CreateInstrument(CreateInstrumentOp {
                    instrument: crate::valuegen::instrument(instrument),
                }),
            );
            f.push(
                "CreateStaff",
                OperationKind::CreateStaff(CreateStaffOp {
                    staff: crate::valuegen::staff(staff, instrument),
                }),
            );
            f.push(
                "CreateRegion",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region),
                }),
            );
            f.push(
                "CreateStaffInstance",
                OperationKind::CreateStaffInstance(CreateStaffInstanceOp {
                    region,
                    instance: crate::valuegen::staff_instance(instance, staff),
                }),
            );
            f.push(
                "mint sig0 (throwaway)",
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region,
                    anchor: throwaway.clone(),
                    time_signature: Some(crate::valuegen::time_signature(sig0, 4)),
                }),
            );
            f.push(
                "clear throwaway (sig0)",
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region,
                    anchor: throwaway.clone(),
                    time_signature: None,
                }),
            );
            f.push(
                "mint sig1 (throwaway)",
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region,
                    anchor: throwaway.clone(),
                    time_signature: Some(crate::valuegen::time_signature(sig1, 4)),
                }),
            );
            f.push(
                "clear throwaway (sig1)",
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region,
                    anchor: throwaway,
                    time_signature: None,
                }),
            );
            f.push(
                "SetMetricGrid baseline G0 (sig0)",
                OperationKind::SetMetricGrid(SetMetricGridOp {
                    region,
                    grid: Some(MetricGrid {
                        meter_sequence: vec![MeterChange {
                            anchor: pos0.clone(),
                            time_signature: sig0,
                        }],
                    }),
                }),
            );
            f.push_tx(
                "DeclareTransaction",
                tx,
                OperationKind::DeclareTransaction(crate::payload::TransactionDescriptor {
                    id: tx,
                    label: String::from("g3b end-to-end undo integration"),
                    category: None,
                }),
            );
            f.push_tx(
                "tx SetMetricGrid (to G1/sig1)",
                tx,
                OperationKind::SetMetricGrid(SetMetricGridOp {
                    region,
                    grid: Some(MetricGrid {
                        meter_sequence: vec![MeterChange {
                            anchor: pos0.clone(),
                            time_signature: sig1,
                        }],
                    }),
                }),
            );
            f.push(
                "CreateMeasure m0 (agrees with G1)",
                OperationKind::CreateMeasure(CreateMeasureOp {
                    instance,
                    measure: Measure {
                        id: MeasureId::new(ReplicaId(1), 100),
                        start: pos0,
                        time_signature: Some(sig1),
                        explicit_number: None,
                        number_visibility: Default::default(),
                    },
                }),
            );
            (f, tx, sig0, sig1)
        }

        /// M46, end-to-end: `StrictInverse` undoing the transaction must
        /// CONFLICT — restoring G0 (`sig0`) disagrees with the live
        /// measure (which declares `sig1`, agreeing with G1). Deleting the
        /// `aggregate_restorations_violate_invariant20` call site in
        /// `undo_transaction` (replacing its `if` guard with `if false`)
        /// must make this go red (the undo would report `Applied`
        /// instead).
        #[test]
        fn m46_end_to_end_strict_inverse_conflicts_on_disagreeing_restoration() {
            let (mut f, tx, _sig0, _sig1) = build_end_to_end_undo_setup();
            let undo = undo_env(
                1,
                f.next_counter,
                f.next_counter as i64,
                f.next_causal.clone(),
                tx,
                UndoPolicy::StrictInverse,
            );
            f.labeled
                .push(("UndoTransaction (StrictInverse)", undo.clone()));

            let out = f.run_allowing_tail_conflict(1);
            let effect = g3b_effect_of(&out.state, undo.id);
            assert!(
                matches!(effect, Some(OperationEffect::Conflicted { .. })),
                "StrictInverse must CONFLICT when restoring the whole-grid predecessor \
                 (G0/sig0) would disagree with a live measure (which declares sig1, \
                 agreeing with G1) — got {effect:?}"
            );
            assert_eq!(
                out.state.conflicts.records().len(),
                1,
                "exactly one conflict — the undo's own — must be recorded"
            );
            // The graph must show the undo did NOT revert the grid: the
            // aggregate check refuses before `apply_restorations` runs.
            let region_value = out
                .score
                .canvas
                .regions
                .iter()
                .find(|r| r.id == f.region)
                .expect("region present");
            let sequence = region_value
                .content
                .staff_based()
                .and_then(|c| c.default_metric_grid.as_ref())
                .map(|g| g.meter_sequence.clone())
                .unwrap_or_default();
            assert_eq!(
                sequence,
                vec![MeterChange {
                    anchor: g3b_region_anchor(f.region, 0),
                    time_signature: _sig1,
                }],
                "a conflicted (refused) undo must leave the grid exactly as the \
                 transaction left it — G1/sig1, not reverted to G0/sig0"
            );
        }

        /// M47, end-to-end: `BestEffort` undoing the SAME transaction must
        /// apply the documented canonical-order-greedy safe subset. This
        /// scenario adds a SECOND, unrelated restoration (a per-key
        /// `SetTimeSignature` write at a position no measure references,
        /// freshly minted inside the transaction) that is vacuously safe
        /// alone: BestEffort must admit it (graph shows it removed after
        /// undo) while SKIPPING the whole-grid restoration (graph must
        /// still show `sig1` at pos0, NOT reverted to `sig0`). Replacing
        /// `select_invariant20_safe_restorations(restorations)`'s call
        /// site with the identity (`restorations` unchanged) must make
        /// this go red — it would apply BOTH, reverting pos0 to `sig0` and
        /// disagreeing with the live measure.
        #[test]
        fn m47_end_to_end_best_effort_applies_safe_subset_skips_unsafe() {
            let (mut f, tx, _sig0, sig1) = build_end_to_end_undo_setup();
            let sig_far = TimeSignatureId::new(ReplicaId(1), 12);
            let far_anchor = g3b_region_anchor(f.region, 50);
            f.push_tx(
                "tx SetTimeSignature (mint sig_far at a position no measure references)",
                tx,
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region: f.region,
                    anchor: far_anchor,
                    time_signature: Some(crate::valuegen::time_signature(sig_far, 4)),
                }),
            );
            let undo = undo_env(
                1,
                f.next_counter,
                f.next_counter as i64,
                f.next_causal.clone(),
                tx,
                UndoPolicy::BestEffort,
            );
            f.labeled
                .push(("UndoTransaction (BestEffort)", undo.clone()));

            let out = f.run_allowing_tail_conflict(1);
            let effect = g3b_effect_of(&out.state, undo.id);
            assert!(
                matches!(
                    effect,
                    Some(OperationEffect::Applied)
                        | Some(OperationEffect::AppliedWithRepair { .. })
                ),
                "BestEffort must never refuse wholesale — got {effect:?}"
            );
            assert!(
                out.state.conflicts.is_empty(),
                "BestEffort must not conflict"
            );
            let region_value = out
                .score
                .canvas
                .regions
                .iter()
                .find(|r| r.id == f.region)
                .expect("region present");
            let sequence = region_value
                .content
                .staff_based()
                .and_then(|c| c.default_metric_grid.as_ref())
                .map(|g| g.meter_sequence.clone())
                .unwrap_or_default();
            assert_eq!(
                sequence,
                vec![MeterChange {
                    anchor: g3b_region_anchor(f.region, 0),
                    time_signature: sig1,
                }],
                "BestEffort's canonical-order greedy must SKIP the disagreeing \
                 whole-grid restoration (G0/sig0) — pos0 must still show sig1, the \
                 transaction's own write, unreverted"
            );
        }
    }

    /// Genesis tranche G3b, packet 3a (`spec/CONTRACT_GENESIS_G3B_MEASURE.md`
    /// pin 10, mutations M48-M63): the undo surfaces. `materialize_graph_
    /// tombstones`'s `Measure` arm, the `Measure` strand guard across all
    /// seven inbound surface classes, the `TimeSignature` extension, and
    /// post-undo re-create ordering.
    #[cfg(test)]
    mod g3b_undo_surface_tests {
        use super::*;
        use epiphany_core::{RepeatKind, SpanStyle, Spanner, SpannerId, SpannerKind, Tempo};

        /// Minimal G3b undo-surface fixture: the full prerequisite chain
        /// (CreateInstrument -> CreateStaff -> CreateRegion ->
        /// CreateStaffInstance), non-transactional, followed by a
        /// single-member transaction `tx` that mints one bare `Measure`
        /// (`time_signature: None`, so agreement/boundary are vacuous — the
        /// first measure of the instance). Contiguous counters from 0,
        /// `physical` stepped in lockstep, `seen_r1(prev)` chained, per the
        /// fixture discipline.
        struct G3bUndoFixture {
            labeled: Vec<(&'static str, OperationEnvelope)>,
            region: RegionId,
            instance: StaffInstanceId,
            measure: MeasureId,
            tx: TransactionId,
            next_counter: u64,
            next_causal: CausalContext,
        }

        impl G3bUndoFixture {
            fn push(&mut self, label: &'static str, kind: OperationKind) -> OperationEnvelope {
                let counter = self.next_counter;
                let env = prim_env(1, counter, counter as i64, self.next_causal.clone(), kind);
                self.labeled.push((label, env.clone()));
                self.next_counter += 1;
                self.next_causal = seen_r1(counter);
                env
            }

            fn push_tx(&mut self, label: &'static str, kind: OperationKind) -> OperationEnvelope {
                let counter = self.next_counter;
                let env = tx_member(
                    1,
                    counter,
                    counter as i64,
                    self.next_causal.clone(),
                    self.tx,
                    kind,
                );
                self.labeled.push((label, env.clone()));
                self.next_counter += 1;
                self.next_causal = seen_r1(counter);
                env
            }

            fn push_undo(&mut self, label: &'static str, policy: UndoPolicy) -> OperationEnvelope {
                let counter = self.next_counter;
                let env = undo_env(
                    1,
                    counter,
                    counter as i64,
                    self.next_causal.clone(),
                    self.tx,
                    policy,
                );
                self.labeled.push((label, env.clone()));
                self.next_counter += 1;
                self.next_causal = seen_r1(counter);
                env
            }

            /// Runs every envelope pushed so far against an empty base,
            /// asserting every envelope EXCEPT the last `unchecked_tail` is
            /// exactly `Applied`, that every accepted envelope produced an
            /// effect entry (no silently dropped/pending op), and that there
            /// are no anomalies — the fixture discipline. Returns the
            /// materialization so the caller can inspect the tail
            /// envelope(s)' own effect.
            fn run_allowing_tail_conflict(&self, unchecked_tail: usize) -> GraphMaterialization {
                self.run_onto(
                    &Score::empty(IdentityContext::new(ReplicaId(1))),
                    unchecked_tail,
                )
            }

            /// Like [`Self::run_allowing_tail_conflict`], but onto a caller-
            /// supplied base graph (for the restoration-direction fixtures,
            /// which inject a base-seeded value the operations never mint).
            fn run_onto(&self, base: &Score, unchecked_tail: usize) -> GraphMaterialization {
                let mut set = OperationSet::new();
                let envelopes: Vec<OperationEnvelope> =
                    self.labeled.iter().map(|(_, e)| e.clone()).collect();
                let accepted_count = envelopes.len();
                set.accept_all(envelopes);
                let out = reduce_operation_set_onto(&set, base);
                let clean_len = self.labeled.len() - unchecked_tail;
                for (label, env) in &self.labeled[..clean_len] {
                    assert_eq!(
                        g3b_effect_of(&out.state, env.id),
                        Some(OperationEffect::Applied),
                        "setup op `{label}` (id {:?}) must be Applied",
                        env.id
                    );
                }
                assert_eq!(
                    out.state.effects.len(),
                    accepted_count,
                    "every accepted envelope must produce an effect entry — a \
                     dropped (pending) op fails loudly here instead of silently \
                     vanishing"
                );
                assert!(
                    out.state.anomalies.is_empty(),
                    "no anomalies: {:?}",
                    out.state.anomalies
                );
                out
            }
        }

        /// Builds the fixture through the target `CreateMeasure`, WITHOUT the
        /// closing `DeclareTransaction`/`CreateMeasure` pair applied yet — for
        /// callers that need to inject base-seeded state referencing the
        /// eventual measure id before minting it. Use [`g3b_undo_fixture`] for
        /// the common case.
        fn g3b_undo_fixture_prereqs_only() -> G3bUndoFixture {
            let region = RegionId::new(ReplicaId(1), 1);
            let instance = StaffInstanceId::new(ReplicaId(1), 2);
            let staff = StaffId::new(ReplicaId(1), 3);
            let instrument = InstrumentId::new(ReplicaId(1), 4);
            let measure = MeasureId::new(ReplicaId(1), 100);
            let tx = TransactionId::new(ReplicaId(1), 900);

            let mut f = G3bUndoFixture {
                labeled: Vec::new(),
                region,
                instance,
                measure,
                tx,
                next_counter: 0,
                next_causal: CausalContext::new(),
            };
            f.push(
                "CreateInstrument",
                OperationKind::CreateInstrument(CreateInstrumentOp {
                    instrument: crate::valuegen::instrument(instrument),
                }),
            );
            f.push(
                "CreateStaff",
                OperationKind::CreateStaff(CreateStaffOp {
                    staff: crate::valuegen::staff(staff, instrument),
                }),
            );
            f.push(
                "CreateRegion",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region),
                }),
            );
            f.push(
                "CreateStaffInstance",
                OperationKind::CreateStaffInstance(CreateStaffInstanceOp {
                    region,
                    instance: crate::valuegen::staff_instance(instance, staff),
                }),
            );
            f
        }

        /// The common fixture: prerequisites, then `tx` = {DeclareTransaction,
        /// CreateMeasure(measure)}.
        impl G3bUndoFixture {
            /// Opens the target transaction — `DeclareTransaction` then
            /// `CreateMeasure` of the fixture's own `measure` — as its first
            /// two members. MUST be called only after every non-tx op the
            /// transaction's LATER members will depend on: a transaction
            /// block reduces atomically at the canonical position of its
            /// EARLIEST member, so a non-member op canonically BETWEEN two
            /// members of this tx has not been applied yet when the block
            /// runs (found the hard way — see the `measure_values` M61 row's
            /// doc comment).
            fn open_target_tx(&mut self) {
                let region = self.region;
                let instance = self.instance;
                let measure = self.measure;
                let tx = self.tx;
                let pos0 = g3b_region_anchor(region, 0);
                self.push_tx(
                    "DeclareTransaction",
                    OperationKind::DeclareTransaction(crate::payload::TransactionDescriptor {
                        id: tx,
                        label: String::from("g3b undo surface"),
                        category: None,
                    }),
                );
                self.push_tx(
                    "CreateMeasure (target)",
                    OperationKind::CreateMeasure(CreateMeasureOp {
                        instance,
                        measure: Measure {
                            id: measure,
                            start: pos0,
                            time_signature: None,
                            explicit_number: None,
                            number_visibility: Default::default(),
                        },
                    }),
                );
            }
        }

        fn g3b_undo_fixture() -> G3bUndoFixture {
            let mut f = g3b_undo_fixture_prereqs_only();
            f.open_target_tx();
            f
        }

        fn measure_anchor(measure: MeasureId, position: MeasurePosition) -> TimeAnchor {
            TimeAnchor::Measure {
                id: measure,
                position,
                offset: AnchorOffset::Zero,
            }
        }

        fn assert_blocks(out: &GraphMaterialization, env: &OperationEnvelope, why: &str) {
            assert!(
                matches!(
                    g3b_effect_of(&out.state, env.id),
                    Some(OperationEffect::Conflicted { .. })
                ),
                "{why}: undo must be Conflicted, got {:?}",
                g3b_effect_of(&out.state, env.id)
            );
        }

        fn assert_undo_applied(out: &GraphMaterialization, env: &OperationEnvelope, why: &str) {
            assert!(
                matches!(
                    g3b_effect_of(&out.state, env.id),
                    Some(OperationEffect::Applied)
                        | Some(OperationEffect::AppliedWithRepair { .. })
                ),
                "{why}: undo must be Applied, got {:?}",
                g3b_effect_of(&out.state, env.id)
            );
        }

        fn bare_spanner(id: SpannerId, start: TimeAnchor, end: TimeAnchor) -> Spanner {
            Spanner {
                id,
                start,
                end,
                staves: Vec::new(),
                kind: SpannerKind::default(),
                style: SpanStyle::default(),
            }
        }

        fn bare_repeat(
            id: RepeatStructureId,
            start: TimeAnchor,
            end: TimeAnchor,
        ) -> RepeatStructure {
            RepeatStructure {
                id,
                start,
                end,
                kind: RepeatKind::SimpleRepeat { count: 2 },
                voltas: Vec::new(),
            }
        }

        fn bare_tempo_segment(start: TimeAnchor, end: Option<TimeAnchor>) -> TempoSegment {
            TempoSegment {
                start,
                end,
                start_tempo: Tempo::quarter(120.0).expect("positive finite bpm"),
                end_tempo: None,
                shape: TempoShape::Constant,
            }
        }

        // === M51-M58: each surface blocks a live outside referencer. =======

        /// (M51) A live `Spanner` anchored to the measure blocks its undo.
        #[test]
        fn m51_spanner_surface_blocks_measure_undo() {
            let mut f = g3b_undo_fixture();
            let sid = SpannerId::new(ReplicaId(1), 200);
            f.push(
                "CreateCrossCutting spanner->measure",
                OperationKind::CreateCrossCutting(CreateCrossCuttingOp {
                    structure: CrossCuttingValue::Spanner(bare_spanner(
                        sid,
                        measure_anchor(f.measure, MeasurePosition::Start),
                        measure_anchor(f.measure, MeasurePosition::End),
                    )),
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_blocks(&out, &undo, "a live spanner anchored to the measure");
        }

        /// (M52) A live `RepeatStructure` anchored to the measure blocks its
        /// undo (signs pin 10.4: `repeat_values`, not `cross_cutting_modify_
        /// chain`, since `CrossCuttingValue` has no `RepeatStructure`
        /// variant).
        #[test]
        fn m52_repeat_surface_blocks_measure_undo() {
            let mut f = g3b_undo_fixture();
            let rid = RepeatStructureId::new(ReplicaId(1), 201);
            f.push(
                "CreateRepeatStructure ->measure",
                OperationKind::CreateRepeatStructure(CreateRepeatStructureOp {
                    repeat: bare_repeat(
                        rid,
                        measure_anchor(f.measure, MeasurePosition::Start),
                        measure_anchor(f.measure, MeasurePosition::End),
                    ),
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_blocks(
                &out,
                &undo,
                "a live repeat structure anchored to the measure",
            );
        }

        /// (M53) A repeat structure present in the BASE graph (not minted by
        /// any operation) still blocks the measure's undo — exercises
        /// `repeat_values`'s BASE-SEED site (`seed_from_graph`), distinct
        /// from the create-insertion site M52 exercises.
        #[test]
        fn m53_base_seeded_repeat_blocks_measure_undo() {
            let prereqs = g3b_undo_fixture_prereqs_only();
            let mut base = prereqs.run_allowing_tail_conflict(0).score;
            let rid = RepeatStructureId::new(ReplicaId(1), 201);
            base.cross_cutting.repeats.push(bare_repeat(
                rid,
                measure_anchor(prereqs.measure, MeasurePosition::Start),
                measure_anchor(prereqs.measure, MeasurePosition::End),
            ));

            let mut f = g3b_fixture_onto(&prereqs);
            f.open_target_tx();
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_onto(&base, 1);
            assert_blocks(
                &out,
                &undo,
                "a base-seeded repeat anchored to the measure must block",
            );
        }

        /// (M54) A live measure C, in a SECOND staff instance so ordering is
        /// vacuous, whose `start` anchors to the measure under test blocks
        /// its undo (`measure_values`).
        #[test]
        fn m54_measure_values_surface_blocks_measure_undo() {
            let mut f = g3b_undo_fixture();
            let instance2 = StaffInstanceId::new(ReplicaId(1), 5);
            let staff = StaffId::new(ReplicaId(1), 3);
            let c = MeasureId::new(ReplicaId(1), 101);
            f.push(
                "CreateStaffInstance 2",
                OperationKind::CreateStaffInstance(CreateStaffInstanceOp {
                    region: f.region,
                    instance: crate::valuegen::staff_instance(instance2, staff),
                }),
            );
            f.push(
                "CreateMeasure C -> measure (instance2, first measure: vacuous order)",
                OperationKind::CreateMeasure(CreateMeasureOp {
                    instance: instance2,
                    measure: Measure {
                        id: c,
                        start: measure_anchor(f.measure, MeasurePosition::Start),
                        time_signature: None,
                        explicit_number: None,
                        number_visibility: Default::default(),
                    },
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_blocks(
                &out,
                &undo,
                "a live measure whose start anchors to the measure",
            );
        }

        /// (M55) A live meter change, owned by a SECOND (empty) region, whose
        /// anchor names the measure under test blocks its undo
        /// (`meter_change_chain`).
        #[test]
        fn m55_meter_change_surface_blocks_measure_undo() {
            let mut f = g3b_undo_fixture();
            let region2 = RegionId::new(ReplicaId(1), 6);
            let sig = TimeSignatureId::new(ReplicaId(1), 300);
            f.push(
                "CreateRegion 2 (empty)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            f.push(
                "SetTimeSignature region2 -> measure",
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region: region2,
                    anchor: measure_anchor(f.measure, MeasurePosition::Start),
                    time_signature: Some(crate::valuegen::time_signature(sig, 4)),
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_blocks(&out, &undo, "a live meter change anchored to the measure");
        }

        /// (M56) A live user system-break whose anchor names the measure
        /// under test blocks its undo (`break_chain`).
        #[test]
        fn m56_system_break_surface_blocks_measure_undo() {
            let mut f = g3b_undo_fixture();
            let region2 = RegionId::new(ReplicaId(1), 6);
            f.push(
                "CreateRegion 2 (empty)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            f.push(
                "SetUserSystemBreak region2 -> measure",
                OperationKind::SetUserSystemBreak(crate::payload::SetUserSystemBreakOp {
                    region: region2,
                    anchor: measure_anchor(f.measure, MeasurePosition::Start),
                    present: true,
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_blocks(&out, &undo, "a live system break anchored to the measure");
        }

        /// (M57) A live user page-break whose anchor names the measure under
        /// test blocks its undo (`page_break_chain`).
        #[test]
        fn m57_page_break_surface_blocks_measure_undo() {
            let mut f = g3b_undo_fixture();
            let region2 = RegionId::new(ReplicaId(1), 6);
            f.push(
                "CreateRegion 2 (empty)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            f.push(
                "SetUserPageBreak region2 -> measure",
                OperationKind::SetUserPageBreak(SetUserPageBreakOp {
                    region: region2,
                    anchor: measure_anchor(f.measure, MeasurePosition::Start),
                    present: true,
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_blocks(&out, &undo, "a live page break anchored to the measure");
        }

        /// (M58, site 1/2: `start`) A live REGION-SCOPED tempo segment whose
        /// `start` anchor names the measure blocks its undo.
        #[test]
        fn m58_tempo_segment_region_scoped_start_blocks_measure_undo() {
            let mut f = g3b_undo_fixture();
            let region2 = RegionId::new(ReplicaId(1), 6);
            f.push(
                "CreateRegion 2 (empty)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            let start = measure_anchor(f.measure, MeasurePosition::Start);
            f.push(
                "SetTempoSegment region2 start -> measure",
                OperationKind::SetTempoSegment(SetTempoSegmentOp {
                    region: Some(region2),
                    start: start.clone(),
                    segment: Some(bare_tempo_segment(start, None)),
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_blocks(
                &out,
                &undo,
                "a live region-scoped tempo segment whose start anchors to the measure",
            );
        }

        /// (M58, site 2/2: `end`) A live REGION-SCOPED tempo segment whose
        /// `end` anchor (NOT `start`) names the measure still blocks its
        /// undo — a `start`-only guard would miss this.
        #[test]
        fn m58_tempo_segment_region_scoped_end_blocks_measure_undo() {
            let mut f = g3b_undo_fixture();
            let region2 = RegionId::new(ReplicaId(1), 6);
            f.push(
                "CreateRegion 2 (empty)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            // A `Measure` anchor resolves to `MusicalPosition::origin()`
            // (only `Region`+`Musical` gets special-cased), so `start` must
            // ALSO resolve to origin or `prospective_tempo_write_well_formed`
            // rejects the end as preceding the start.
            let start = g3b_region_anchor(region2, 0);
            let end = measure_anchor(f.measure, MeasurePosition::End);
            f.push(
                "SetTempoSegment region2 end -> measure",
                OperationKind::SetTempoSegment(SetTempoSegmentOp {
                    region: Some(region2),
                    start: start.clone(),
                    segment: Some(bare_tempo_segment(start, Some(end))),
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_blocks(
                &out,
                &undo,
                "a live region-scoped tempo segment whose end anchors to the measure",
            );
        }

        /// (M58, score-level `None`, both sites) A live SCORE-LEVEL
        /// (`region: None`) tempo segment naming the measure blocks its undo
        /// too, even though this key has no owner object at all.
        #[test]
        fn m58_tempo_segment_score_level_blocks_measure_undo() {
            for (label, start, end) in [
                (
                    "start",
                    measure_anchor(MeasureId::new(ReplicaId(1), 100), MeasurePosition::Start),
                    None,
                ),
                (
                    "end",
                    g3b_region_anchor(RegionId::new(ReplicaId(1), 1), 0),
                    Some(measure_anchor(
                        MeasureId::new(ReplicaId(1), 100),
                        MeasurePosition::End,
                    )),
                ),
            ] {
                let mut f = g3b_undo_fixture();
                f.push(
                    "SetTempoSegment score-level -> measure",
                    OperationKind::SetTempoSegment(SetTempoSegmentOp {
                        region: None,
                        start: start.clone(),
                        segment: Some(bare_tempo_segment(start, end)),
                    }),
                );
                let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
                let out = f.run_allowing_tail_conflict(1);
                assert_blocks(
                    &out,
                    &undo,
                    &format!(
                        "a live score-level tempo segment whose {label} anchors to the measure"
                    ),
                );
            }
        }

        // === M61: same-transaction teardown exempts all seven surfaces. ====
        //
        // The referencing structure (or its owning region) is minted by the
        // SAME transaction as the measure, so it is itself in `targets` and
        // the `!targets.contains(...)` conjunct excludes it — undo must NOT
        // block, and must tombstone everything.

        /// (M61, row 1/7: spanner) The spanner is minted in the same tx.
        #[test]
        fn m61_same_transaction_teardown_exempts_spanner() {
            let mut f = g3b_undo_fixture();
            let sid = SpannerId::new(ReplicaId(1), 200);
            f.push_tx(
                "CreateCrossCutting spanner (same tx)",
                OperationKind::CreateCrossCutting(CreateCrossCuttingOp {
                    structure: CrossCuttingValue::Spanner(bare_spanner(
                        sid,
                        measure_anchor(f.measure, MeasurePosition::Start),
                        measure_anchor(f.measure, MeasurePosition::End),
                    )),
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_undo_applied(&out, &undo, "same-tx spanner mint must not strand-block");
        }

        /// (M61, row 2/7: repeat) The repeat is minted in the same tx.
        #[test]
        fn m61_same_transaction_teardown_exempts_repeat() {
            let mut f = g3b_undo_fixture();
            let rid = RepeatStructureId::new(ReplicaId(1), 201);
            f.push_tx(
                "CreateRepeatStructure (same tx)",
                OperationKind::CreateRepeatStructure(CreateRepeatStructureOp {
                    repeat: bare_repeat(
                        rid,
                        measure_anchor(f.measure, MeasurePosition::Start),
                        measure_anchor(f.measure, MeasurePosition::End),
                    ),
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_undo_applied(&out, &undo, "same-tx repeat mint must not strand-block");
        }

        /// (M61, row 3/7: `measure_values`) The referencing measure C is
        /// minted in the same tx. `instance2` MUST be created before the
        /// transaction's EARLIEST member (`DeclareTransaction`), not merely
        /// before C's own `CreateMeasure`: a transaction block reduces
        /// atomically at the canonical position of its first member, so a
        /// non-member op canonically BETWEEN two tx members has not been
        /// applied yet when the block runs (found via this row going red
        /// with `TransactionConflict` before this fix).
        #[test]
        fn m61_same_transaction_teardown_exempts_measure_values() {
            let mut f = g3b_undo_fixture_prereqs_only();
            let instance2 = StaffInstanceId::new(ReplicaId(1), 5);
            let staff = StaffId::new(ReplicaId(1), 3);
            let c = MeasureId::new(ReplicaId(1), 101);
            f.push(
                "CreateStaffInstance 2",
                OperationKind::CreateStaffInstance(CreateStaffInstanceOp {
                    region: f.region,
                    instance: crate::valuegen::staff_instance(instance2, staff),
                }),
            );
            let measure = f.measure;
            f.open_target_tx();
            f.push_tx(
                "CreateMeasure C -> measure (same tx)",
                OperationKind::CreateMeasure(CreateMeasureOp {
                    instance: instance2,
                    measure: Measure {
                        id: c,
                        start: measure_anchor(measure, MeasurePosition::Start),
                        time_signature: None,
                        explicit_number: None,
                        number_visibility: Default::default(),
                    },
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_undo_applied(&out, &undo, "same-tx measure mint must not strand-block");
        }

        /// (M61, row 4/7: meter change) The owning region is minted in the
        /// same tx; the write itself need not be transactional.
        #[test]
        fn m61_same_transaction_teardown_exempts_meter_change() {
            let mut f = g3b_undo_fixture();
            let region2 = RegionId::new(ReplicaId(1), 6);
            let sig = TimeSignatureId::new(ReplicaId(1), 300);
            f.push_tx(
                "CreateRegion 2 (same tx)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            f.push(
                "SetTimeSignature region2 -> measure",
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region: region2,
                    anchor: measure_anchor(f.measure, MeasurePosition::Start),
                    time_signature: Some(crate::valuegen::time_signature(sig, 4)),
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_undo_applied(&out, &undo, "same-tx region mint must not strand-block");
        }

        /// (M61, row 5/7: system break) The owning region is minted in the
        /// same tx.
        #[test]
        fn m61_same_transaction_teardown_exempts_system_break() {
            let mut f = g3b_undo_fixture();
            let region2 = RegionId::new(ReplicaId(1), 6);
            f.push_tx(
                "CreateRegion 2 (same tx)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            f.push(
                "SetUserSystemBreak region2 -> measure",
                OperationKind::SetUserSystemBreak(crate::payload::SetUserSystemBreakOp {
                    region: region2,
                    anchor: measure_anchor(f.measure, MeasurePosition::Start),
                    present: true,
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_undo_applied(&out, &undo, "same-tx region mint must not strand-block");
        }

        /// (M61, row 6/7: page break) The owning region is minted in the
        /// same tx.
        #[test]
        fn m61_same_transaction_teardown_exempts_page_break() {
            let mut f = g3b_undo_fixture();
            let region2 = RegionId::new(ReplicaId(1), 6);
            f.push_tx(
                "CreateRegion 2 (same tx)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            f.push(
                "SetUserPageBreak region2 -> measure",
                OperationKind::SetUserPageBreak(SetUserPageBreakOp {
                    region: region2,
                    anchor: measure_anchor(f.measure, MeasurePosition::Start),
                    present: true,
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_undo_applied(&out, &undo, "same-tx region mint must not strand-block");
        }

        /// (M61, row 7/7: region-scoped tempo segment) The owning region is
        /// minted in the same tx.
        #[test]
        fn m61_same_transaction_teardown_exempts_tempo_segment_region_scoped() {
            let mut f = g3b_undo_fixture();
            let region2 = RegionId::new(ReplicaId(1), 6);
            f.push_tx(
                "CreateRegion 2 (same tx)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            let start = measure_anchor(f.measure, MeasurePosition::Start);
            f.push(
                "SetTempoSegment region2 start -> measure",
                OperationKind::SetTempoSegment(SetTempoSegmentOp {
                    region: Some(region2),
                    start: start.clone(),
                    segment: Some(bare_tempo_segment(start, None)),
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_undo_applied(&out, &undo, "same-tx region mint must not strand-block");
        }

        // === M62: a TOMBSTONED referencer does not block (the `Live`
        // conjunct). Six always-owned rows plus region-scoped tempo; score-
        // level (`None`) tempo has no owner conjunct and is N/A. ============

        /// (M62, row 1/7: spanner) `DeleteCrossCutting` ALSO removes the
        /// spanner's `cross_cutting_modify_chain` entry, which would make
        /// this row pass regardless of the `Live` conjunct — vacuous, and
        /// found the hard way (this row was originally written that way and
        /// stayed green under M62). Instead, the spanner is minted in its
        /// OWN transaction and THAT transaction is undone: `tombstone_undo_
        /// targets` marks it `Tombstoned` in `objects` WITHOUT removing the
        /// chain entry, so the (still-present, still-naming-the-measure)
        /// value is exactly what the `Live` conjunct must exclude.
        #[test]
        fn m62_tombstoned_spanner_does_not_block() {
            let mut f = g3b_undo_fixture();
            let sid = SpannerId::new(ReplicaId(1), 200);
            let tx_s = TransactionId::new(ReplicaId(1), 902);

            let counter = f.next_counter;
            let declare_s = tx_member(
                1,
                counter,
                counter as i64,
                f.next_causal.clone(),
                tx_s,
                OperationKind::DeclareTransaction(crate::payload::TransactionDescriptor {
                    id: tx_s,
                    label: String::from("g3b undo surface: spanner"),
                    category: None,
                }),
            );
            f.labeled.push(("DeclareTransaction (S)", declare_s));
            f.next_counter += 1;
            f.next_causal = seen_r1(counter);

            let counter = f.next_counter;
            let create_s = tx_member(
                1,
                counter,
                counter as i64,
                f.next_causal.clone(),
                tx_s,
                OperationKind::CreateCrossCutting(CreateCrossCuttingOp {
                    structure: CrossCuttingValue::Spanner(bare_spanner(
                        sid,
                        measure_anchor(f.measure, MeasurePosition::Start),
                        measure_anchor(f.measure, MeasurePosition::End),
                    )),
                }),
            );
            f.labeled
                .push(("CreateCrossCutting spanner (own tx)", create_s));
            f.next_counter += 1;
            f.next_causal = seen_r1(counter);

            let counter = f.next_counter;
            let undo_s = undo_env(
                1,
                counter,
                counter as i64,
                f.next_causal.clone(),
                tx_s,
                UndoPolicy::StrictInverse,
            );
            f.labeled.push((
                "undo S's own tx (tombstones S, chain entry survives)",
                undo_s.clone(),
            ));
            f.next_counter += 1;
            f.next_causal = seen_r1(counter);

            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(2);
            assert_undo_applied(&out, &undo_s, "undoing S's own tx must succeed (Applied)");
            assert_undo_applied(
                &out,
                &undo,
                "a tombstoned spanner, with its chain entry still present, must not \
                 strand-block",
            );
        }

        /// (M62, row 2/7: repeat) Delete the repeat before undoing the
        /// measure's tx.
        #[test]
        fn m62_tombstoned_repeat_does_not_block() {
            let mut f = g3b_undo_fixture();
            let rid = RepeatStructureId::new(ReplicaId(1), 201);
            f.push(
                "CreateRepeatStructure ->measure",
                OperationKind::CreateRepeatStructure(CreateRepeatStructureOp {
                    repeat: bare_repeat(
                        rid,
                        measure_anchor(f.measure, MeasurePosition::Start),
                        measure_anchor(f.measure, MeasurePosition::End),
                    ),
                }),
            );
            f.push(
                "DeleteRepeatStructure",
                OperationKind::DeleteRepeatStructure(DeleteRepeatStructureOp { repeat: rid }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_undo_applied(
                &out,
                &undo,
                "a tombstoned repeat must not strand-block — and its retained \
                 `repeat_values` entry (pin 10.4) is what makes this row \
                 reachable at all",
            );
        }

        /// (M62, row 3/7: `measure_values`) Undo measure C's OWN transaction
        /// first (tombstoning C — the only way to tombstone a measure), then
        /// undo the target measure's tx.
        #[test]
        fn m62_tombstoned_measure_referencer_does_not_block() {
            let mut f = g3b_undo_fixture();
            let instance2 = StaffInstanceId::new(ReplicaId(1), 5);
            let staff = StaffId::new(ReplicaId(1), 3);
            let c = MeasureId::new(ReplicaId(1), 101);
            let tx_c = TransactionId::new(ReplicaId(1), 901);
            f.push(
                "CreateStaffInstance 2",
                OperationKind::CreateStaffInstance(CreateStaffInstanceOp {
                    region: f.region,
                    instance: crate::valuegen::staff_instance(instance2, staff),
                }),
            );
            // C's own (separate) transaction.
            let counter = f.next_counter;
            let declare_c = tx_member(
                1,
                counter,
                counter as i64,
                f.next_causal.clone(),
                tx_c,
                OperationKind::DeclareTransaction(crate::payload::TransactionDescriptor {
                    id: tx_c,
                    label: String::from("g3b undo surface: measure C"),
                    category: None,
                }),
            );
            f.labeled.push(("DeclareTransaction (C)", declare_c));
            f.next_counter += 1;
            f.next_causal = seen_r1(counter);

            let counter = f.next_counter;
            let create_c = tx_member(
                1,
                counter,
                counter as i64,
                f.next_causal.clone(),
                tx_c,
                OperationKind::CreateMeasure(CreateMeasureOp {
                    instance: instance2,
                    measure: Measure {
                        id: c,
                        start: measure_anchor(f.measure, MeasurePosition::Start),
                        time_signature: None,
                        explicit_number: None,
                        number_visibility: Default::default(),
                    },
                }),
            );
            f.labeled.push(("CreateMeasure C (own tx)", create_c));
            f.next_counter += 1;
            f.next_causal = seen_r1(counter);

            let counter = f.next_counter;
            let undo_c = undo_env(
                1,
                counter,
                counter as i64,
                f.next_causal.clone(),
                tx_c,
                UndoPolicy::StrictInverse,
            );
            f.labeled
                .push(("undo C's tx (tombstones C)", undo_c.clone()));
            f.next_counter += 1;
            f.next_causal = seen_r1(counter);

            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(2);
            assert_undo_applied(&out, &undo_c, "undoing C's own tx must succeed (Applied)");
            assert_undo_applied(
                &out,
                &undo,
                "a tombstoned measure C must not strand-block the target measure",
            );
        }

        /// (M62, row 4/7: meter change) Delete the owning (throwaway, empty)
        /// region before undoing the measure's tx.
        #[test]
        fn m62_tombstoned_meter_change_owner_does_not_block() {
            let mut f = g3b_undo_fixture();
            let region2 = RegionId::new(ReplicaId(1), 6);
            let sig = TimeSignatureId::new(ReplicaId(1), 300);
            f.push(
                "CreateRegion 2 (empty)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            f.push(
                "SetTimeSignature region2 -> measure",
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region: region2,
                    anchor: measure_anchor(f.measure, MeasurePosition::Start),
                    time_signature: Some(crate::valuegen::time_signature(sig, 4)),
                }),
            );
            f.push(
                "DeleteRegion 2 (empty, so deletable)",
                OperationKind::DeleteRegion(crate::payload::DeleteRegionOp { region: region2 }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_undo_applied(
                &out,
                &undo,
                "a tombstoned owning region must not strand-block via meter change",
            );
        }

        /// (M62, row 5/7: system break) Delete the owning region.
        #[test]
        fn m62_tombstoned_system_break_owner_does_not_block() {
            let mut f = g3b_undo_fixture();
            let region2 = RegionId::new(ReplicaId(1), 6);
            f.push(
                "CreateRegion 2 (empty)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            f.push(
                "SetUserSystemBreak region2 -> measure",
                OperationKind::SetUserSystemBreak(crate::payload::SetUserSystemBreakOp {
                    region: region2,
                    anchor: measure_anchor(f.measure, MeasurePosition::Start),
                    present: true,
                }),
            );
            f.push(
                "DeleteRegion 2 (empty, so deletable)",
                OperationKind::DeleteRegion(crate::payload::DeleteRegionOp { region: region2 }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_undo_applied(
                &out,
                &undo,
                "a tombstoned owning region must not strand-block via system break",
            );
        }

        /// (M62, row 6/7: page break) Delete the owning region.
        #[test]
        fn m62_tombstoned_page_break_owner_does_not_block() {
            let mut f = g3b_undo_fixture();
            let region2 = RegionId::new(ReplicaId(1), 6);
            f.push(
                "CreateRegion 2 (empty)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            f.push(
                "SetUserPageBreak region2 -> measure",
                OperationKind::SetUserPageBreak(SetUserPageBreakOp {
                    region: region2,
                    anchor: measure_anchor(f.measure, MeasurePosition::Start),
                    present: true,
                }),
            );
            f.push(
                "DeleteRegion 2 (empty, so deletable)",
                OperationKind::DeleteRegion(crate::payload::DeleteRegionOp { region: region2 }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_undo_applied(
                &out,
                &undo,
                "a tombstoned owning region must not strand-block via page break",
            );
        }

        /// (M62, row 7/7: region-scoped tempo) Delete the owning region.
        /// Score-level (`None`) tempo has NO owner conjunct at all and is
        /// N/A for this row (pin 10.5).
        #[test]
        fn m62_tombstoned_tempo_segment_owner_does_not_block() {
            let mut f = g3b_undo_fixture();
            let region2 = RegionId::new(ReplicaId(1), 6);
            f.push(
                "CreateRegion 2 (empty)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            let start = measure_anchor(f.measure, MeasurePosition::Start);
            f.push(
                "SetTempoSegment region2 start -> measure",
                OperationKind::SetTempoSegment(SetTempoSegmentOp {
                    region: Some(region2),
                    start: start.clone(),
                    segment: Some(bare_tempo_segment(start, None)),
                }),
            );
            f.push(
                "DeleteRegion 2 (empty, so deletable)",
                OperationKind::DeleteRegion(crate::payload::DeleteRegionOp { region: region2 }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_undo_applied(
                &out,
                &undo,
                "a tombstoned owning region must not strand-block via tempo segment",
            );
        }

        // === M59/M60: restoration-awareness on the five `WriteChain`
        // surfaces (`repeat_values`/`measure_values` are immutable value
        // maps — N/A, not tested here; see M52/M54 above for their
        // coverage). Six observations each (tempo at both anchor sites). ===
        //
        // M60 (this section): the ADDED direction. A write, WITHIN the
        // measure's own transaction, adds a reference from an already-live
        // structure to the fresh measure. Undoing the transaction restores
        // the pre-tx (necessarily M-free, since M did not exist before this
        // tx) value — the reference is REMOVED — and undo MUST NOT block.

        /// (M60, 1/6: spanner) `S` pre-exists (WallClock endpoints); a
        /// same-tx `ModifyCrossCutting` retargets it to the fresh measure.
        #[test]
        fn m60_added_direction_spanner_does_not_block() {
            let mut f = g3b_undo_fixture_prereqs_only();
            let sid = SpannerId::new(ReplicaId(1), 200);
            let benign = |n: i64| TimeAnchor::WallClock {
                time: WallClockTime(n),
            };
            f.push(
                "CreateCrossCutting spanner (benign, pre-tx)",
                OperationKind::CreateCrossCutting(CreateCrossCuttingOp {
                    structure: CrossCuttingValue::Spanner(bare_spanner(sid, benign(1), benign(2))),
                }),
            );
            let measure = f.measure;
            f.open_target_tx();
            f.push_tx(
                "ModifyCrossCutting spanner -> measure (same tx, adds the reference)",
                OperationKind::ModifyCrossCutting(ModifyCrossCuttingOp {
                    structure: CrossCuttingValue::Spanner(bare_spanner(
                        sid,
                        measure_anchor(measure, MeasurePosition::Start),
                        measure_anchor(measure, MeasurePosition::End),
                    )),
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_undo_applied(
                &out,
                &undo,
                "an added spanner reference, undone, must be removed and must not block",
            );
        }

        /// (M60, 2/6: meter change) A benign meter change pre-exists at the
        /// SAME (region, resolved-position) key; a same-tx `SetTimeSignature`
        /// overwrites it to reference the fresh measure.
        #[test]
        fn m60_added_direction_meter_change_does_not_block() {
            let mut f = g3b_undo_fixture_prereqs_only();
            let region2 = RegionId::new(ReplicaId(1), 6);
            let sig0 = TimeSignatureId::new(ReplicaId(1), 300);
            let sig1 = TimeSignatureId::new(ReplicaId(1), 301);
            f.push(
                "CreateRegion 2 (empty)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            f.push(
                "SetTimeSignature region2 (benign, pre-tx)",
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region: region2,
                    anchor: g3b_region_anchor(region2, 0),
                    time_signature: Some(crate::valuegen::time_signature(sig0, 4)),
                }),
            );
            let measure = f.measure;
            f.open_target_tx();
            f.push_tx(
                "SetTimeSignature region2 -> measure (same tx, adds the reference)",
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region: region2,
                    anchor: measure_anchor(measure, MeasurePosition::Start),
                    time_signature: Some(crate::valuegen::time_signature(sig1, 4)),
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_undo_applied(
                &out,
                &undo,
                "an added meter-change reference, undone, must be removed and must not block",
            );
        }

        /// (M60, 3/6: system break) A benign break pre-exists at the SAME
        /// key; a same-tx `SetUserSystemBreak` overwrites it to reference the
        /// fresh measure.
        #[test]
        fn m60_added_direction_system_break_does_not_block() {
            let mut f = g3b_undo_fixture_prereqs_only();
            let region2 = RegionId::new(ReplicaId(1), 6);
            f.push(
                "CreateRegion 2 (empty)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            f.push(
                "SetUserSystemBreak region2 (benign, pre-tx)",
                OperationKind::SetUserSystemBreak(crate::payload::SetUserSystemBreakOp {
                    region: region2,
                    anchor: g3b_region_anchor(region2, 0),
                    present: true,
                }),
            );
            let measure = f.measure;
            f.open_target_tx();
            f.push_tx(
                "SetUserSystemBreak region2 -> measure (same tx, adds the reference)",
                OperationKind::SetUserSystemBreak(crate::payload::SetUserSystemBreakOp {
                    region: region2,
                    anchor: measure_anchor(measure, MeasurePosition::Start),
                    present: true,
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_undo_applied(
                &out,
                &undo,
                "an added system-break reference, undone, must be removed and must not block",
            );
        }

        /// (M60, 4/6: page break) Same shape as (3) via `SetUserPageBreak`.
        #[test]
        fn m60_added_direction_page_break_does_not_block() {
            let mut f = g3b_undo_fixture_prereqs_only();
            let region2 = RegionId::new(ReplicaId(1), 6);
            f.push(
                "CreateRegion 2 (empty)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            f.push(
                "SetUserPageBreak region2 (benign, pre-tx)",
                OperationKind::SetUserPageBreak(SetUserPageBreakOp {
                    region: region2,
                    anchor: g3b_region_anchor(region2, 0),
                    present: true,
                }),
            );
            let measure = f.measure;
            f.open_target_tx();
            f.push_tx(
                "SetUserPageBreak region2 -> measure (same tx, adds the reference)",
                OperationKind::SetUserPageBreak(SetUserPageBreakOp {
                    region: region2,
                    anchor: measure_anchor(measure, MeasurePosition::Start),
                    present: true,
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_undo_applied(
                &out,
                &undo,
                "an added page-break reference, undone, must be removed and must not block",
            );
        }

        /// (M60, 5/6: tempo segment, `start` site) A benign segment
        /// pre-exists at the SAME key; a same-tx `SetTempoSegment` overwrites
        /// it so `start` names the fresh measure.
        #[test]
        fn m60_added_direction_tempo_segment_start_does_not_block() {
            let mut f = g3b_undo_fixture_prereqs_only();
            let region2 = RegionId::new(ReplicaId(1), 6);
            f.push(
                "CreateRegion 2 (empty)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            let key_pos = g3b_region_anchor(region2, 0);
            f.push(
                "SetTempoSegment region2 (benign, pre-tx)",
                OperationKind::SetTempoSegment(SetTempoSegmentOp {
                    region: Some(region2),
                    start: key_pos.clone(),
                    segment: Some(bare_tempo_segment(key_pos.clone(), None)),
                }),
            );
            let measure = f.measure;
            f.open_target_tx();
            let new_start = measure_anchor(measure, MeasurePosition::Start);
            f.push_tx(
                "SetTempoSegment region2 start -> measure (same tx, adds the reference)",
                OperationKind::SetTempoSegment(SetTempoSegmentOp {
                    region: Some(region2),
                    start: key_pos,
                    segment: Some(bare_tempo_segment(new_start, None)),
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_undo_applied(
                &out,
                &undo,
                "an added tempo-segment start reference, undone, must be removed and \
                 must not block",
            );
        }

        /// (M60, 6/6: tempo segment, `end` site) Same shape as (5), but the
        /// added reference is the segment's `end`, not its `start`.
        #[test]
        fn m60_added_direction_tempo_segment_end_does_not_block() {
            let mut f = g3b_undo_fixture_prereqs_only();
            let region2 = RegionId::new(ReplicaId(1), 6);
            f.push(
                "CreateRegion 2 (empty)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            let key_pos = g3b_region_anchor(region2, 0);
            f.push(
                "SetTempoSegment region2 (benign, pre-tx)",
                OperationKind::SetTempoSegment(SetTempoSegmentOp {
                    region: Some(region2),
                    start: key_pos.clone(),
                    segment: Some(bare_tempo_segment(key_pos.clone(), None)),
                }),
            );
            let measure = f.measure;
            f.open_target_tx();
            let new_end = measure_anchor(measure, MeasurePosition::End);
            f.push_tx(
                "SetTempoSegment region2 end -> measure (same tx, adds the reference)",
                OperationKind::SetTempoSegment(SetTempoSegmentOp {
                    region: Some(region2),
                    start: key_pos.clone(),
                    segment: Some(bare_tempo_segment(key_pos, Some(new_end))),
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_undo_applied(
                &out,
                &undo,
                "an added tempo-segment end reference, undone, must be removed and \
                 must not block",
            );
        }

        // === M59: the REINSTATED direction. ================================
        //
        // A restoration's chain-predecessor is the graph's own pre-
        // operational BASE — the only place a reference to the fixture's
        // measure can predate the measure's own mint, since nothing can
        // validly WRITE such a reference before the measure exists (proven
        // by exhaustion while drafting this packet: any reference authored
        // by an operation must be canonically ordered after `CreateMeasure`,
        // and a chain-predecessor search skips every write tagged with the
        // SAME transaction being undone — so an intra-tx swap can only ever
        // demonstrate M60's ADDED direction). Seeding performs no cross-
        // reference validation, so injecting a base value that names the
        // fixture's own (not-yet-minted) measure id is a structurally valid
        // way to construct the one case seeding CAN present: a dangling
        // forward reference. Within the target tx, a write REMOVES that
        // reference (current, pre-undo: no reference); undoing the tx
        // restores the chain to its base value — REINSTATING the reference —
        // and MUST block.

        /// A fresh, empty-transaction-history fixture reusing `prereqs`'
        /// region/instance/measure/tx ids, for reduction onto a caller-
        /// mutated base.
        fn g3b_fixture_onto(prereqs: &G3bUndoFixture) -> G3bUndoFixture {
            G3bUndoFixture {
                labeled: Vec::new(),
                region: prereqs.region,
                instance: prereqs.instance,
                measure: prereqs.measure,
                tx: prereqs.tx,
                next_counter: 0,
                next_causal: CausalContext::new(),
            }
        }

        /// (M59, 1/6: spanner) The base graph already carries a `Spanner`
        /// referencing the fixture's own (not-yet-minted) measure.
        #[test]
        fn m59_reinstated_direction_spanner_blocks() {
            let prereqs = g3b_undo_fixture_prereqs_only();
            let mut base = prereqs.run_allowing_tail_conflict(0).score;
            let sid = SpannerId::new(ReplicaId(1), 200);
            base.cross_cutting.spanners.push(bare_spanner(
                sid,
                measure_anchor(prereqs.measure, MeasurePosition::Start),
                measure_anchor(prereqs.measure, MeasurePosition::End),
            ));

            let mut f = g3b_fixture_onto(&prereqs);
            f.open_target_tx();
            let benign_a = TimeAnchor::WallClock {
                time: WallClockTime(9),
            };
            let benign_b = TimeAnchor::WallClock {
                time: WallClockTime(10),
            };
            f.push_tx(
                "ModifyCrossCutting spanner -> benign (same tx, removes the reference)",
                OperationKind::ModifyCrossCutting(ModifyCrossCuttingOp {
                    structure: CrossCuttingValue::Spanner(bare_spanner(sid, benign_a, benign_b)),
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_onto(&base, 1);
            assert_blocks(
                &out,
                &undo,
                "a restoration reinstating the spanner's measure reference must block",
            );
        }

        /// (M59, 2/6: meter change) The base graph's region2 already carries
        /// a `MeterChange` referencing the fixture's own (not-yet-minted)
        /// measure.
        #[test]
        fn m59_reinstated_direction_meter_change_blocks() {
            let mut prereqs = g3b_undo_fixture_prereqs_only();
            let region2 = RegionId::new(ReplicaId(1), 6);
            prereqs.push(
                "CreateRegion 2 (empty)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            let mut base = prereqs.run_allowing_tail_conflict(0).score;
            let dangling_sig = TimeSignatureId::new(ReplicaId(1), 300);
            {
                let region = base
                    .canvas
                    .regions
                    .iter_mut()
                    .find(|r| r.id == region2)
                    .expect("region2 present");
                let content = region.content.staff_based_mut().expect("staff-based");
                content.default_metric_grid = Some(MetricGrid {
                    meter_sequence: vec![MeterChange {
                        anchor: measure_anchor(prereqs.measure, MeasurePosition::Start),
                        time_signature: dangling_sig,
                    }],
                });
            }

            let mut f = g3b_fixture_onto(&prereqs);
            f.open_target_tx();
            f.push_tx(
                "SetTimeSignature region2 (same tx, removes the reference)",
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region: region2,
                    anchor: measure_anchor(prereqs.measure, MeasurePosition::Start),
                    time_signature: None,
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_onto(&base, 1);
            assert_blocks(
                &out,
                &undo,
                "a restoration reinstating the meter change's measure reference must block",
            );
        }

        /// (M59, 3/6: system break) The base graph's region2 already carries
        /// a user system-break anchored to the fixture's own (not-yet-
        /// minted) measure.
        #[test]
        fn m59_reinstated_direction_system_break_blocks() {
            let mut prereqs = g3b_undo_fixture_prereqs_only();
            let region2 = RegionId::new(ReplicaId(1), 6);
            prereqs.push(
                "CreateRegion 2 (empty)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            let mut base = prereqs.run_allowing_tail_conflict(0).score;
            {
                let region = base
                    .canvas
                    .regions
                    .iter_mut()
                    .find(|r| r.id == region2)
                    .expect("region2 present");
                let content = region.content.staff_based_mut().expect("staff-based");
                content
                    .user_system_breaks
                    .push(measure_anchor(prereqs.measure, MeasurePosition::Start));
            }

            let mut f = g3b_fixture_onto(&prereqs);
            f.open_target_tx();
            f.push_tx(
                "SetUserSystemBreak region2 (same tx, removes the reference)",
                OperationKind::SetUserSystemBreak(crate::payload::SetUserSystemBreakOp {
                    region: region2,
                    anchor: measure_anchor(prereqs.measure, MeasurePosition::Start),
                    present: false,
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_onto(&base, 1);
            assert_blocks(
                &out,
                &undo,
                "a restoration reinstating the system break's measure reference must block",
            );
        }

        /// (M59, 4/6: page break) Same shape as (3) via `user_page_breaks` /
        /// `SetUserPageBreak`.
        #[test]
        fn m59_reinstated_direction_page_break_blocks() {
            let mut prereqs = g3b_undo_fixture_prereqs_only();
            let region2 = RegionId::new(ReplicaId(1), 6);
            prereqs.push(
                "CreateRegion 2 (empty)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            let mut base = prereqs.run_allowing_tail_conflict(0).score;
            {
                let region = base
                    .canvas
                    .regions
                    .iter_mut()
                    .find(|r| r.id == region2)
                    .expect("region2 present");
                let content = region.content.staff_based_mut().expect("staff-based");
                content
                    .user_page_breaks
                    .push(measure_anchor(prereqs.measure, MeasurePosition::Start));
            }

            let mut f = g3b_fixture_onto(&prereqs);
            f.open_target_tx();
            f.push_tx(
                "SetUserPageBreak region2 (same tx, removes the reference)",
                OperationKind::SetUserPageBreak(SetUserPageBreakOp {
                    region: region2,
                    anchor: measure_anchor(prereqs.measure, MeasurePosition::Start),
                    present: false,
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_onto(&base, 1);
            assert_blocks(
                &out,
                &undo,
                "a restoration reinstating the page break's measure reference must block",
            );
        }

        /// (M59, 5/6: tempo segment, `start` site) The base graph's
        /// region2's local tempo map already carries a segment whose `start`
        /// names the fixture's own (not-yet-minted) measure.
        #[test]
        fn m59_reinstated_direction_tempo_segment_start_blocks() {
            let mut prereqs = g3b_undo_fixture_prereqs_only();
            let region2 = RegionId::new(ReplicaId(1), 6);
            prereqs.push(
                "CreateRegion 2 (empty)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            let mut base = prereqs.run_allowing_tail_conflict(0).score;
            let dangling_start = measure_anchor(prereqs.measure, MeasurePosition::Start);
            {
                let region = base
                    .canvas
                    .regions
                    .iter_mut()
                    .find(|r| r.id == region2)
                    .expect("region2 present");
                region.local_tempo_map = Some(TempoMap {
                    initial: None,
                    segments: vec![bare_tempo_segment(dangling_start.clone(), None)],
                });
            }

            let mut f = g3b_fixture_onto(&prereqs);
            f.open_target_tx();
            f.push_tx(
                "SetTempoSegment region2 start (same tx, removes the reference)",
                OperationKind::SetTempoSegment(SetTempoSegmentOp {
                    region: Some(region2),
                    start: dangling_start,
                    segment: None,
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_onto(&base, 1);
            assert_blocks(
                &out,
                &undo,
                "a restoration reinstating the tempo segment's start measure \
                 reference must block",
            );
        }

        /// (M59, 6/6: tempo segment, `end` site) The dangling segment's
        /// `start` is benign (a region anchor); only its `end` names the
        /// fixture's own (not-yet-minted) measure.
        #[test]
        fn m59_reinstated_direction_tempo_segment_end_blocks() {
            let mut prereqs = g3b_undo_fixture_prereqs_only();
            let region2 = RegionId::new(ReplicaId(1), 6);
            prereqs.push(
                "CreateRegion 2 (empty)",
                OperationKind::CreateRegion(CreateRegionOp {
                    region: crate::valuegen::region(region2),
                }),
            );
            let mut base = prereqs.run_allowing_tail_conflict(0).score;
            let key_start = g3b_region_anchor(region2, 0);
            let dangling_end = measure_anchor(prereqs.measure, MeasurePosition::End);
            {
                let region = base
                    .canvas
                    .regions
                    .iter_mut()
                    .find(|r| r.id == region2)
                    .expect("region2 present");
                region.local_tempo_map = Some(TempoMap {
                    initial: None,
                    segments: vec![bare_tempo_segment(key_start.clone(), Some(dangling_end))],
                });
            }

            let mut f = g3b_fixture_onto(&prereqs);
            f.open_target_tx();
            f.push_tx(
                "SetTempoSegment region2 end (same tx, removes the reference)",
                OperationKind::SetTempoSegment(SetTempoSegmentOp {
                    region: Some(region2),
                    start: key_start,
                    segment: None,
                }),
            );
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_onto(&base, 1);
            assert_blocks(
                &out,
                &undo,
                "a restoration reinstating the tempo segment's end measure \
                 reference must block",
            );
        }

        // === M48: the `TimeSignature` <-> `Measure` extension. ==============

        /// (M48) A minted `TimeSignature`, still named by a live
        /// `Measure.time_signature`, blocks the signature's own undo — the
        /// hole that exists TODAY, before G3b (`undo_strand_block`'s
        /// existing `TimeSignature` arm consulted only `meter_change_chain`).
        #[test]
        fn m48_time_signature_still_named_by_live_measure_blocks_undo() {
            let mut f = g3b_undo_fixture_prereqs_only();
            let sig = TimeSignatureId::new(ReplicaId(1), 300);
            let tx_ts = f.tx;
            let pos0 = g3b_region_anchor(f.region, 0);
            f.push_tx(
                "DeclareTransaction (mints the signature)",
                OperationKind::DeclareTransaction(crate::payload::TransactionDescriptor {
                    id: tx_ts,
                    label: String::from("g3b undo surface: signature"),
                    category: None,
                }),
            );
            f.push_tx(
                "SetTimeSignature (mints sig)",
                OperationKind::SetTimeSignature(SetTimeSignatureOp {
                    region: f.region,
                    anchor: pos0.clone(),
                    time_signature: Some(crate::valuegen::time_signature(sig, 4)),
                }),
            );
            f.push(
                "CreateMeasure naming sig (non-tx, first measure: agreement holds)",
                OperationKind::CreateMeasure(CreateMeasureOp {
                    instance: f.instance,
                    measure: Measure {
                        id: f.measure,
                        start: pos0,
                        time_signature: Some(sig),
                        explicit_number: None,
                        number_visibility: Default::default(),
                    },
                }),
            );
            let undo = f.push_undo("undo the signature's own tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_blocks(
                &out,
                &undo,
                "a live measure still naming the time signature must block its undo",
            );
        }

        // === M49: the `Measure` graph-removal arm. ===========================

        /// (M49) Undoing a measure's mint removes it from the OWNING
        /// `StaffInstance.measures` — not merely tombstones it in `objects`
        /// (`materialize_graph_tombstones` cannot be a bare `retain` over
        /// `score`, since `Measure` is a nested container child).
        #[test]
        fn m49_undo_removes_measure_from_owning_instance() {
            let mut f = g3b_undo_fixture();
            let undo = f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let out = f.run_allowing_tail_conflict(1);
            assert_undo_applied(&out, &undo, "an unblocked measure undo must be Applied");
            let region_value = out
                .score
                .canvas
                .regions
                .iter()
                .find(|r| r.id == f.region)
                .expect("region present");
            let instance_value = region_value
                .staff_instances()
                .iter()
                .find(|i| i.id == f.instance)
                .expect("instance present");
            assert!(
                !instance_value.measures.iter().any(|m| m.id == f.measure),
                "the tombstoned measure must be REMOVED from StaffInstance.measures, \
                 not merely tombstoned in `objects`"
            );
            assert!(
                matches!(
                    out.state.objects.get(&TypedObjectId::Measure(f.measure)),
                    Some(ObjectState::Tombstoned { .. })
                ),
                "the ledger must also record the tombstone"
            );
        }

        // === M63: post-undo re-create ordering. ==============================

        /// (M63) After an undo tombstones a measure, a byte-identical
        /// re-carry of the original `CreateMeasure` must observe
        /// `TargetTombstoned`, not `AlreadyApplied` — `create_measure`'s
        /// `Tombstoned` arm must NOT fall through to the value-map identity
        /// check.
        #[test]
        fn m63_recreate_after_undo_is_target_tombstoned_not_already_applied() {
            let mut f = g3b_undo_fixture();
            f.push_undo("undo target tx", UndoPolicy::StrictInverse);
            let pos0 = g3b_region_anchor(f.region, 0);
            let recreate = f.push(
                "byte-identical re-carry of CreateMeasure",
                OperationKind::CreateMeasure(CreateMeasureOp {
                    instance: f.instance,
                    measure: Measure {
                        id: f.measure,
                        start: pos0,
                        time_signature: None,
                        explicit_number: None,
                        number_visibility: Default::default(),
                    },
                }),
            );
            let out = f.run_allowing_tail_conflict(2);
            assert_eq!(
                g3b_effect_of(&out.state, recreate.id),
                Some(OperationEffect::NoOp {
                    reason: NoOpReason::TargetTombstoned
                }),
                "a byte-identical re-carry after undo must be TargetTombstoned, \
                 not AlreadyApplied"
            );
        }
    }
}
