G3b packet 1: CreateMeasure reaches the wire, the mint, and the grid oracle

Kind and tag 39 at schema-minor epoch 12, in both unaligned discriminant
spaces. Measure is schema major 0 -- struct_codec! is a plain walk and
TimeAnchor's Codec has no version branching -- so schema_major() gains no arm
and OperationEnvelopeBlock stays at 3.

CreateMeasure is a nested-container mint following CreateStaffInstance, not
G3a's root-level shape: it carries the owning StaffInstanceId beside the
value, and measure_values carries that parent because Measure has no
back-pointer and the graph-removal arm will need it. Append-only, with
referential preconditions on the parent, the signature, and every non-wall-clock
start referent.

The comparable relation is five exact shapes with an identical boundary
selector; ordering across Start/End is unsound while measure length is
unresolved, so it stays unverifiable. Boundary distance needs a musical delta,
which only same-referent same-selector Musical offsets supply. The effective-grid
oracle reconstructs inheritance from metric_grid_chain and meter_change_chain by
write recency -- not by always overlaying per-key on whole-grid -- folds in
prospective overrides, and runs identically in both reduction modes, so an
instance_grid ledger keeps base-free reduction honest.

Three precondition reasons at 16-18. Repairs a live bug found in review: the
materialized-effect decoder stopped at 13, so reasons 14 and 15 already encoded
without decoding, and the generator drawing below(14) could not see them.

Executed against spec/CONTRACT_GENESIS_G3B_MEASURE.md, mutations M1-M33,
M64-M66, M67-M70. text_projection.tex moved into this packet: four tests read
it live, so the companion bump cannot be split from the grammar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
This commit is contained in:
Levi Neuwirth 2026-07-30 12:19:32 -04:00
parent 93deb18ed6
commit e64a4b7103
26 changed files with 3909 additions and 144 deletions

View File

@ -3598,6 +3598,14 @@ canonical_value! {
PartDefinition, PartDefinition,
AnalysisLayer, AnalysisLayer,
ViewDefinition, ViewDefinition,
// Genesis tranche G3b (`CONTRACT_GENESIS_G3B_MEASURE.md` pin 3) —
// CreateMeasure embeds the full value, mirroring CreateStaffInstance's
// `StaffInstance`. `Measure` already has a `Codec` (`struct_codec!` at
// `:1825`) and already ships inside `Score`; this makes that existing
// layout reachable per-value, same as every other entry here. No new wire
// layout, and no `textvalue_graph.rs` work — `struct_codec!` already
// generated `Measure`'s `TextValue` impl alongside its `Codec`.
Measure,
} }
#[cfg(test)] #[cfg(test)]
@ -3926,6 +3934,128 @@ mod tests {
assert!(back.accidental_extensions.is_empty()); assert!(back.accidental_extensions.is_empty());
} }
/// Genesis tranche G3b (`CONTRACT_GENESIS_G3B_MEASURE.md` pin 4, M12):
/// pins the exact frozen bytes of `Measure`'s `struct_codec!` wire form
/// (`id, start, time_signature, explicit_number, number_visibility`).
///
/// The five field values are chosen so their encodings are MUTUALLY
/// DISTINCT in length (contract §3's `valuegen` trap, from G3a's
/// `analysis_layer` mistake where a same-width field pair made a
/// field-swap byte-invisible): `id` is a 20-byte id-leaf, `start` (a
/// `WallClock` anchor) is 13 bytes, `time_signature` (`Some`) is a
/// 21-byte id-leaf, `explicit_number` (`Some`) is a bare 5-byte `u32`,
/// and `number_visibility` is a 1-byte C-style enum tag.
///
/// **Mutation:** reorder `struct_codec!(Measure { ... })`'s field list in
/// this file; must fail — a `struct_codec!` field reorder changes encode
/// and decode symmetrically and stays green under a round-trip-only
/// assertion, which is why this pins literal bytes instead.
#[test]
fn genesis_g3b_measure_wire_bytes_are_frozen() {
use crate::graph::{Measure, MeasureNumberVisibility};
use crate::ids::{MeasureId, ReplicaId, TimeSignatureId};
use crate::time::{TimeAnchor, WallClockTime};
fn hex(bytes: &[u8]) -> String {
bytes.iter().map(|b| format!("{b:02x}")).collect()
}
let measure = Measure {
id: MeasureId::new(ReplicaId(1), 2),
start: TimeAnchor::WallClock {
time: WallClockTime(3),
},
time_signature: Some(TimeSignatureId::new(ReplicaId(1), 4)),
explicit_number: Some(5),
number_visibility: MeasureNumberVisibility::Always,
};
let mut bytes = Vec::new();
measure.enc(&mut bytes);
let expected = "100000000000000000000001000000000000000203080000000300000000000000011000000000000000000000010000000000000004010500000001";
assert_eq!(hex(&bytes), expected, "the Measure wire form moved");
assert!(!bytes.is_empty());
let decoded = Measure::dec(&mut Reader::new(&bytes)).expect("golden decodes");
assert_eq!(decoded, measure);
}
/// Genesis tranche G3b (M14): the strict per-value re-encode comparison
/// in `canonical_value!` is the ONLY thing standing between an
/// unreduced `RationalTime` spelling and acceptance.
///
/// `Measure.start` carries an `Event`-anchored `Musical` offset whose
/// `RationalTime` is spelled UNREDUCED, `2/4`. `RationalTime::dec` ends in
/// `BigRational::new`, which reduces on construction, so the decoded
/// value is `1/2`; re-encoding it then emits `1/2`'s magnitudes, which
/// differ from the fed-in `2/4` bytes. A structurally-decodable but
/// NONCANONICAL encoding — exactly what the strict per-value check
/// (decode → `finish()` → re-encode → reject on mismatch) exists to
/// reject.
///
/// **Mutation:** in `canonical_value!`, remove the
/// `v.canonical_bytes() != bytes` check (return `Ok(v)` unconditionally);
/// must fail. NOT "remove `Measure` from `canonical_value!`" — that does
/// not compile: the ops-crate envelope decode arm calls `value::<Measure>`,
/// bound by `T: CanonicalValue`.
#[test]
fn genesis_g3b_measure_start_rejects_an_unreduced_rational_time() {
use crate::graph::{Measure, MeasureNumberVisibility};
use crate::ids::{EventId, MeasureId, ReplicaId};
use crate::time::{AnchorOffset, MusicalDuration, RationalTime, TimeAnchor};
// The canonical (reduced) 1/2 value this rung's fixture decodes to.
let reduced = Measure {
id: MeasureId::new(ReplicaId(1), 2),
start: TimeAnchor::Event {
id: EventId::new(ReplicaId(1), 3),
offset: AnchorOffset::Musical(MusicalDuration(
RationalTime::new(1, 2).expect("1/2 is representable"),
)),
},
time_signature: None,
explicit_number: None,
number_visibility: MeasureNumberVisibility::Auto,
};
let mut good_bytes = Vec::new();
reduced.enc(&mut good_bytes);
// The RationalTime wire pattern for 1/2 (Plus sign, 1-byte numerator
// magnitude `01`, 1-byte denominator magnitude `02`) and its
// UNREDUCED 2/4 counterpart — same byte length (11), so substituting
// one for the other does not disturb any surrounding length prefix.
let pattern_1_2: [u8; 11] = [1, 1, 0, 0, 0, 0x01, 1, 0, 0, 0, 0x02];
let pattern_2_4: [u8; 11] = [1, 1, 0, 0, 0, 0x02, 1, 0, 0, 0, 0x04];
let occurrences = good_bytes
.windows(pattern_1_2.len())
.filter(|w| *w == pattern_1_2)
.count();
assert_eq!(
occurrences, 1,
"the 1/2 RationalTime pattern must appear exactly once, to substitute unambiguously"
);
let at = good_bytes
.windows(pattern_1_2.len())
.position(|w| w == pattern_1_2)
.unwrap();
let mut bad_bytes = good_bytes.clone();
bad_bytes[at..at + pattern_2_4.len()].copy_from_slice(&pattern_2_4);
assert_eq!(bad_bytes.len(), good_bytes.len());
// The reduced (canonical) bytes round-trip.
assert_eq!(
Measure::decode_canonical(&good_bytes).as_ref(),
Ok(&reduced)
);
// The unreduced (2/4) bytes are structurally decodable (RationalTime
// itself never rejects an unreduced input — it normalizes), but the
// outer strict re-encode comparison MUST reject them.
assert!(
Measure::decode_canonical(&bad_bytes).is_err(),
"an unreduced RationalTime spelling must be rejected by the strict re-encode check"
);
}
/// Genesis tranche G2b (`CONTRACT_GENESIS_G2B_TUNING.md` §1, pin/touch-row /// Genesis tranche G2b (`CONTRACT_GENESIS_G2B_TUNING.md` §1, pin/touch-row
/// 3): `TuningContextSettings`'s canonical encoding is **byte-identical** /// 3): `TuningContextSettings`'s canonical encoding is **byte-identical**
/// to `ScoreTuningContext`'s existing five-field walk — a type-level /// to `ScoreTuningContext`'s existing five-field walk — a type-level

View File

@ -584,6 +584,19 @@ impl Voice {
/// A measure belonging to exactly one staff instance (Chapter 5 /// A measure belonging to exactly one staff instance (Chapter 5
/// §"Staff-Based Content"). /// §"Staff-Based Content").
///
/// Genesis tranche G3b (`spec/CONTRACT_GENESIS_G3B_MEASURE.md`): `CreateMeasure`
/// is the sole authoring path, and it is append-only — a measure is always
/// pushed at the end of the owning [`StaffInstance::measures`], never
/// inserted. `time_signature: None` means *inherit* the effective grid's
/// active signature at this measure's start; that inherited meter still
/// governs boundary consistency (invariant 20's second clause) even though
/// `None` exempts a measure from the first clause (agreement). Invariant 20's
/// agreement and boundary checks ABSTAIN — emit no violation — where the
/// comparison or delta they need is not computable (contract pin 7): this is
/// deliberate, not a safety property, because base-ingested data may predate
/// the rule. Pickup/anacrusis (a partial first measure) is deferred
/// (P13-S19) and is never refused or flagged by this rung.
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
pub struct Measure { pub struct Measure {
pub id: MeasureId, pub id: MeasureId,
@ -607,7 +620,9 @@ pub struct StaffInstance {
pub key_sequence: Vec<KeySignatureChange>, pub key_sequence: Vec<KeySignatureChange>,
pub local_metric_grid: Option<MetricGrid>, pub local_metric_grid: Option<MetricGrid>,
/// Measures belonging to this instance, in order (per-staff; admits /// Measures belonging to this instance, in order (per-staff; admits
/// polymeter). /// polymeter). Append-only: `CreateMeasure` (genesis tranche G3b) always
/// pushes at the end, gated on the effective grid's agreement and
/// boundary-distance preconditions (contract pin 9).
pub measures: Vec<Measure>, pub measures: Vec<Measure>,
pub instrument_override: Option<InstrumentId>, pub instrument_override: Option<InstrumentId>,
pub staff_lines_override: Option<StaffLineConfiguration>, pub staff_lines_override: Option<StaffLineConfiguration>,

View File

@ -466,6 +466,17 @@ pub(crate) fn subjects_of(kind: &OperationKind, score: &Score) -> BarrierSubject
OperationKind::CreateView(op) => { OperationKind::CreateView(op) => {
one(TypedObjectId::View(op.view_id()), EditContext::default()) one(TypedObjectId::View(op.view_id()), EditContext::default())
} }
// Genesis tranche G3b: `Measure` is a nested container child of a
// `StaffInstance` (not a root-level entity like the mints above), so
// — exactly like `CreateVoice` — it names the region/staff-instance
// context its parent resolves to.
OperationKind::CreateMeasure(op) => one(
TypedObjectId::Measure(op.measure_id()),
ctx(
region_of_staff_instance(score, op.instance),
Some(op.instance),
),
),
OperationKind::SetTimeSignature(op) => { OperationKind::SetTimeSignature(op) => {
let mut objects = vec![(TypedObjectId::Region(op.region), ctx(Some(op.region), None))]; let mut objects = vec![(TypedObjectId::Region(op.region), ctx(Some(op.region), None))];
if let Some(signature) = &op.time_signature { if let Some(signature) = &op.time_signature {

View File

@ -1153,30 +1153,32 @@ mod tests {
tag: 7 tag: 7
}) })
); );
// Operation-kind tag 39 is one past the vocabulary (the Phase-3 ops // Operation-kind tag 40 is one past the vocabulary (the Phase-3 ops
// tranche appended 24..=27, the repeat pair 28/29, `TransposeInterval` // tranche appended 24..=27, the repeat pair 28/29, `TransposeInterval`
// 30, genesis G1's `CreateInstrument` 31, genesis G2a's // 30, genesis G1's `CreateInstrument` 31, genesis G2a's
// `SetCanvasLayoutDefaults` 32 and `SetSpellingPrecedence` 33, // `SetCanvasLayoutDefaults` 32 and `SetSpellingPrecedence` 33,
// genesis G2b's `SetTuningContext` 34, genesis G3a's // genesis G2b's `SetTuningContext` 34, genesis G3a's
// `CreateStaffGroup`/`CreatePartDefinition`/`CreateAnalysisLayer`/ // `CreateStaffGroup`/`CreatePartDefinition`/`CreateAnalysisLayer`/
// `CreateView` 35..=38; encodings are append-only). // `CreateView` 35..=38, genesis G3b's `CreateMeasure` 39; encodings
// are append-only).
// //
// This assertion named 30 until Push 5 / P4, 31 until genesis G1, 32 // This assertion named 30 until Push 5 / P4, 31 until genesis G1, 32
// until genesis G2a, 34 until genesis G2b, and 35 until genesis G3a — // until genesis G2a, 34 until genesis G2b, 35 until genesis G3a, and
// each time, by then, the number had become a real kind, so the test // 39 until genesis G3b — each time, by then, the number had become a
// was pinning a bug: a barrier that prohibited the new operation // real kind, so the test was pinning a bug: a barrier that
// encoded fine and would not read back. It must be bumped by every // prohibited the new operation encoded fine and would not read back.
// tranche that appends a tag, and it is deliberately a literal rather // It must be bumped by every tranche that appends a tag, and it is
// than `PAYLOAD_FREE.len()` so the bump is a conscious act. // deliberately a literal rather than `PAYLOAD_FREE.len()` so the bump
// is a conscious act.
let mut bytes = vec![0u8]; let mut bytes = vec![0u8];
bytes.extend(set_blob(&[])); bytes.extend(set_blob(&[]));
bytes.extend(set_blob(&[vec![39u8]])); bytes.extend(set_blob(&[vec![40u8]]));
bytes.push(0); bytes.push(0);
assert_eq!( assert_eq!(
EditBarrier::decode_canonical_bytes(&bytes), EditBarrier::decode_canonical_bytes(&bytes),
Err(BarrierDecodeError::InvalidTag { Err(BarrierDecodeError::InvalidTag {
kind: "OperationKindTag", kind: "OperationKindTag",
tag: 39 tag: 40
}) })
); );
} }

View File

@ -223,6 +223,14 @@ fn precondition_reason(reader: &mut Reader<'_>) -> Result<PreconditionFailureRea
11 => Ok(PreconditionFailureReason::TempoMapMalformed), 11 => Ok(PreconditionFailureReason::TempoMapMalformed),
12 => Ok(PreconditionFailureReason::SystemDerivedContentImmutable), 12 => Ok(PreconditionFailureReason::SystemDerivedContentImmutable),
13 => Ok(PreconditionFailureReason::RecreateContentMismatch), 13 => Ok(PreconditionFailureReason::RecreateContentMismatch),
// Additive (Push 4a); a pre-existing decoder hole (P13-S20) — these
// two encode but could not decode until this rung.
14 => Ok(PreconditionFailureReason::AcousticRealizationPinned),
15 => Ok(PreconditionFailureReason::TranspositionOutOfRange),
// Additive (Genesis tranche G3b).
16 => Ok(PreconditionFailureReason::MeasureMeterMismatch),
17 => Ok(PreconditionFailureReason::MeasureOutOfOrder),
18 => Ok(PreconditionFailureReason::MeasureOrderUnverifiable),
tag => Err(MaterializedDecodeError::InvalidTag { tag => Err(MaterializedDecodeError::InvalidTag {
kind: "PreconditionFailureReason", kind: "PreconditionFailureReason",
tag, tag,
@ -618,10 +626,38 @@ mod tests {
ReanchorReason::SameCanvasNearer ReanchorReason::SameCanvasNearer
); );
// The vocabularies stay bounded: one past the append rejects. // The vocabularies stay bounded: one past the append rejects.
assert!(exact(&[14], precondition_reason).is_err()); assert!(exact(&[19], precondition_reason).is_err());
assert!(exact(&[7], reanchor_reason).is_err()); assert!(exact(&[7], reanchor_reason).is_err());
} }
/// Genesis tranche G3b (contract row 12a / M64M66): reasons 14 and 15
/// (Push 4a's `AcousticRealizationPinned`/`TranspositionOutOfRange`) were
/// a pre-existing decoder hole — they encoded but could not decode
/// (P13-S20) — and this rung's own 1618 must decode too.
#[test]
fn genesis_g3b_and_the_p13_s20_hole_decode() {
assert_eq!(
exact(&[14], precondition_reason).unwrap(),
PreconditionFailureReason::AcousticRealizationPinned
);
assert_eq!(
exact(&[15], precondition_reason).unwrap(),
PreconditionFailureReason::TranspositionOutOfRange
);
assert_eq!(
exact(&[16], precondition_reason).unwrap(),
PreconditionFailureReason::MeasureMeterMismatch
);
assert_eq!(
exact(&[17], precondition_reason).unwrap(),
PreconditionFailureReason::MeasureOutOfOrder
);
assert_eq!(
exact(&[18], precondition_reason).unwrap(),
PreconditionFailureReason::MeasureOrderUnverifiable
);
}
#[test] #[test]
fn decoder_rejects_truncation_and_trailing_bytes() { fn decoder_rejects_truncation_and_trailing_bytes() {
let bytes = MaterializedState::default().canonical_bytes(); let bytes = MaterializedState::default().canonical_bytes();

View File

@ -185,6 +185,20 @@ pub enum PreconditionFailureReason {
/// past its `i8` bound (Push 4a). The frozen `Transpose` saturates here /// past its `i8` bound (Push 4a). The frozen `Transpose` saturates here
/// and reports success; this refuses. /// and reports success; this refuses.
TranspositionOutOfRange, TranspositionOutOfRange,
/// A `CreateMeasure` (or a prospective preservation check) found a
/// resolving `time_signature` that disagrees with the effective grid's
/// active signature (genesis tranche G3b, contract pin 8b) — distinct
/// from the resolution failure, which is `TargetMissing`.
MeasureMeterMismatch,
/// A `CreateMeasure`'s carried `start` is comparable to the current last
/// measure's start (contract pin 6) and is not strictly after it (genesis
/// tranche G3b, contract pin 8b).
MeasureOutOfOrder,
/// A `CreateMeasure` ordering or boundary-distance check could not be
/// verified: the two starts are not comparable (contract pin 6), or the
/// delta between them is not computable (contract pin 6b) (genesis
/// tranche G3b, contract pin 8b).
MeasureOrderUnverifiable,
} }
impl PreconditionFailureReason { impl PreconditionFailureReason {
@ -210,6 +224,10 @@ impl PreconditionFailureReason {
// Additive (Push 4a, TransposeInterval); appended past 13. // Additive (Push 4a, TransposeInterval); appended past 13.
PreconditionFailureReason::AcousticRealizationPinned => 14, PreconditionFailureReason::AcousticRealizationPinned => 14,
PreconditionFailureReason::TranspositionOutOfRange => 15, PreconditionFailureReason::TranspositionOutOfRange => 15,
// Additive (Genesis tranche G3b); appended past 15.
PreconditionFailureReason::MeasureMeterMismatch => 16,
PreconditionFailureReason::MeasureOutOfOrder => 17,
PreconditionFailureReason::MeasureOrderUnverifiable => 18,
} }
} }
} }
@ -243,6 +261,10 @@ impl PreconditionFailureReason {
// Minor 7 (Push 4a). // Minor 7 (Push 4a).
PreconditionFailureReason::AcousticRealizationPinned => Some(7), PreconditionFailureReason::AcousticRealizationPinned => Some(7),
PreconditionFailureReason::TranspositionOutOfRange => Some(7), PreconditionFailureReason::TranspositionOutOfRange => Some(7),
// Minor 12 (Genesis tranche G3b).
PreconditionFailureReason::MeasureMeterMismatch => Some(12),
PreconditionFailureReason::MeasureOutOfOrder => Some(12),
PreconditionFailureReason::MeasureOrderUnverifiable => Some(12),
} }
} }
} }
@ -512,6 +534,41 @@ mod tests {
); );
} }
/// (M5/M6/M7, M8/M9/M10) Genesis tranche G3b: the three new
/// `PreconditionFailureReason` variants sit at discriminants 16, 17, 18
/// (contract pin 8b), each at epoch `Some(12)`.
///
/// **Mutation M5/M6/M7:** move any one discriminant to 19 (unused, so it
/// compiles); must fail. **Mutation M8/M9/M10:** move any one
/// `introduced_minor()` to `Some(11)`; must fail.
#[test]
fn genesis_g3b_reasons_are_16_17_18_at_epoch_12() {
assert_eq!(
PreconditionFailureReason::MeasureMeterMismatch.to_canonical_bytes(),
vec![16]
);
assert_eq!(
PreconditionFailureReason::MeasureOutOfOrder.to_canonical_bytes(),
vec![17]
);
assert_eq!(
PreconditionFailureReason::MeasureOrderUnverifiable.to_canonical_bytes(),
vec![18]
);
assert_eq!(
PreconditionFailureReason::MeasureMeterMismatch.introduced_minor(),
Some(12)
);
assert_eq!(
PreconditionFailureReason::MeasureOutOfOrder.introduced_minor(),
Some(12)
);
assert_eq!(
PreconditionFailureReason::MeasureOrderUnverifiable.introduced_minor(),
Some(12)
);
}
#[test] #[test]
fn voice_promotion_repair_round_trips_shape() { fn voice_promotion_repair_round_trips_shape() {
let r = RepairRecord { let r = RepairRecord {

View File

@ -32,7 +32,7 @@
use std::collections::BTreeSet; use std::collections::BTreeSet;
use epiphany_core::{ use epiphany_core::{
AnalysisLayer, CanvasLayoutDefaults, EventId, Instrument, InstrumentId, MetricGrid, AnalysisLayer, CanvasLayoutDefaults, EventId, Instrument, InstrumentId, Measure, MetricGrid,
MusicalPosition, OperationId, PartDefinition, PitchId, PitchSpelling, RegionId, MusicalPosition, OperationId, PartDefinition, PitchId, PitchSpelling, RegionId,
RegionTimeModel, RepeatStructureId, ReplicaId, ScoreMetadata, SpellingPrecedence, Staff, RegionTimeModel, RepeatStructureId, ReplicaId, ScoreMetadata, SpellingPrecedence, Staff,
StaffGroup, StaffInstance, StaffInstanceId, StaffLineConfiguration, TimeAnchor, TimeSignature, StaffGroup, StaffInstance, StaffInstanceId, StaffLineConfiguration, TimeAnchor, TimeSignature,
@ -612,6 +612,10 @@ fn operation_kind(r: &mut Reader<'_>) -> Result<OperationKind> {
38 => OperationKind::CreateView(CreateViewOp { 38 => OperationKind::CreateView(CreateViewOp {
view: value::<ViewDefinition>(r, "ViewDefinition")?, view: value::<ViewDefinition>(r, "ViewDefinition")?,
}), }),
39 => OperationKind::CreateMeasure(CreateMeasureOp {
instance: staff_instance_id(r)?,
measure: value::<Measure>(r, "Measure")?,
}),
tag => { tag => {
return Err(EnvelopeDecodeError::InvalidTag { return Err(EnvelopeDecodeError::InvalidTag {
kind: "OperationKind", kind: "OperationKind",
@ -948,6 +952,16 @@ pub(crate) mod tests {
), ),
}) })
} }
OperationKindTag::CreateMeasure => {
OperationKind::CreateMeasure(crate::payload::CreateMeasureOp {
instance: si(),
measure: valuegen::measure(
epiphany_core::MeasureId::new(ReplicaId(7), 1),
epiphany_core::TimeSignatureId::new(ReplicaId(7), 1),
1,
),
})
}
} }
} }

View File

@ -91,7 +91,7 @@ fn pitch(n: u64) -> PitchId {
/// Generates a random payload over the shared id space. /// Generates a random payload over the shared id space.
fn gen_payload(rng: &mut SplitMix64) -> OperationPayload { fn gen_payload(rng: &mut SplitMix64) -> OperationPayload {
let kind = match rng.below(36) { let kind = match rng.below(37) {
0 => { 0 => {
let voice = VoiceId::new(ReplicaId(7), rng.below(3)); let voice = VoiceId::new(ReplicaId(7), rng.below(3));
let position = MusicalPosition(RationalTime::from_int(rng.below(4) as i32)); let position = MusicalPosition(RationalTime::from_int(rng.below(4) as i32));
@ -329,6 +329,17 @@ fn gen_payload(rng: &mut SplitMix64) -> OperationPayload {
vec![AnalysisLayerId::new(ReplicaId(7), rng.below(2))], vec![AnalysisLayerId::new(ReplicaId(7), rng.below(2))],
), ),
}), }),
// Genesis tranche G3b: append a measure onto the shared staff-instance
// id space, over the shared measure/time-signature id spaces so
// mints/re-carries genuinely interact with them.
36 => OperationKind::CreateMeasure(crate::payload::CreateMeasureOp {
instance: StaffInstanceId::new(ReplicaId(7), rng.below(3)),
measure: valuegen::measure(
epiphany_core::MeasureId::new(ReplicaId(7), rng.below(4)),
epiphany_core::TimeSignatureId::new(ReplicaId(7), rng.below(2)),
rng.below(4) as u32,
),
}),
_ => OperationKind::SetStaffLayout(SetStaffLayoutOp { _ => OperationKind::SetStaffLayout(SetStaffLayoutOp {
staff_instance: StaffInstanceId::new(ReplicaId(7), rng.below(3)), staff_instance: StaffInstanceId::new(ReplicaId(7), rng.below(3)),
instrument_override: None, instrument_override: None,

View File

@ -125,17 +125,17 @@ pub use migrate::{migrate_v0_envelope, project_v1_to_v0, MigrationError};
pub use opset::{AcceptOutcome, OperationSet}; pub use opset::{AcceptOutcome, OperationSet};
pub use payload::{ pub use payload::{
operation_block_introduced_minor, ChangeRegionTimeModelOp, CreateAnalysisLayerOp, operation_block_introduced_minor, ChangeRegionTimeModelOp, CreateAnalysisLayerOp,
CreateCrossCuttingOp, CreateInstrumentOp, CreatePartDefinitionOp, CreateRegionOp, CreateCrossCuttingOp, CreateInstrumentOp, CreateMeasureOp, CreatePartDefinitionOp,
CreateRepeatStructureOp, CreateStaffGroupOp, CreateStaffInstanceOp, CreateStaffOp, CreateRegionOp, CreateRepeatStructureOp, CreateStaffGroupOp, CreateStaffInstanceOp,
CreateViewOp, CreateVoiceOp, CrossCuttingValue, DeleteCrossCuttingOp, DeleteEventOp, CreateStaffOp, CreateViewOp, CreateVoiceOp, CrossCuttingValue, DeleteCrossCuttingOp,
DeleteIdentifiedPitchOp, DeleteRegionOp, DeleteRepeatStructureOp, DeleteStaffInstanceOp, DeleteEventOp, DeleteIdentifiedPitchOp, DeleteRegionOp, DeleteRepeatStructureOp,
DeleteVoiceOp, InsertEventOp, InsertIdentifiedPitchOp, ModifyCrossCuttingOp, ModifyEventOp, DeleteStaffInstanceOp, DeleteVoiceOp, InsertEventOp, InsertIdentifiedPitchOp,
ModifyIdentifiedPitchOp, OperationKind, OperationKindTag, OperationPayload, PositionRemapping, ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp, OperationKind, OperationKindTag,
ResolveConflictPayload, ResolveEquivocationPayload, RespellPitchOp, SetCanvasLayoutDefaultsOp, OperationPayload, PositionRemapping, ResolveConflictPayload, ResolveEquivocationPayload,
SetMetadataOp, SetMetricGridOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp, RespellPitchOp, SetCanvasLayoutDefaultsOp, SetMetadataOp, SetMetricGridOp,
SetTimeSignatureOp, SetTuningContextOp, SetUserPageBreakOp, SetUserSystemBreakOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp, SetTimeSignatureOp,
TransactionCategory, TransactionDescriptor, TransposeIntervalOp, TransposeOp, SetTuningContextOp, SetUserPageBreakOp, SetUserSystemBreakOp, TransactionCategory,
TupletCompensation, TransactionDescriptor, TransposeIntervalOp, TransposeOp, TupletCompensation,
}; };
pub use reduce::{ pub use reduce::{
canonical_reduction_order, GraphMaterialization, MaterializedState, ObjectState, PendingReason, canonical_reduction_order, GraphMaterialization, MaterializedState, ObjectState, PendingReason,

View File

@ -197,6 +197,8 @@ fn project_kind(kind: &OperationKind) -> V0OperationKind {
} }
OperationKind::CreateAnalysisLayer(op) => V0OperationKind::CreateAnalysisLayer(op.clone()), OperationKind::CreateAnalysisLayer(op) => V0OperationKind::CreateAnalysisLayer(op.clone()),
OperationKind::CreateView(op) => V0OperationKind::CreateView(op.clone()), OperationKind::CreateView(op) => V0OperationKind::CreateView(op.clone()),
// Genesis tranche G3b: born past v0; projected verbatim.
OperationKind::CreateMeasure(op) => V0OperationKind::CreateMeasure(op.clone()),
} }
} }
@ -368,6 +370,8 @@ fn migrate_kind(kind: &V0OperationKind, context: &Score) -> Result<OperationKind
} }
V0OperationKind::CreateAnalysisLayer(op) => OperationKind::CreateAnalysisLayer(op.clone()), V0OperationKind::CreateAnalysisLayer(op) => OperationKind::CreateAnalysisLayer(op.clone()),
V0OperationKind::CreateView(op) => OperationKind::CreateView(op.clone()), V0OperationKind::CreateView(op) => OperationKind::CreateView(op.clone()),
// Genesis tranche G3b: identity round-trip (no lossy v0 form).
V0OperationKind::CreateMeasure(op) => OperationKind::CreateMeasure(op.clone()),
}) })
} }

View File

@ -33,13 +33,14 @@
use epiphany_core::{ use epiphany_core::{
AnalysisLayer, AnalysisLayerId, Beam, CanonicalValue, CanvasLayoutDefaults, Event, AnalysisLayer, AnalysisLayerId, Beam, CanonicalValue, CanvasLayoutDefaults, Event,
EventDuration, EventId, EventPosition, IdentifiedPitch, Instrument, InstrumentId, MetricGrid, EventDuration, EventId, EventPosition, IdentifiedPitch, Instrument, InstrumentId, Measure,
MusicalDuration, MusicalPosition, OperationId, PartDefinition, PartDefinitionId, Pitch, MeasureId, MetricGrid, MusicalDuration, MusicalPosition, OperationId, PartDefinition,
PitchId, PitchSpelling, Region, RegionId, RegionTimeModel, RepeatStructure, RepeatStructureId, PartDefinitionId, Pitch, PitchId, PitchSpelling, Region, RegionId, RegionTimeModel,
Rest, ScoreMetadata, Slur, Spanner, SpellingPrecedence, Staff, StaffGroup, StaffGroupId, RepeatStructure, RepeatStructureId, Rest, ScoreMetadata, Slur, Spanner, SpellingPrecedence,
StaffId, StaffInstance, StaffInstanceId, StaffLineConfiguration, TempoSegment, Tie, TimeAnchor, Staff, StaffGroup, StaffGroupId, StaffId, StaffInstance, StaffInstanceId,
TimeSignature, TransactionId, TranspositionInterval, TuningContextSettings, TupletId, StaffLineConfiguration, TempoSegment, Tie, TimeAnchor, TimeSignature, TransactionId,
TypedObjectId, ViewDefinition, ViewId, Voice, VoiceId, TranspositionInterval, TuningContextSettings, TupletId, TypedObjectId, ViewDefinition, ViewId,
Voice, VoiceId,
}; };
use epiphany_determinism::{ use epiphany_determinism::{
sorted_canonical, CanonicalDecode, CanonicalEncode, CanonicalSet, DecodeError, sorted_canonical, CanonicalDecode, CanonicalEncode, CanonicalSet, DecodeError,
@ -294,6 +295,15 @@ pub enum OperationKind {
/// reduction preconditions every carried active layer resolves to a live /// reduction preconditions every carried active layer resolves to a live
/// `AnalysisLayer`. /// `AnalysisLayer`.
CreateView(CreateViewOp), CreateView(CreateViewOp),
// --- Genesis tranche G3b (`spec/CONTRACT_GENESIS_G3B_MEASURE.md`): the
// final rung of the genesis ladder. Discriminant extends additively past
// 38. ---
/// Append a measure to a live staff instance (append-only set-union
/// creation, contract pin 4/9). Carries the owning instance id beside the
/// full `Measure` value, mirroring `CreateStaffInstance`: `Measure` has no
/// back-pointer to its parent, so the parent must ride along in the
/// payload (and in the reducer's carried-value map, contract pin 5).
CreateMeasure(CreateMeasureOp),
} }
impl OperationKind { impl OperationKind {
@ -415,6 +425,8 @@ impl OperationKind {
OperationKind::CreatePartDefinition(_) => 36, OperationKind::CreatePartDefinition(_) => 36,
OperationKind::CreateAnalysisLayer(_) => 37, OperationKind::CreateAnalysisLayer(_) => 37,
OperationKind::CreateView(_) => 38, OperationKind::CreateView(_) => 38,
// Genesis tranche G3b; appended past 38.
OperationKind::CreateMeasure(_) => 39,
} }
} }
@ -481,6 +493,9 @@ impl OperationKind {
| OperationKind::CreatePartDefinition(_) | OperationKind::CreatePartDefinition(_)
| OperationKind::CreateAnalysisLayer(_) | OperationKind::CreateAnalysisLayer(_)
| OperationKind::CreateView(_) => Some(11), | OperationKind::CreateView(_) => Some(11),
// Minor 12 (Genesis tranche G3b), ratified
// `spec/PLAN_GMINOR_SCHEMA_MINOR.md` §4.
OperationKind::CreateMeasure(_) => Some(12),
} }
} }
@ -536,6 +551,9 @@ impl OperationKind {
OperationKind::CreatePartDefinition(_) => OperationKindTag::CreatePartDefinition, OperationKind::CreatePartDefinition(_) => OperationKindTag::CreatePartDefinition,
OperationKind::CreateAnalysisLayer(_) => OperationKindTag::CreateAnalysisLayer, OperationKind::CreateAnalysisLayer(_) => OperationKindTag::CreateAnalysisLayer,
OperationKind::CreateView(_) => OperationKindTag::CreateView, OperationKind::CreateView(_) => OperationKindTag::CreateView,
// Genesis tranche G3b. Name-verbatim, as every genesis addition
// since G1 has been (contract pin 3's precedent).
OperationKind::CreateMeasure(_) => OperationKindTag::CreateMeasure,
} }
} }
} }
@ -586,6 +604,7 @@ impl CanonicalEncode for OperationKind {
OperationKind::CreatePartDefinition(op) => op.encode_canonical(out), OperationKind::CreatePartDefinition(op) => op.encode_canonical(out),
OperationKind::CreateAnalysisLayer(op) => op.encode_canonical(out), OperationKind::CreateAnalysisLayer(op) => op.encode_canonical(out),
OperationKind::CreateView(op) => op.encode_canonical(out), OperationKind::CreateView(op) => op.encode_canonical(out),
OperationKind::CreateMeasure(op) => op.encode_canonical(out),
} }
} }
} }
@ -650,6 +669,8 @@ pub enum OperationKindTag {
CreateAnalysisLayer, CreateAnalysisLayer,
/// Genesis tranche G3a. /// Genesis tranche G3a.
CreateView, CreateView,
/// Genesis tranche G3b.
CreateMeasure,
} }
/// The discriminant of [`OperationKindTag::Registered`], the one tag that /// The discriminant of [`OperationKindTag::Registered`], the one tag that
@ -769,6 +790,7 @@ operation_kind_tag_vocabulary! {
CreatePartDefinition = 36 => "create-part-definition" @ Some(11), CreatePartDefinition = 36 => "create-part-definition" @ Some(11),
CreateAnalysisLayer = 37 => "create-analysis-layer" @ Some(11), CreateAnalysisLayer = 37 => "create-analysis-layer" @ Some(11),
CreateView = 38 => "create-view" @ Some(11), CreateView = 38 => "create-view" @ Some(11),
CreateMeasure = 39 => "create-measure" @ Some(12),
} }
impl CanonicalEncode for OperationKindTag { impl CanonicalEncode for OperationKindTag {
@ -1856,6 +1878,39 @@ impl CanonicalEncode for CreateViewOp {
} }
} }
// --- Genesis tranche G3b (`spec/CONTRACT_GENESIS_G3B_MEASURE.md`): the final
// rung of the genesis ladder. `Measure` is a nested container child of
// `StaffInstance`, not a `Score`-root vector, so this rides
// `CreateStaffInstance`'s parent-carrying shape (contract pin 4), not the
// nine root-level mints' bare-value shape above. ---
/// Append a `Measure` to a live `StaffInstance` (operation_catalog
/// §CreateMeasure). Carries the owning instance id beside the full `Measure`
/// value — `Measure` has no back-pointer to its parent (`graph.rs`), so the
/// parent must ride along, exactly like `CreateStaffInstanceOp::region`.
/// Append-only set-union creation (contract pin 9): the measure is pushed at
/// the end of `instance.measures`, gated on ordering, meter agreement, and
/// boundary-distance preconditions against the effective grid.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct CreateMeasureOp {
pub instance: StaffInstanceId,
pub measure: Measure,
}
impl CreateMeasureOp {
/// The appended measure's identifier.
pub fn measure_id(&self) -> MeasureId {
self.measure.id
}
}
impl CanonicalEncode for CreateMeasureOp {
fn encode_canonical(&self, out: &mut Vec<u8>) {
push_canon(out, &self.instance);
push_lp_bytes(out, &self.measure.canonical_bytes());
}
}
/// Set, replace, or (`None`) remove the single meter change at the anchor's /// Set, replace, or (`None`) remove the single meter change at the anchor's
/// resolved musical position in a region's default metric grid /// resolved musical position in a region's default metric grid
/// (operation_catalog §"Meter and Tempo Overwrites"). Carries the full /// (operation_catalog §"Meter and Tempo Overwrites"). Carries the full
@ -2765,4 +2820,128 @@ mod tests {
let rev = CrossCuttingValue::Slur(crate::valuegen::slur(s, b, a)); let rev = CrossCuttingValue::Slur(crate::valuegen::slur(s, b, a));
assert_ne!(fwd.to_canonical_bytes(), rev.to_canonical_bytes()); assert_ne!(fwd.to_canonical_bytes(), rev.to_canonical_bytes());
} }
// -----------------------------------------------------------------
// Genesis tranche G3b (`spec/CONTRACT_GENESIS_G3B_MEASURE.md`).
// -----------------------------------------------------------------
fn g3b_sample_measure() -> Measure {
crate::valuegen::measure(
MeasureId::new(ReplicaId(1), 1),
epiphany_core::TimeSignatureId::new(ReplicaId(1), 1),
1,
)
}
/// (M1/M2) `CreateMeasure`'s kind discriminant and tag discriminant are
/// both 39, in both discriminant spaces (contract pin 1).
///
/// **Mutation M1:** move the kind discriminant to 40; must fail.
/// **Mutation M2:** move the tag discriminant to 40; must fail. (The two
/// spaces are asserted independently — a G-minor lesson from
/// `TransposeInterval`.)
#[test]
fn g3b_m1_m2_kind_and_tag_discriminant_are_39() {
let kind = OperationKind::CreateMeasure(CreateMeasureOp {
instance: StaffInstanceId::new(ReplicaId(1), 1),
measure: g3b_sample_measure(),
});
let mut bytes = Vec::new();
kind.encode_canonical(&mut bytes);
assert_eq!(bytes[0], 39, "the kind discriminant byte must lead");
assert_eq!(kind.tag(), OperationKindTag::CreateMeasure);
assert_eq!(OperationKindTag::CreateMeasure.discriminant(), 39);
}
/// (M3/M4) `CreateMeasure`'s epoch is `Some(12)` in BOTH the kind's own
/// `introduced_minor()` and the tag vocabulary's epoch.
///
/// **Mutation M3:** change `OperationKind::introduced_minor()`'s
/// `CreateMeasure` arm to `Some(11)`; must fail.
/// **Mutation M4:** change the tag vocabulary's `@ Some(12)` to
/// `Some(11)`; must fail.
#[test]
fn g3b_m3_m4_epoch_is_12_in_both_spaces() {
let kind = OperationKind::CreateMeasure(CreateMeasureOp {
instance: StaffInstanceId::new(ReplicaId(1), 1),
measure: g3b_sample_measure(),
});
assert_eq!(kind.introduced_minor(), Some(12));
assert_eq!(OperationKindTag::CreateMeasure.introduced_minor(), Some(12));
}
/// (M11) `CreateMeasure` gains NO `schema_major()` arm (pin 2: `Measure`
/// is schema major 0, so `OperationEnvelopeBlock` stays at 3). A block
/// containing ONLY a `CreateMeasure` envelope stamps major 0 — the block
/// composition is load-bearing: a mixed block would stamp from another
/// kind and pass even with an errant arm present.
///
/// **Mutation:** add `OperationKind::CreateMeasure(_) => 3` to
/// `schema_major()`; must fail.
#[test]
fn g3b_m11_create_measure_only_block_stamps_major_zero() {
let kind = OperationKind::CreateMeasure(CreateMeasureOp {
instance: StaffInstanceId::new(ReplicaId(1), 1),
measure: g3b_sample_measure(),
});
assert_eq!(
kind.schema_major(),
0,
"CreateMeasure falls through the catch-all _ => 0 arm"
);
let envelopes = [envelope(
1,
OperationPayload::Primitive(OperationKind::CreateMeasure(CreateMeasureOp {
instance: StaffInstanceId::new(ReplicaId(1), 1),
measure: g3b_sample_measure(),
})),
)];
let major = envelopes
.iter()
.map(|e| e.schema_major())
.max()
.expect("one envelope");
assert_eq!(
major, 0,
"a block carrying only CreateMeasure stamps major 0"
);
}
/// (M13) `CreateMeasureOp::encode_canonical` pushes the parent
/// `StaffInstanceId` THEN the value — mirroring `CreateStaffInstanceOp`
/// (contract pin 4). Frozen literal bytes, not a round-trip assertion:
/// swapping the two fields' encode order round-trips fine on its own
/// (each half decodes to the right type), so only a byte literal catches
/// the reorder.
///
/// **Mutation:** swap the two `push_canon`/`push_lp_bytes` calls in
/// `CreateMeasureOp::encode_canonical`; must fail.
#[test]
fn g3b_m13_create_measure_op_encodes_parent_then_value() {
let op = CreateMeasureOp {
instance: StaffInstanceId::new(ReplicaId(1), 7),
measure: g3b_sample_measure(),
};
let mut bytes = Vec::new();
op.encode_canonical(&mut bytes);
// The instance id leads: its own canonical form (`push_canon`) is a
// fixed-width id encoding, and this exact prefix is what a
// parent/value swap would move.
let mut instance_bytes = Vec::new();
push_canon(&mut instance_bytes, &op.instance);
assert!(
bytes.starts_with(&instance_bytes),
"the parent StaffInstanceId must be the first bytes encoded"
);
let mut value_bytes = Vec::new();
push_lp_bytes(&mut value_bytes, &op.measure.canonical_bytes());
assert_eq!(
bytes.len(),
instance_bytes.len() + value_bytes.len(),
"the payload is exactly parent-bytes then value-bytes, nothing else"
);
assert_eq!(&bytes[instance_bytes.len()..], &value_bytes[..]);
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -9,15 +9,15 @@ use unicode_normalization::UnicodeNormalization;
use crate::payload::{ use crate::payload::{
ChangeRegionTimeModelOp, CreateAnalysisLayerOp, CreateCrossCuttingOp, CreateInstrumentOp, ChangeRegionTimeModelOp, CreateAnalysisLayerOp, CreateCrossCuttingOp, CreateInstrumentOp,
CreatePartDefinitionOp, CreateRegionOp, CreateRepeatStructureOp, CreateStaffGroupOp, CreateMeasureOp, CreatePartDefinitionOp, CreateRegionOp, CreateRepeatStructureOp,
CreateStaffInstanceOp, CreateStaffOp, CreateViewOp, CreateVoiceOp, DeleteCrossCuttingOp, CreateStaffGroupOp, CreateStaffInstanceOp, CreateStaffOp, CreateViewOp, CreateVoiceOp,
DeleteEventOp, DeleteIdentifiedPitchOp, DeleteRegionOp, DeleteRepeatStructureOp, DeleteCrossCuttingOp, DeleteEventOp, DeleteIdentifiedPitchOp, DeleteRegionOp,
DeleteStaffInstanceOp, DeleteVoiceOp, InsertEventOp, InsertIdentifiedPitchOp, DeleteRepeatStructureOp, DeleteStaffInstanceOp, DeleteVoiceOp, InsertEventOp,
ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp, OperationKind, OperationKindTag, InsertIdentifiedPitchOp, ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp,
RespellPitchOp, SetCanvasLayoutDefaultsOp, SetMetadataOp, SetMetricGridOp, OperationKind, OperationKindTag, RespellPitchOp, SetCanvasLayoutDefaultsOp, SetMetadataOp,
SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp, SetTimeSignatureOp, SetMetricGridOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp,
SetTuningContextOp, SetUserPageBreakOp, SetUserSystemBreakOp, TransactionDescriptor, SetTimeSignatureOp, SetTuningContextOp, SetUserPageBreakOp, SetUserSystemBreakOp,
TransposeIntervalOp, TransposeOp, TransactionDescriptor, TransposeIntervalOp, TransposeOp,
}; };
use crate::support::OperationKindRegistryId; use crate::support::OperationKindRegistryId;
@ -241,6 +241,10 @@ impl TextValue for OperationKind {
production(self.tag(), vec![op.layer.project()]) production(self.tag(), vec![op.layer.project()])
} }
OperationKind::CreateView(op) => production(self.tag(), vec![op.view.project()]), OperationKind::CreateView(op) => production(self.tag(), vec![op.view.project()]),
OperationKind::CreateMeasure(op) => production(
self.tag(),
vec![op.instance.project(), op.measure.project()],
),
} }
} }
@ -618,6 +622,15 @@ impl TextValue for OperationKind {
view: TextValue::parse(view)?, view: TextValue::parse(view)?,
}) })
} }
OperationKindTag::CreateMeasure => {
let [instance, measure] = fields(s, tag, 2)? else {
unreachable!("the arity-2 check returned two fields")
};
OperationKind::CreateMeasure(CreateMeasureOp {
instance: TextValue::parse(instance)?,
measure: TextValue::parse(measure)?,
})
}
}) })
} }
} }
@ -671,7 +684,7 @@ mod tests {
#[test] #[test]
fn every_operation_kind_round_trips_with_canonical_text() { fn every_operation_kind_round_trips_with_canonical_text() {
let tags: Vec<_> = all_tags().collect(); let tags: Vec<_> = all_tags().collect();
assert_eq!(tags.len(), 39, "the grammar has 39 kind productions"); assert_eq!(tags.len(), 40, "the grammar has 40 kind productions");
for tag in tags { for tag in tags {
round_trip(&sample_kind(tag)); round_trip(&sample_kind(tag));
} }

View File

@ -123,6 +123,10 @@ pub enum V0OperationKind {
CreatePartDefinition(crate::payload::CreatePartDefinitionOp), CreatePartDefinition(crate::payload::CreatePartDefinitionOp),
CreateAnalysisLayer(crate::payload::CreateAnalysisLayerOp), CreateAnalysisLayer(crate::payload::CreateAnalysisLayerOp),
CreateView(crate::payload::CreateViewOp), CreateView(crate::payload::CreateViewOp),
// Genesis tranche G3b — born at wire-disc 39; no lossy v0 form (v0
// predates the catalog entirely), so it round-trips by identity like
// every other v1-native kind above.
CreateMeasure(crate::payload::CreateMeasureOp),
} }
/// v0 `InsertEvent`: the event was a bare [`EventId`] plus the reduction-relevant /// v0 `InsertEvent`: the event was a bare [`EventId`] plus the reduction-relevant

View File

@ -17,14 +17,14 @@ use std::collections::BTreeMap;
use epiphany_core::{ use epiphany_core::{
AcousticPitch, AcousticRealization, AleatoricAnchoringDiscipline, AleatoricTimeModel, AcousticPitch, AcousticRealization, AleatoricAnchoringDiscipline, AleatoricTimeModel,
AnalysisLayerId, AnchorOffset, Beam, BeamId, CmnNominal, Event, EventId, EventOrderingDAG, AnalysisLayerId, AnchorOffset, Beam, BeamId, CmnNominal, Event, EventId, EventOrderingDAG,
EventPosition, IdentifiedPitch, MetricTimeModel, MusicalDuration, MusicalPosition, EventPosition, IdentifiedPitch, Measure, MeasureId, MeasureNumberVisibility, MetricTimeModel,
PartDefinitionId, Pitch, PitchId, PitchSpaceId, PitchSpacePosition, PitchSpelling, MusicalDuration, MusicalPosition, PartDefinitionId, Pitch, PitchId, PitchSpaceId,
PitchedEvent, ProportionalTimeModel, Region, RegionContent, RegionEdge, RegionId, PitchSpacePosition, PitchSpelling, PitchedEvent, ProportionalTimeModel, Region, RegionContent,
RegionTimeModel, RepeatKind, RepeatStructure, RepeatStructureId, Rest, ScalePosition, Slur, RegionEdge, RegionId, RegionTimeModel, RepeatKind, RepeatStructure, RepeatStructureId, Rest,
SlurId, SpellingAttachment, SpellingDirective, SpellingScope, SpellingSource, ScalePosition, Slur, SlurId, SpellingAttachment, SpellingDirective, SpellingScope,
StaffBasedContent, StaffExtent, StaffGroupId, StaffId, StaffInstance, StaffInstanceId, SpellingSource, StaffBasedContent, StaffExtent, StaffGroupId, StaffId, StaffInstance,
StemConfiguration, Tie, TieClass, TieId, TimeAnchor, TimeExtent, ViewId, Voice, VoiceId, StaffInstanceId, StemConfiguration, Tie, TieClass, TieId, TimeAnchor, TimeExtent,
VoiceOrigin, Volta, WallClockDuration, WallClockTime, TimeSignatureId, ViewId, Voice, VoiceId, VoiceOrigin, Volta, WallClockDuration, WallClockTime,
}; };
/// A deterministic, fully-specified C4 pitch in the cmn-12 space — the neutral /// A deterministic, fully-specified C4 pitch in the cmn-12 space — the neutral
@ -424,6 +424,38 @@ pub fn view(id: ViewId, active_layers: Vec<AnalysisLayerId>) -> epiphany_core::V
} }
} }
/// A minimal [`Measure`] (genesis tranche G3b) — the value a `CreateMeasure`
/// appends: anchored to a `WallClock` point (deliberately, over an id-carrying
/// shape — see below), with an explicit signature reference and number.
///
/// **Field-length distinguishability (contract §3's `valuegen` trap, from
/// G3a's `analysis_layer` mistake — a name that happened to share its
/// encoded byte width with the 16-byte `id` field made a field-swap mutation
/// byte-invisible):** `Measure` has five fields; this fixture's chosen
/// encodings are MUTUALLY DISTINCT in length — `id` (an identifier, a
/// length-prefixed leaf: 4-byte length + 16-byte payload = 20 bytes),
/// `start` (a `WallClock` anchor: 1-byte variant tag + a `WallClockTime` leaf,
/// 4+8 = 12 bytes, so 13 total — deliberately not an `Event`/`Measure`/
/// `Region` anchor, whose embedded id-leaf would collide with `id`'s own
/// width), `time_signature` (`Some`: 1-byte tag + a 20-byte id-leaf = 21
/// bytes), `explicit_number` (`Some`: 1-byte tag + a bare 4-byte `u32`, NOT
/// leaf-framed = 5 bytes), and `number_visibility` (a C-style enum: 1 tag
/// byte, no leaf framing) — 20, 13, 21, 5, 1 are pairwise distinct, so a
/// `struct_codec!` field reorder (M12) changes the byte layout, not merely
/// reinterprets it. Verified against `leaf_codec!`/`Option<T>`/`u32`'s actual
/// `Codec` impls (`codec.rs`), not assumed.
pub fn measure(id: MeasureId, time_signature: TimeSignatureId, explicit_number: u32) -> Measure {
Measure {
id,
start: TimeAnchor::WallClock {
time: WallClockTime(1_000_000_000 * i64::from(explicit_number)),
},
time_signature: Some(time_signature),
explicit_number: Some(explicit_number),
number_visibility: MeasureNumberVisibility::Auto,
}
}
/// Canvas layout defaults with an `nth`-distinct page width (genesis tranche /// Canvas layout defaults with an `nth`-distinct page width (genesis tranche
/// G2a) — distinct `nth` give distinct `CanvasLayoutDefaults` values so a /// G2a) — distinct `nth` give distinct `CanvasLayoutDefaults` values so a
/// harness can drive concurrent `SetCanvasLayoutDefaults`s, an advisory LWW /// harness can drive concurrent `SetCanvasLayoutDefaults`s, an advisory LWW

View File

@ -564,6 +564,45 @@ pub fn decode_vectors() -> Vec<DecodeVector> {
view_trailing, view_trailing,
)); ));
// Genesis tranche G3b (kind 39, `spec/CONTRACT_GENESIS_G3B_MEASURE.md`).
let measure_envelope = OperationEnvelope {
id: OperationId::new(ReplicaId(1), 9),
author: crate::support::AuthorId(0),
stamp: crate::stamp::OperationStamp::new(
crate::stamp::HybridLogicalClock::new(epiphany_core::WallClockTime(1), 1),
OperationId::new(ReplicaId(1), 9),
),
causal_context: crate::causal::CausalContext::new(),
transaction: None,
payload: crate::payload::OperationPayload::Primitive(
crate::payload::OperationKind::CreateMeasure(crate::payload::CreateMeasureOp {
instance: epiphany_core::StaffInstanceId::new(ReplicaId(1), 1),
measure: crate::valuegen::measure(
epiphany_core::MeasureId::new(ReplicaId(1), 1),
epiphany_core::TimeSignatureId::new(ReplicaId(1), 1),
1,
),
}),
),
};
let measure_envelope_bytes = measure_envelope.to_canonical_bytes();
v.push(row(
OE,
"accept",
"-",
"create_measure",
measure_envelope_bytes.clone(),
));
let mut measure_trailing = measure_envelope_bytes;
measure_trailing.push(0);
v.push(row(
OE,
"reject",
"trailing-bytes",
"create_measure_trailing",
measure_trailing,
));
v v
} }

View File

@ -34,23 +34,23 @@ use epiphany_ops::{
AnomalousReplicaSegment, AuthorId, CausalContext, ChangeRegionTimeModelOp, ConflictId, AnomalousReplicaSegment, AuthorId, CausalContext, ChangeRegionTimeModelOp, ConflictId,
ConflictKind, ConflictKindRegistryId, ConflictRecord, ConflictRegistry, ConflictKind, ConflictKindRegistryId, ConflictRecord, ConflictRegistry,
ConflictResolutionState, CreateAnalysisLayerOp, CreateCrossCuttingOp, CreateInstrumentOp, ConflictResolutionState, CreateAnalysisLayerOp, CreateCrossCuttingOp, CreateInstrumentOp,
CreatePartDefinitionOp, CreateRegionOp, CreateRepeatStructureOp, CreateStaffGroupOp, CreateMeasureOp, CreatePartDefinitionOp, CreateRegionOp, CreateRepeatStructureOp,
CreateStaffInstanceOp, CreateStaffOp, CreateViewOp, CreateVoiceOp, CrossCuttingValue, CreateStaffGroupOp, CreateStaffInstanceOp, CreateStaffOp, CreateViewOp, CreateVoiceOp,
DeleteCrossCuttingOp, DeleteEventOp, DeleteIdentifiedPitchOp, DeleteRegionOp, CrossCuttingValue, DeleteCrossCuttingOp, DeleteEventOp, DeleteIdentifiedPitchOp,
DeleteRepeatStructureOp, DeleteStaffInstanceOp, DeleteVoiceOp, ExtensionPreconditionId, DeleteRegionOp, DeleteRepeatStructureOp, DeleteStaffInstanceOp, DeleteVoiceOp,
FieldPath, HybridLogicalClock, InsertEventOp, InsertIdentifiedPitchOp, IntegrityAnomaly, ExtensionPreconditionId, FieldPath, HybridLogicalClock, InsertEventOp, InsertIdentifiedPitchOp,
IntegrityAnomalyKind, IntegrityAnomalyRegistryId, MaterializedState, ModifyCrossCuttingOp, IntegrityAnomaly, IntegrityAnomalyKind, IntegrityAnomalyRegistryId, MaterializedState,
ModifyEventOp, ModifyIdentifiedPitchOp, NoOpReason, ObjectKind, ObjectState, OperationEffect, ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp, NoOpReason, ObjectKind,
OperationEnvelope, OperationKind, OperationKindRegistryId, OperationPayload, OperationSet, ObjectState, OperationEffect, OperationEnvelope, OperationKind, OperationKindRegistryId,
OperationStamp, PendingReason, PositionRemapping, PreconditionFailureReason, OperationPayload, OperationSet, OperationStamp, PendingReason, PositionRemapping,
PreconditionFailureRegistryId, ReanchorReason, ReanchorReasonRegistryId, ReanchorResult, PreconditionFailureReason, PreconditionFailureRegistryId, ReanchorReason,
RepairKind, RepairKindRegistryId, RepairRecord, ReplicaAnomalyReason, ReplicaAnomalyRegistryId, ReanchorReasonRegistryId, ReanchorResult, RepairKind, RepairKindRegistryId, RepairRecord,
ResolutionAction, ResolutionRegistryId, ResolveConflictPayload, RespellPitchOp, ReplicaAnomalyReason, ReplicaAnomalyRegistryId, ResolutionAction, ResolutionRegistryId,
SerializedCanonicalInputs, SetCanvasLayoutDefaultsOp, SetMetadataOp, SetMetricGridOp, ResolveConflictPayload, RespellPitchOp, SerializedCanonicalInputs, SetCanvasLayoutDefaultsOp,
SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp, SetTimeSignatureOp, SetMetadataOp, SetMetricGridOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp,
SetTuningContextOp, SetUserPageBreakOp, SetUserSystemBreakOp, TransactionCategory, SetTimeSignatureOp, SetTuningContextOp, SetUserPageBreakOp, SetUserSystemBreakOp,
TransactionDescriptor, TransposeIntervalOp, TransposeOp, TupletCompensation, TransactionCategory, TransactionDescriptor, TransposeIntervalOp, TransposeOp,
TupletCompensationKind, UndoPolicy, UndoTransactionPayload, TupletCompensation, TupletCompensationKind, UndoPolicy, UndoTransactionPayload,
}; };
use crate::rng::Rng; use crate::rng::Rng;
@ -414,7 +414,7 @@ pub fn conflict_registry(rng: &mut Rng) -> ConflictRegistry {
/// A typed precondition failure (every core and registered variant). /// A typed precondition failure (every core and registered variant).
pub fn precondition_failure_reason(rng: &mut Rng) -> PreconditionFailureReason { pub fn precondition_failure_reason(rng: &mut Rng) -> PreconditionFailureReason {
match rng.below(14) { match rng.below(19) {
0 => PreconditionFailureReason::TargetMissing, 0 => PreconditionFailureReason::TargetMissing,
1 => PreconditionFailureReason::TargetTombstoned, 1 => PreconditionFailureReason::TargetTombstoned,
2 => PreconditionFailureReason::WrongRegionTimeModel, 2 => PreconditionFailureReason::WrongRegionTimeModel,
@ -427,7 +427,15 @@ pub fn precondition_failure_reason(rng: &mut Rng) -> PreconditionFailureReason {
9 => PreconditionFailureReason::TempoMapMalformed, 9 => PreconditionFailureReason::TempoMapMalformed,
10 => PreconditionFailureReason::SystemDerivedContentImmutable, 10 => PreconditionFailureReason::SystemDerivedContentImmutable,
11 => PreconditionFailureReason::RecreateContentMismatch, 11 => PreconditionFailureReason::RecreateContentMismatch,
12 => PreconditionFailureReason::ExtensionPrecondition(ExtensionPreconditionId( // Push 4a (previously a decoder hole this generator never reached —
// P13-S20, closed by genesis tranche G3b's row 12a repair).
12 => PreconditionFailureReason::AcousticRealizationPinned,
13 => PreconditionFailureReason::TranspositionOutOfRange,
// Genesis tranche G3b.
14 => PreconditionFailureReason::MeasureMeterMismatch,
15 => PreconditionFailureReason::MeasureOutOfOrder,
16 => PreconditionFailureReason::MeasureOrderUnverifiable,
17 => PreconditionFailureReason::ExtensionPrecondition(ExtensionPreconditionId(
rng.next_u64() as u128, rng.next_u64() as u128,
)), )),
_ => PreconditionFailureReason::Registered(PreconditionFailureRegistryId( _ => PreconditionFailureReason::Registered(PreconditionFailureRegistryId(
@ -647,7 +655,7 @@ pub fn operation_payload(rng: &mut Rng, events: u64, pitches: u64) -> OperationP
} }
_ => {} _ => {}
} }
let kind = match rng.below(39) { let kind = match rng.below(40) {
0 => { 0 => {
let pitches = if rng.boolean() { let pitches = if rng.boolean() {
vec![obj_pitch(rng.below(pitches))] vec![obj_pitch(rng.below(pitches))]
@ -899,6 +907,16 @@ pub fn operation_payload(rng: &mut Rng, events: u64, pitches: u64) -> OperationP
vec![AnalysisLayerId::new(OBJ_REPLICA, rng.below(2))], vec![AnalysisLayerId::new(OBJ_REPLICA, rng.below(2))],
), ),
}), }),
// Genesis tranche G3b: append a measure onto the shared
// staff-instance id space.
38 => OperationKind::CreateMeasure(CreateMeasureOp {
instance: StaffInstanceId::new(OBJ_REPLICA, rng.below(2)),
measure: valuegen::measure(
MeasureId::new(OBJ_REPLICA, rng.below(2)),
TimeSignatureId::new(OBJ_REPLICA, rng.below(2)),
rng.below(4) as u32,
),
}),
_ => OperationKind::Registered( _ => OperationKind::Registered(
OperationKindRegistryId(rng.next_u64() as u128), OperationKindRegistryId(rng.next_u64() as u128),
rng.byte_vec(0, 16), rng.byte_vec(0, 16),
@ -1929,7 +1947,7 @@ mod tests {
/// Push-4a debt) and `CreateInstrument` (kind 31, G1 debt) went missing /// Push-4a debt) and `CreateInstrument` (kind 31, G1 debt) went missing
/// from every corpus this generator feeds despite every downstream suite /// from every corpus this generator feeds despite every downstream suite
/// staying green. Assert a bounded draw actually reaches every kind /// staying green. Assert a bounded draw actually reaches every kind
/// appended past the historically-tested range (discriminants 30..=38), /// appended past the historically-tested range (discriminants 30..=39),
/// not just that the function does not panic. /// not just that the function does not panic.
#[test] #[test]
fn operation_payload_emits_every_appended_kind() { fn operation_payload_emits_every_appended_kind() {
@ -1939,6 +1957,7 @@ mod tests {
let mut saw_tuning_context = false; let mut saw_tuning_context = false;
let (mut saw_create_staff_group, mut saw_create_part_definition) = (false, false); let (mut saw_create_staff_group, mut saw_create_part_definition) = (false, false);
let (mut saw_create_analysis_layer, mut saw_create_view) = (false, false); let (mut saw_create_analysis_layer, mut saw_create_view) = (false, false);
let mut saw_create_measure = false;
for _ in 0..2000 { for _ in 0..2000 {
let OperationPayload::Primitive(kind) = operation_payload(&mut rng, 8, 8) else { let OperationPayload::Primitive(kind) = operation_payload(&mut rng, 8, 8) else {
continue; continue;
@ -1953,6 +1972,7 @@ mod tests {
OperationKind::CreatePartDefinition(_) => saw_create_part_definition = true, OperationKind::CreatePartDefinition(_) => saw_create_part_definition = true,
OperationKind::CreateAnalysisLayer(_) => saw_create_analysis_layer = true, OperationKind::CreateAnalysisLayer(_) => saw_create_analysis_layer = true,
OperationKind::CreateView(_) => saw_create_view = true, OperationKind::CreateView(_) => saw_create_view = true,
OperationKind::CreateMeasure(_) => saw_create_measure = true,
_ => {} _ => {}
} }
} }
@ -1992,6 +2012,54 @@ mod tests {
saw_create_view, saw_create_view,
"CreateView (kind 38, G3a debt) never drawn in 2000 samples" "CreateView (kind 38, G3a debt) never drawn in 2000 samples"
); );
assert!(
saw_create_measure,
"CreateMeasure (kind 39, G3b debt) never drawn in 2000 samples"
);
}
/// (M66, row 23) `precondition_failure_reason`'s doc comment claims
/// "every core and registered variant" — assert the bounded draw
/// actually reaches every one, including the genesis tranche G3b
/// additions (1618) and the previously-untested Push 4a pair (1415,
/// P13-S20).
///
/// **Mutation:** revert `rng.below(19)` to `rng.below(14)`; must fail —
/// the generator would then never reach discriminants 14 through 18.
#[test]
fn precondition_failure_reason_reaches_every_variant() {
let mut rng = Rng::new(23);
let mut seen: std::collections::BTreeSet<u8> = std::collections::BTreeSet::new();
for _ in 0..2000 {
let reason = precondition_failure_reason(&mut rng);
let discriminant = match reason {
PreconditionFailureReason::TargetMissing => 0,
PreconditionFailureReason::TargetTombstoned => 1,
PreconditionFailureReason::WrongRegionTimeModel => 2,
PreconditionFailureReason::TupletCompensationInvalid => 3,
PreconditionFailureReason::EventDurationInvalid => 4,
PreconditionFailureReason::PositionOutsideRegion => 5,
PreconditionFailureReason::PitchSpaceMismatch => 6,
PreconditionFailureReason::VoiceMissing => 7,
PreconditionFailureReason::ContainerNotEmpty => 8,
PreconditionFailureReason::TempoMapMalformed => 9,
PreconditionFailureReason::SystemDerivedContentImmutable => 10,
PreconditionFailureReason::RecreateContentMismatch => 11,
PreconditionFailureReason::AcousticRealizationPinned => 12,
PreconditionFailureReason::TranspositionOutOfRange => 13,
PreconditionFailureReason::MeasureMeterMismatch => 14,
PreconditionFailureReason::MeasureOutOfOrder => 15,
PreconditionFailureReason::MeasureOrderUnverifiable => 16,
PreconditionFailureReason::ExtensionPrecondition(_) => 17,
PreconditionFailureReason::Registered(_) => 18,
};
seen.insert(discriminant);
}
let expected: std::collections::BTreeSet<u8> = (0..=18).collect();
assert_eq!(
seen, expected,
"the bounded draw must reach every core and registered variant"
);
} }
#[test] #[test]

View File

@ -1372,7 +1372,7 @@ mod tests {
/// (s10, row 29) `gen_operation_kind_tag`'s draw must cover exactly /// (s10, row 29) `gen_operation_kind_tag`'s draw must cover exactly
/// `PAYLOAD_FREE` `{Registered}` — **not** merely the appended /// `PAYLOAD_FREE` `{Registered}` — **not** merely the appended
/// discriminants 30..=38, which would pass even if the `Registered` /// discriminants 30..=39, which would pass even if the `Registered`
/// append (structurally different from every built-in: it is the one /// append (structurally different from every built-in: it is the one
/// variant `PAYLOAD_FREE` excludes by design, `payload.rs:469`) were /// variant `PAYLOAD_FREE` excludes by design, `payload.rs:469`) were
/// deleted from the generator entirely. /// deleted from the generator entirely.

View File

@ -306,15 +306,16 @@ fn the_kind_productions_are_the_operation_vocabulary() {
// appends a tag must bump it (genesis G1 took it from 31 to 32 by adding // appends a tag must bump it (genesis G1 took it from 31 to 32 by adding
// `CreateInstrument`; genesis G2a took it from 32 to 34 by adding // `CreateInstrument`; genesis G2a took it from 32 to 34 by adding
// `SetCanvasLayoutDefaults` and `SetSpellingPrecedence`; genesis G2b took // `SetCanvasLayoutDefaults` and `SetSpellingPrecedence`; genesis G2b took
// it from 34 to 35 by adding `SetTuningContext`; genesis G3a takes it // it from 34 to 35 by adding `SetTuningContext`; genesis G3a took it
// from 35 to 39 by adding `CreateStaffGroup`, `CreatePartDefinition`, // from 35 to 39 by adding `CreateStaffGroup`, `CreatePartDefinition`,
// `CreateAnalysisLayer`, and `CreateView`). It stays a literal on // `CreateAnalysisLayer`, and `CreateView`; genesis G3b takes it from 39
// purpose: deriving it from `PAYLOAD_FREE.len()` would make the assertion // to 40 by adding `CreateMeasure`). It stays a literal on purpose:
// deriving it from `PAYLOAD_FREE.len()` would make the assertion
// vacuous, since that is the very list it exists to pin. // vacuous, since that is the very list it exists to pin.
assert_eq!( assert_eq!(
expected.len(), expected.len(),
39, 40,
"38 payload-free kinds plus `Registered`" "39 payload-free kinds plus `Registered`"
); );
let actual = alternatives("kind"); let actual = alternatives("kind");

View File

@ -56,7 +56,7 @@ use epiphany_ops::OperationEnvelope;
/// and `create-view` to the `kind` production — the same reasoning as every /// and `create-view` to the `kind` production — the same reasoning as every
/// prior kind append: extending the grammar without moving this constant /// prior kind append: extending the grammar without moving this constant
/// would leave two incompatible grammars both claiming `(0 11 0)`. /// would leave two incompatible grammars both claiming `(0 11 0)`.
pub const COMPANION_VERSION: (u32, u32, u32) = (0, 12, 0); pub const COMPANION_VERSION: (u32, u32, u32) = (0, 13, 0);
/// A parsed canonical Text Projection document. /// A parsed canonical Text Projection document.
/// ///

View File

@ -650,11 +650,12 @@ mod tests {
// Bumped with `COMPANION_VERSION` (0.7.0 → 0.8.0, genesis G1; 0.8.0 → // Bumped with `COMPANION_VERSION` (0.7.0 → 0.8.0, genesis G1; 0.8.0 →
// 0.9.0, genesis G2a; 0.9.0 → 0.10.0, G-minor; 0.10.0 → 0.11.0, genesis // 0.9.0, genesis G2a; 0.9.0 → 0.10.0, G-minor; 0.10.0 → 0.11.0, genesis
// G2b; 0.11.0 → 0.12.0, genesis G3a). Kept a literal because `projection` // G2b; 0.11.0 → 0.12.0, genesis G3a; 0.12.0 → 0.13.0, genesis G3b). Kept
// takes `&[&str]` and a formatted String would ripple through every call // a literal because `projection` takes `&[&str]` and a formatted String
// site; `the_test_header_tracks_the_implemented_version` below fails // would ripple through every call site;
// loudly if the two ever drift. // `the_test_header_tracks_the_implemented_version` below fails loudly if
const HEADER: &str = "(text-projection (0 12 0))"; // the two ever drift.
const HEADER: &str = "(text-projection (0 13 0))";
const DOCUMENT: &str = "(document #x00000000000000000000000000000001 (schema 0 1))"; const DOCUMENT: &str = "(document #x00000000000000000000000000000001 (schema 0 1))";
/// A minimal but complete valid projection: just the two mandatory lines. /// A minimal but complete valid projection: just the two mandatory lines.

View File

@ -22,13 +22,13 @@ use epiphany_bundle::{
ReductionAlgorithmVersion, SchemaVersion, SemVer, SnapshotId, ReductionAlgorithmVersion, SchemaVersion, SemVer, SnapshotId,
}; };
use epiphany_core::{ use epiphany_core::{
AnalysisLayerId, OperationId, PartDefinitionId, RegionId, ReplicaId, StaffGroupId, StaffId, AnalysisLayerId, MeasureId, OperationId, PartDefinitionId, RegionId, ReplicaId, StaffGroupId,
ViewId, WallClockTime, StaffId, StaffInstanceId, TimeSignatureId, ViewId, WallClockTime,
}; };
use epiphany_ops::{ use epiphany_ops::{
AuthorId, CausalContext, CreateAnalysisLayerOp, CreatePartDefinitionOp, CreateStaffGroupOp, AuthorId, CausalContext, CreateAnalysisLayerOp, CreateMeasureOp, CreatePartDefinitionOp,
CreateViewOp, DeleteRegionOp, HybridLogicalClock, OperationEnvelope, OperationKind, CreateStaffGroupOp, CreateViewOp, DeleteRegionOp, HybridLogicalClock, OperationEnvelope,
OperationPayload, OperationStamp, SetTuningContextOp, OperationKind, OperationPayload, OperationStamp, SetTuningContextOp,
}; };
use crate::parse::parse_document; use crate::parse::parse_document;
@ -258,6 +258,27 @@ fn view_envelope(counter: u64, physical_time: i64) -> OperationEnvelope {
} }
} }
/// Genesis tranche G3b (kind 39, `spec/CONTRACT_GENESIS_G3B_MEASURE.md`).
/// Same rationale as `staff_group_envelope` above.
fn measure_envelope(counter: u64, physical_time: i64) -> OperationEnvelope {
let id = OperationId::new(ReplicaId(1), counter);
OperationEnvelope {
id,
author: AuthorId(0xAB),
stamp: OperationStamp::new(HybridLogicalClock::new(WallClockTime(physical_time), 0), id),
causal_context: CausalContext::new(),
transaction: None,
payload: OperationPayload::Primitive(OperationKind::CreateMeasure(CreateMeasureOp {
instance: StaffInstanceId::new(ReplicaId(1), 1),
measure: epiphany_ops::valuegen::measure(
MeasureId::new(ReplicaId(1), 1),
TimeSignatureId::new(ReplicaId(1), 1),
1,
),
})),
}
}
fn profiles(custom: bool) -> Vec<ProfileDeclaration> { fn profiles(custom: bool) -> Vec<ProfileDeclaration> {
let mut profiles = vec![ProfileDeclaration::full()]; let mut profiles = vec![ProfileDeclaration::full()];
if custom { if custom {
@ -416,6 +437,19 @@ fn accept_documents() -> Vec<(&'static str, String)> {
envelopes: vec![view_envelope(11, 1100)], envelopes: vec![view_envelope(11, 1100)],
}; };
// Genesis G3b: kind 39 in the committed corpus. Same manifest-version
// discipline as `staff_group` etc above.
let measure = TextDocument {
document_id: DocumentId([10; 16]),
manifest_schema_version: SchemaVersion::V0,
lineage_id: None,
profiles: profiles(false),
extensions: Vec::new(),
canonical_base: None,
blobs: Vec::new(),
envelopes: vec![measure_envelope(12, 1200)],
};
vec![ vec![
("minimal", project_text_document(&minimal)), ("minimal", project_text_document(&minimal)),
("set_tuning_context", project_text_document(&tuning_context)), ("set_tuning_context", project_text_document(&tuning_context)),
@ -438,6 +472,7 @@ fn accept_documents() -> Vec<(&'static str, String)> {
project_text_document(&analysis_layer), project_text_document(&analysis_layer),
), ),
("create_view", project_text_document(&view)), ("create_view", project_text_document(&view)),
("create_measure", project_text_document(&measure)),
] ]
} }
@ -522,16 +557,16 @@ pub fn document_vectors() -> Vec<TextVector> {
.collect(); .collect();
// The rejected version must be one this crate does NOT implement. Genesis // The rejected version must be one this crate does NOT implement. Genesis
// tranche G3a moved `COMPANION_VERSION` to 0.12.0, which had been this // tranche G3b moved `COMPANION_VERSION` to 0.13.0, which had been this
// vector's "future" version — leaving it would have made the negative // vector's "future" version — leaving it would have made the negative
// vector assert that the *correct* header is rejected. It now names // vector assert that the *correct* header is rejected. It now names
// 0.11.0, the immediately superseded companion, which is the better test // 0.12.0, the immediately superseded companion, which is the better test
// anyway: rejecting the version right behind you is exactly the deferred // anyway: rejecting the version right behind you is exactly the deferred
// migrate-on-read posture (`req:textproj:header-version`). // migrate-on-read posture (`req:textproj:header-version`).
let wrong_version = replace_once( let wrong_version = replace_once(
minimal, minimal,
"(text-projection (0 13 0))",
"(text-projection (0 12 0))", "(text-projection (0 12 0))",
"(text-projection (0 11 0))",
); );
vectors.push(( vectors.push((
SURFACE, SURFACE,
@ -851,7 +886,7 @@ mod tests {
#[test] #[test]
fn the_reference_implementation_agrees_with_every_vector() { fn the_reference_implementation_agrees_with_every_vector() {
match verify(COMMITTED) { match verify(COMMITTED) {
Ok(count) => assert_eq!(count, 18, "the corpus has unexpectedly thinned"), Ok(count) => assert_eq!(count, 19, "the corpus has unexpectedly thinned"),
Err(failures) => panic!( Err(failures) => panic!(
"{} disagreement(s):\n{}", "{} disagreement(s):\n{}",
failures.len(), failures.len(),
@ -890,23 +925,15 @@ mod tests {
); );
} }
/// (t11) Genesis tranche G3a: text projection round-trips all four new /// (t11) Genesis tranche G3a: text projection round-trips all four
/// kinds (`create-staff-group`, `create-part-definition`, /// kinds (`create-staff-group`, `create-part-definition`,
/// `create-analysis-layer`, `create-view`), and the companion version is /// `create-analysis-layer`, `create-view`) it added.
/// **0.12.0**, with the negative vector rejecting **0.11.0**.
/// ///
/// **Mutation:** drop one parse arm (e.g. /// **Mutation:** drop one parse arm (e.g.
/// `OperationKindTag::CreateStaffGroup` from `OperationKind::parse` in /// `OperationKindTag::CreateStaffGroup` from `OperationKind::parse` in
/// `textproj_kind.rs`); must fail. Separately, leave `COMPANION_VERSION` /// `textproj_kind.rs`); must fail.
/// at `(0, 11, 0)`; the negative vector must fail.
#[test] #[test]
fn t11_g3a_kinds_round_trip_and_companion_is_0_12_0_rejecting_0_11_0() { fn t11_g3a_kinds_round_trip() {
assert_eq!(
crate::COMPANION_VERSION,
(0, 12, 0),
"the companion version must be 0.12.0"
);
for name in [ for name in [
"create_staff_group", "create_staff_group",
"create_part_definition", "create_part_definition",
@ -927,9 +954,41 @@ mod tests {
"{name}: project(serialize(parse(T))) == T must hold" "{name}: project(serialize(parse(T))) == T must hold"
); );
} }
}
/// (t12) Genesis tranche G3b: text projection round-trips the new
/// `create-measure` kind, and the companion version is **0.13.0**, with
/// the negative vector rejecting **0.12.0** (the immediately superseded
/// companion).
///
/// **Mutation:** drop `OperationKindTag::CreateMeasure` from
/// `OperationKind::parse` in `textproj_kind.rs`; must fail. Separately,
/// leave `COMPANION_VERSION` at `(0, 12, 0)`; the negative vector must
/// fail.
#[test]
fn t12_g3b_kinds_round_trip_and_companion_is_0_13_0_rejecting_0_12_0() {
assert_eq!(
crate::COMPANION_VERSION,
(0, 13, 0),
"the companion version must be 0.13.0"
);
let name = "create_measure";
let text = accept_documents()
.into_iter()
.find(|(n, _)| *n == name)
.unwrap_or_else(|| panic!("accept document is absent: {name}"))
.1;
let document = parse_document(&text).unwrap_or_else(|e| panic!("{name} must parse: {e}"));
assert_eq!(document.envelopes.len(), 1, "{name} carries one envelope");
let reprojected = project_text_document(&document);
assert_eq!(
reprojected, text,
"{name}: project(serialize(parse(T))) == T must hold"
);
// The negative vector must reject exactly the immediately superseded // The negative vector must reject exactly the immediately superseded
// companion, 0.11.0. // companion, 0.12.0.
let rows = parse(COMMITTED).expect("the committed corpus parses"); let rows = parse(COMMITTED).expect("the committed corpus parses");
let superseded = rows let superseded = rows
.iter() .iter()
@ -938,8 +997,8 @@ mod tests {
assert_eq!(superseded.verdict, "reject"); assert_eq!(superseded.verdict, "reject");
let text = String::from_utf8(superseded.text.clone()).expect("utf8"); let text = String::from_utf8(superseded.text.clone()).expect("utf8");
assert!( assert!(
text.contains("(text-projection (0 11 0))"), text.contains("(text-projection (0 12 0))"),
"the negative vector must name the immediately superseded companion 0.11.0, got: {text}" "the negative vector must name the immediately superseded companion 0.12.0, got: {text}"
); );
assert!( assert!(
parse_document(&text).is_err(), parse_document(&text).is_err(),

File diff suppressed because it is too large Load Diff

View File

@ -234,7 +234,7 @@
{\Large\scshape\color{epiphanyslate}Text Projection}\\[6pt] {\Large\scshape\color{epiphanyslate}Text Projection}\\[6pt]
{\large\itshape\color{epiphanyslate}A companion to the Core Specification}\\[14pt] {\large\itshape\color{epiphanyslate}A companion to the Core Specification}\\[14pt]
{\color{epiphanygold}\rule{3in}{0.8pt}}\\[24pt] {\color{epiphanygold}\rule{3in}{0.8pt}}\\[24pt]
{\normalsize\color{epiphanyink}Version 0.12.0 --- The four remaining genesis root-level entity mints reach the grammar}\\[4pt] {\normalsize\color{epiphanyink}Version 0.13.0 --- The genesis ladder closes: \texttt{create-measure} reaches the grammar}\\[4pt]
{\small\color{epiphanyslate}Normative for the text form it defines} {\small\color{epiphanyslate}Normative for the text form it defines}
\vfill \vfill
\end{titlepage} \end{titlepage}
@ -483,7 +483,7 @@ A projection is, in order:
\begin{requirement} \begin{requirement}
\label{req:textproj:header-version} \label{req:textproj:header-version}
A parser implementing this companion \MUST{} accept exactly one header A parser implementing this companion \MUST{} accept exactly one header
version: \texttt{(0 12 0)}, the version of the companion it implements. It version: \texttt{(0 13 0)}, the version of the companion it implements. It
\MUST{} reject any other version at line one. \MUST{} reject any other version at line one.
Multi-version acceptance and text migrate-on-read are deferred in the same Multi-version acceptance and text migrate-on-read are deferred in the same
@ -534,7 +534,7 @@ projection introduces no ordering of its own.
A parser \MUST{} reject every \texttt{(blob ...)} line whose blob is A parser \MUST{} reject every \texttt{(blob ...)} line whose blob is
unreferenced by canonical state unreferenced by canonical state
(Requirement~\ref{req:textproj:canonical-blobs}). At companion (Requirement~\ref{req:textproj:canonical-blobs}). At companion
version~0.12.0, neither a canonical operation nor canonical reduced state can version~0.13.0, neither a canonical operation nor canonical reduced state can
carry a \texttt{BlobId}; canonical state therefore cannot reference a blob, carry a \texttt{BlobId}; canonical state therefore cannot reference a blob,
and a parser \MUST{} reject every \texttt{(blob ...)} line. and a parser \MUST{} reject every \texttt{(blob ...)} line.
\end{requirement} \end{requirement}
@ -1066,6 +1066,7 @@ kind ::= "(insert-event " bytes " " value ")"
| "(create-part-definition " value ")" | "(create-part-definition " value ")"
| "(create-analysis-layer " value ")" | "(create-analysis-layer " value ")"
| "(create-view " value ")" | "(create-view " value ")"
| "(create-measure " value ")"
tuplet-comp ::= "not-in-tuplet" | "(replace-with-rest " value ")" tuplet-comp ::= "not-in-tuplet" | "(replace-with-rest " value ")"
| "(rewrite-tuplets (" bytes* "))" | "(rewrite-tuplets (" bytes* "))"
@ -1142,7 +1143,7 @@ A document of one operation --- a transposition of two pitches up a perfect
fifth, over a compacted base --- projects to five lines: fifth, over a compacted base --- projects to five lines:
\begin{lstlisting} \begin{lstlisting}
(text-projection (0 12 0)) (text-projection (0 13 0))
(document #x05050505050505050505050505050505 (schema 0 1)) (document #x05050505050505050505050505050505 (schema 0 1))
(profile full (0 1 0) (constraints 67108864 (retention 1 () true))) (profile full (0 1 0) (constraints 67108864 (retention 1 () true)))
(canonical-base #x1f8b0000000000000000000000000000 #x 1 full (schema 0 1) #x0000) (canonical-base #x1f8b0000000000000000000000000000 #x 1 full (schema 0 1) #x0000)

View File

@ -76,8 +76,9 @@ ops.operation_kind_tag accept - tag_35 23
ops.operation_kind_tag accept - tag_36 24 ops.operation_kind_tag accept - tag_36 24
ops.operation_kind_tag accept - tag_37 25 ops.operation_kind_tag accept - tag_37 25
ops.operation_kind_tag accept - tag_38 26 ops.operation_kind_tag accept - tag_38 26
ops.operation_kind_tag accept - tag_39 27
ops.operation_kind_tag accept - registered 1000000000000000000123456789abcdef ops.operation_kind_tag accept - registered 1000000000000000000123456789abcdef
ops.operation_kind_tag reject unknown-discriminant tag_39_one_past_the_vocabulary 27 ops.operation_kind_tag reject unknown-discriminant tag_40_one_past_the_vocabulary 28
ops.operation_kind_tag reject unknown-discriminant tag_200 c8 ops.operation_kind_tag reject unknown-discriminant tag_200 c8
ops.operation_kind_tag reject truncated tag_empty - ops.operation_kind_tag reject truncated tag_empty -
ops.operation_kind_tag reject trailing-bytes insert_event_trailing 0000 ops.operation_kind_tag reject trailing-bytes insert_event_trailing 0000
@ -100,6 +101,8 @@ ops.operation_envelope accept - create_analysis_layer 00000000000000010000000000
ops.operation_envelope reject trailing-bytes create_analysis_layer_trailing 00000000000000010000000000000007000000000000000000000000000000000100000000000000010000000000000000000001000000000000000700000000000000000000251f0000001000000000000000000000010000000000000001070000006c617965722d3100 ops.operation_envelope reject trailing-bytes create_analysis_layer_trailing 00000000000000010000000000000007000000000000000000000000000000000100000000000000010000000000000000000001000000000000000700000000000000000000251f0000001000000000000000000000010000000000000001070000006c617965722d3100
ops.operation_envelope accept - create_view 000000000000000100000000000000080000000000000000000000000000000001000000000000000100000000000000000000010000000000000008000000000000000000002636000000100000000000000000000001000000000000000106000000766965772d31010000001000000000000000000000010000000000000001 ops.operation_envelope accept - create_view 000000000000000100000000000000080000000000000000000000000000000001000000000000000100000000000000000000010000000000000008000000000000000000002636000000100000000000000000000001000000000000000106000000766965772d31010000001000000000000000000000010000000000000001
ops.operation_envelope reject trailing-bytes create_view_trailing 000000000000000100000000000000080000000000000000000000000000000001000000000000000100000000000000000000010000000000000008000000000000000000002636000000100000000000000000000001000000000000000106000000766965772d3101000000100000000000000000000001000000000000000100 ops.operation_envelope reject trailing-bytes create_view_trailing 000000000000000100000000000000080000000000000000000000000000000001000000000000000100000000000000000000010000000000000008000000000000000000002636000000100000000000000000000001000000000000000106000000766965772d3101000000100000000000000000000001000000000000000100
ops.operation_envelope accept - create_measure 0000000000000001000000000000000900000000000000000000000000000000010000000000000001000000000000000000000100000000000000090000000000000000000027000000000000000100000000000000013c0000001000000000000000000000010000000000000001030800000000ca9a3b00000000011000000000000000000000010000000000000001010100000000
ops.operation_envelope reject trailing-bytes create_measure_trailing 0000000000000001000000000000000900000000000000000000000000000000010000000000000001000000000000000000000100000000000000090000000000000000000027000000000000000100000000000000013c0000001000000000000000000000010000000000000001030800000000ca9a3b0000000001100000000000000000000001000000000000000101010000000000
# bundle.manifest # bundle.manifest
bundle.manifest accept - empty_manifest 6f9e7d11689ab113c4a1f05faf60fe60050505050505050505050505050505050000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000001000000000000000000000400000000010000000001000000000000 bundle.manifest accept - empty_manifest 6f9e7d11689ab113c4a1f05faf60fe60050505050505050505050505050505050000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000001000000000000000000000400000000010000000001000000000000

View File

@ -22,21 +22,22 @@
# document bytes are normative. `<utf8-hex>` is lowercase with no separators. # document bytes are normative. `<utf8-hex>` is lowercase with no separators.
# textproj.document # textproj.document
textproj.document accept - minimal 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a textproj.document accept - minimal 28746578742d70726f6a656374696f6e202830203133203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a
textproj.document accept - set_tuning_context 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830353035303530353035303530353035303530353035303530353035303530352028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303037202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203730302030202378303030303030303030303030303030313030303030303030303030303030303729202863617573616c2028292028292920282920287072696d697469766520287365742d74756e696e672d636f6e74657874202874756e696e672d636f6e746578742d73657474696e67732022636d6e2d31322220227465742d31322220287265666572656e63652d70697463682028636d6e2061203020342920237830303030303030303030663037623430292028736d75666c2d76657273696f6e2d726571756972656d656e742028736d75666c2d76657273696f6e2031203430292028736d75666c2d76657273696f6e20312034302929202829292929290a textproj.document accept - set_tuning_context 28746578742d70726f6a656374696f6e202830203133203029290a28646f63756d656e7420237830353035303530353035303530353035303530353035303530353035303530352028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303037202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203730302030202378303030303030303030303030303030313030303030303030303030303030303729202863617573616c2028292028292920282920287072696d697469766520287365742d74756e696e672d636f6e74657874202874756e696e672d636f6e746578742d73657474696e67732022636d6e2d31322220227465742d31322220287265666572656e63652d70697463682028636d6e2061203020342920237830303030303030303030663037623430292028736d75666c2d76657273696f6e2d726571756972656d656e742028736d75666c2d76657273696f6e2031203430292028736d75666c2d76657273696f6e20312034302929202829292929290a
textproj.document accept - lineage_custom_profile 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830323032303230323032303230323032303230323032303230323032303230322028736368656d612030203129290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a textproj.document accept - lineage_custom_profile 28746578742d70726f6a656374696f6e202830203133203029290a28646f63756d656e7420237830323032303230323032303230323032303230323032303230323032303230322028736368656d612030203129290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a
textproj.document accept - extension_base_two_envelopes 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a textproj.document accept - extension_base_two_envelopes 28746578742d70726f6a656374696f6e202830203133203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a
textproj.document accept - rich_document 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830343034303430343034303430343034303430343034303430343034303430342028736368656d612030203129290a286c696e656167652023783134313431343134313431343134313431343134313431343134313431343134290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a28657874656e73696f6e202378303230323032303230323032303230323032303230323032303230323032303220283120302032292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830332929202378303220237830323033290a2863616e6f6e6963616c2d62617365202378303430343034303430343034303430343034303430343034303430343034303420237830313032303420312066756c6c2028736368656d61203020312920237861303034290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303034202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203430302030202378303030303030303030303030303030313030303030303030303030303030303429202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030342929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303035202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203530302030202378303030303030303030303030303030313030303030303030303030303030303529202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030352929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303036202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203630302030202378303030303030303030303030303030313030303030303030303030303030303629202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030362929290a textproj.document accept - rich_document 28746578742d70726f6a656374696f6e202830203133203029290a28646f63756d656e7420237830343034303430343034303430343034303430343034303430343034303430342028736368656d612030203129290a286c696e656167652023783134313431343134313431343134313431343134313431343134313431343134290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a28657874656e73696f6e202378303230323032303230323032303230323032303230323032303230323032303220283120302032292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830332929202378303220237830323033290a2863616e6f6e6963616c2d62617365202378303430343034303430343034303430343034303430343034303430343034303420237830313032303420312066756c6c2028736368656d61203020312920237861303034290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303034202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203430302030202378303030303030303030303030303030313030303030303030303030303030303429202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030342929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303035202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203530302030202378303030303030303030303030303030313030303030303030303030303030303529202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030352929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303036202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203630302030202378303030303030303030303030303030313030303030303030303030303030303629202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030362929290a
textproj.document accept - create_staff_group 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830363036303630363036303630363036303630363036303630363036303630362028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303038202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203830302030202378303030303030303030303030303030313030303030303030303030303030303829202863617573616c2028292028292920282920287072696d697469766520286372656174652d73746166662d67726f7570202873746166662d67726f757020237830303030303030303030303030303031303030303030303030303030303030312028736f6d65202273746166662d67726f75702d312229206772616e642d737461666620282378303030303030303030303030303030313030303030303030303030303030303129292929290a textproj.document accept - create_staff_group 28746578742d70726f6a656374696f6e202830203133203029290a28646f63756d656e7420237830363036303630363036303630363036303630363036303630363036303630362028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303038202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203830302030202378303030303030303030303030303030313030303030303030303030303030303829202863617573616c2028292028292920282920287072696d697469766520286372656174652d73746166662d67726f7570202873746166662d67726f757020237830303030303030303030303030303031303030303030303030303030303030312028736f6d65202273746166662d67726f75702d312229206772616e642d737461666620282378303030303030303030303030303030313030303030303030303030303030303129292929290a
textproj.document accept - create_part_definition 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830373037303730373037303730373037303730373037303730373037303730372028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303039202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203930302030202378303030303030303030303030303030313030303030303030303030303030303929202863617573616c2028292028292920282920287072696d697469766520286372656174652d706172742d646566696e6974696f6e2028706172742d646566696e6974696f6e20237830303030303030303030303030303031303030303030303030303030303030312022706172742d312220282378303030303030303030303030303030313030303030303030303030303030303129292929290a textproj.document accept - create_part_definition 28746578742d70726f6a656374696f6e202830203133203029290a28646f63756d656e7420237830373037303730373037303730373037303730373037303730373037303730372028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303039202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203930302030202378303030303030303030303030303030313030303030303030303030303030303929202863617573616c2028292028292920282920287072696d697469766520286372656174652d706172742d646566696e6974696f6e2028706172742d646566696e6974696f6e20237830303030303030303030303030303031303030303030303030303030303030312022706172742d312220282378303030303030303030303030303030313030303030303030303030303030303129292929290a
textproj.document accept - create_analysis_layer 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830383038303830383038303830383038303830383038303830383038303830382028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303061202378303030303030303030303030303030303030303030303030303030303030616220287374616d7020313030302030202378303030303030303030303030303030313030303030303030303030303030306129202863617573616c2028292028292920282920287072696d697469766520286372656174652d616e616c797369732d6c617965722028616e616c797369732d6c61796572202378303030303030303030303030303030313030303030303030303030303030303120226c617965722d3122292929290a textproj.document accept - create_analysis_layer 28746578742d70726f6a656374696f6e202830203133203029290a28646f63756d656e7420237830383038303830383038303830383038303830383038303830383038303830382028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303061202378303030303030303030303030303030303030303030303030303030303030616220287374616d7020313030302030202378303030303030303030303030303030313030303030303030303030303030306129202863617573616c2028292028292920282920287072696d697469766520286372656174652d616e616c797369732d6c617965722028616e616c797369732d6c61796572202378303030303030303030303030303030313030303030303030303030303030303120226c617965722d3122292929290a
textproj.document accept - create_view 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830393039303930393039303930393039303930393039303930393039303930392028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303062202378303030303030303030303030303030303030303030303030303030303030616220287374616d7020313130302030202378303030303030303030303030303030313030303030303030303030303030306229202863617573616c2028292028292920282920287072696d697469766520286372656174652d766965772028766965772d646566696e6974696f6e20237830303030303030303030303030303031303030303030303030303030303030312022766965772d312220282378303030303030303030303030303030313030303030303030303030303030303129292929290a textproj.document accept - create_view 28746578742d70726f6a656374696f6e202830203133203029290a28646f63756d656e7420237830393039303930393039303930393039303930393039303930393039303930392028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303062202378303030303030303030303030303030303030303030303030303030303030616220287374616d7020313130302030202378303030303030303030303030303030313030303030303030303030303030306229202863617573616c2028292028292920282920287072696d697469766520286372656174652d766965772028766965772d646566696e6974696f6e20237830303030303030303030303030303031303030303030303030303030303030312022766965772d312220282378303030303030303030303030303030313030303030303030303030303030303129292929290a
textproj.document reject wrong-header-version superseded_companion_version 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a textproj.document accept - create_measure 28746578742d70726f6a656374696f6e202830203133203029290a28646f63756d656e7420237830613061306130613061306130613061306130613061306130613061306130612028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303063202378303030303030303030303030303030303030303030303030303030303030616220287374616d7020313230302030202378303030303030303030303030303030313030303030303030303030303030306329202863617573616c2028292028292920282920287072696d697469766520286372656174652d6d656173757265202378303030303030303030303030303030313030303030303030303030303030303120286d6561737572652023783030303030303030303030303030303130303030303030303030303030303031202877616c6c2d636c6f636b2031303030303030303030292028736f6d652023783030303030303030303030303030303130303030303030303030303030303031292028736f6d65203129206175746f292929290a
textproj.document reject blob-line unreferenced_blob 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28626c6f6220226170706c69636174696f6e2f6f637465742d73747265616d222028292023783031290a textproj.document reject wrong-header-version superseded_companion_version 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a
textproj.document reject out-of-order-sections canonical_base_before_extension 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a textproj.document reject blob-line unreferenced_blob 28746578742d70726f6a656374696f6e202830203133203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28626c6f6220226170706c69636174696f6e2f6f637465742d73747265616d222028292023783031290a
textproj.document reject repeated-singular-section lineage_repeated 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830323032303230323032303230323032303230323032303230323032303230322028736368656d612030203129290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a textproj.document reject out-of-order-sections canonical_base_before_extension 28746578742d70726f6a656374696f6e202830203133203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a
textproj.document reject operation-envelope-order envelopes_reversed 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a textproj.document reject repeated-singular-section lineage_repeated 28746578742d70726f6a656374696f6e202830203133203029290a28646f63756d656e7420237830323032303230323032303230323032303230323032303230323032303230322028736368656d612030203129290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a
textproj.document reject profile-declaration-order profiles_reversed 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830323032303230323032303230323032303230323032303230323032303230322028736368656d612030203129290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a textproj.document reject operation-envelope-order envelopes_reversed 28746578742d70726f6a656374696f6e202830203133203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a
textproj.document reject extension-declaration-order extensions_reversed 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830343034303430343034303430343034303430343034303430343034303430342028736368656d612030203129290a286c696e656167652023783134313431343134313431343134313431343134313431343134313431343134290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303230323032303230323032303230323032303230323032303230323032303220283120302032292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830332929202378303220237830323033290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303430343034303430343034303430343034303430343034303430343034303420237830313032303420312066756c6c2028736368656d61203020312920237861303034290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303034202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203430302030202378303030303030303030303030303030313030303030303030303030303030303429202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030342929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303035202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203530302030202378303030303030303030303030303030313030303030303030303030303030303529202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030352929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303036202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203630302030202378303030303030303030303030303030313030303030303030303030303030303629202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030362929290a textproj.document reject profile-declaration-order profiles_reversed 28746578742d70726f6a656374696f6e202830203133203029290a28646f63756d656e7420237830323032303230323032303230323032303230323032303230323032303230322028736368656d612030203129290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a
textproj.document reject extension-chunk-order extension_chunks_reversed 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a textproj.document reject extension-declaration-order extensions_reversed 28746578742d70726f6a656374696f6e202830203133203029290a28646f63756d656e7420237830343034303430343034303430343034303430343034303430343034303430342028736368656d612030203129290a286c696e656167652023783134313431343134313431343134313431343134313431343134313431343134290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303230323032303230323032303230323032303230323032303230323032303220283120302032292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830332929202378303220237830323033290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303430343034303430343034303430343034303430343034303430343034303420237830313032303420312066756c6c2028736368656d61203020312920237861303034290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303034202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203430302030202378303030303030303030303030303030313030303030303030303030303030303429202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030342929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303035202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203530302030202378303030303030303030303030303030313030303030303030303030303030303529202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030352929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303036202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203630302030202378303030303030303030303030303030313030303030303030303030303030303629202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030362929290a
textproj.document reject missing-trailing-lf final_lf_missing 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e20312028292074727565292929 textproj.document reject extension-chunk-order extension_chunks_reversed 28746578742d70726f6a656374696f6e202830203133203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a
textproj.document reject missing-trailing-lf final_lf_missing 28746578742d70726f6a656374696f6e202830203133203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e20312028292074727565292929