Genesis G3a: the four root-level entity mints

CreateStaffGroup (35), CreatePartDefinition (36), CreateAnalysisLayer (37),
CreateView (38) -- all schema major 0, all schema-minor epoch 11, on
CreateStaff's set-union mint pattern with byte-identical re-carry
idempotence. Completes the four remaining root-level Score entity vectors.

No epiphany-bundle change of any kind: schema_major() gained NO arm (all
four fall through the catch-all _ => 0), so the op-block accept-set stays at
3 where G2b left it. The OperationKind golden lock stays at [(OperationKind,
u8); 30] -- kinds 35-38 remain outside it by design, per P13-S15's own rung.

Closes the satisfiability half of the from-empty defect: every G3 object
kind previously became Live only through base ingest, so CreateStaff's group
precondition was unsatisfiable from empty. It does NOT make a consistent
group authorable -- §1.1 disposition B rules Staff.group the sole authority
and StaffGroup.members a non-authoritative projection G3a stores without
maintaining, with both stale forms permitted. That ruling now reaches all
four normative sites: both field doc comments (neither field was documented
before), core_spec.tex, and both the new CreateStaffGroup and the existing
CreateStaff sections of operation_catalog.tex.

Carried-value maps for all four families thread through seven sites each,
including the base seed that fails silently -- a re-carry test reducing only
from empty cannot see a missing seed, which is why t5b reduces onto a
populated base.

Verified independently, not relayed. Full gate re-run: 1429 tests / 0
failed, clippy 0, fmt clean, git diff --check clean. Two mutations the agent
had not observed were run here and observed: reverting COMPANION_VERSION to
0.11.0 kills t11 (the agent had only reasoned this), and skipping the
staff_group_values base seed kills t5b. Both reversed by editing back, with
the baseline green.

Two findings recorded rather than silently absorbed:

- valuegen::analysis_layer's name format was accidentally exactly 16 bytes,
  the same width as AnalysisLayerId's encoding, which made a field-swap
  mutation on the two-field AnalysisLayer struct byte-invisible. Shortened
  and documented -- a fixture that makes a mutation undetectable is the same
  failure class as a guard that cannot fail.
- binary_format.tex has NO Revision History row for G2b. G2b's own contract
  required one (touch row 27: "version, Revision History row"); it changed
  the payload-layout row, tag row, accept-set text and §2373 history but
  never bumped the version or added the row. The document went 0.12.0 (G2a)
  -> 0.13.0 (G-minor) -> 0.14.0 (G3a) with the accept-set raise unrecorded.
  G3a adds its own row without retroactively backfilling G2b's.

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-29 14:07:35 -04:00
parent 2892e7b2cd
commit 6c5e69f19d
35 changed files with 2683 additions and 140 deletions

View File

@ -1491,3 +1491,38 @@ not `Option`-hidden, so there is no lower-major layout for this payload to
fall back to. This is the sole surface among the nine genesis-tranche fall back to. This is the sole surface among the nine genesis-tranche
settings/creates that drags `OperationEnvelopeBlock`'s accept-set from 2 to 3 settings/creates that drags `OperationEnvelopeBlock`'s accept-set from 2 to 3
(`epiphany-bundle`'s `DECISIONS.md`). (`epiphany-bundle`'s `DECISIONS.md`).
## Genesis tranche G3a — the four root-level entity mints join
## `canonical_value!`, and `Staff.group`/`StaffGroup.members` gain their
## authority doc comments (2026-07-29)
`spec/CONTRACT_GENESIS_G3A_ENTITIES.md` adds `CreateStaffGroup`,
`CreatePartDefinition`, `CreateAnalysisLayer`, and `CreateView` to
`epiphany-ops`, closing G3a of the genesis ladder (`spec/PLAN_GENESIS_OPS.md`
§4). All four carried types — `StaffGroup`, `PartDefinition`, `AnalysisLayer`,
`ViewDefinition` — already had a `Codec` **and** a `TextValue` (both generated
by the one `struct_codec!` macro, `codec.rs:510`/`:522`), so this crate's one
required *code* change is four more `canonical_value!` lines. No new byte
layout, same as G1/G2a/G2b's entries above; `textvalue_graph.rs` needed no
change at all — the cheapest surface this tranche touches.
All four are schema major 0 as standalone payloads: neither `decode_v0_score`
nor the live `Codec` walk has ever versioned any of the four leaf types, so
none gains a `schema_major()` arm in `epiphany-ops` — all four fall into the
existing `_ => 0` catch-all, exactly G2a's shape, not G1/G2b's. Consequently no
`epiphany-bundle` change of any kind: the op-block accept-set stays at 3 where
G2b left it.
**Pin 4b.** `spec/CONTRACT_GENESIS_G3A_ENTITIES.md` §1.1 (disposition B,
ratified 2026-07-29) rules that `Staff.group` is the sole authority for group
membership and `StaffGroup.members` is a non-authoritative denormalized
projection that G3a stores but neither maintains nor trusts; both the missing-
member and the spurious-member stale forms are permitted. Both fields gained a
doc comment stating this — neither had one before — since a ruling that lives
only in a contract and a candidate ledger (filed as P13-S16) is not normative
until the fields themselves say so. `invariants.rs`'s invariant-10 doc comment
was also repaired (pin 6, doc-only — no enum entry, no discriminant, no
behaviour change): its body already resolved a staff's group, a group's
members, a part's staves, a view's active layers, and measure/grid
time-signature references; the doc comment previously named only cross-cutting
structures and event-internal references.

View File

@ -3585,6 +3585,19 @@ canonical_value! {
// `ScoreTuningContext`'s five-field walk; this makes that layout // `ScoreTuningContext`'s five-field walk; this makes that layout
// reachable per-value, exactly as `ScoreTuningContext` above is. // reachable per-value, exactly as `ScoreTuningContext` above is.
TuningContextSettings, TuningContextSettings,
// Genesis tranche G3a (`CONTRACT_GENESIS_G3A_ENTITIES.md` pin 3) — the
// four root-level mints (`CreateStaffGroup`, `CreatePartDefinition`,
// `CreateAnalysisLayer`, `CreateView`) embed the full value, mirroring
// `CreateStaff`'s `Staff` / `CreateInstrument`'s `Instrument`. All four
// already have a `Codec` (`struct_codec!` at `:1790``:1796` and `:2329`)
// and already ship inside `Score`; this makes those existing layouts
// reachable per-value, same as every other entry here. No new byte
// layout, and no `textvalue_graph.rs` work — `struct_codec!` already
// generated each type's `TextValue` impl alongside its `Codec`.
StaffGroup,
PartDefinition,
AnalysisLayer,
ViewDefinition,
} }
#[cfg(test)] #[cfg(test)]

View File

@ -816,6 +816,12 @@ pub struct Staff {
pub abbreviation: Option<String>, pub abbreviation: Option<String>,
pub instrument: InstrumentId, pub instrument: InstrumentId,
pub default_staff_lines: StaffLineConfiguration, pub default_staff_lines: StaffLineConfiguration,
/// Which staff group (if any) this staff belongs to. **The sole authority
/// for group membership** (genesis tranche G3a,
/// `spec/CONTRACT_GENESIS_G3A_ENTITIES.md` §1.1, disposition B, filed as
/// P13-S16): every consumer MUST read membership from this field, not
/// from [`StaffGroup::members`], which is a non-authoritative denormalized
/// projection that may disagree with this field in either direction.
pub group: Option<StaffGroupId>, pub group: Option<StaffGroupId>,
/// Default clef for new instances of this staff (schema major 2, /// Default clef for new instances of this staff (schema major 2,
/// appended last per the wire rule; migration default treble). /// appended last per the wire rule; migration default treble).
@ -1611,6 +1617,13 @@ pub struct StaffGroup {
pub id: StaffGroupId, pub id: StaffGroupId,
pub name: Option<String>, pub name: Option<String>,
pub kind: StaffGroupKind, pub kind: StaffGroupKind,
/// A **non-authoritative denormalized projection** of group membership
/// (genesis tranche G3a, `spec/CONTRACT_GENESIS_G3A_ENTITIES.md` §1.1,
/// disposition B, filed as P13-S16). [`Staff::group`] is the sole
/// authority: this field MUST NOT be read to decide whether a staff is in
/// a group, and MAY be stale in **both** directions — a member missing
/// here while `Staff.group` names this group, or a staff listed here
/// while its own `Staff.group` is `None` or names a different group.
pub members: Vec<StaffId>, pub members: Vec<StaffId>,
} }
@ -2066,3 +2079,82 @@ mod tests {
assert!(EventOrderingDAG::default().is_acyclic()); assert!(EventOrderingDAG::default().is_acyclic());
} }
} }
/// Genesis tranche G3a (`spec/CONTRACT_GENESIS_G3A_ENTITIES.md` pin 4b): the
/// authority-rule doc-comment guards for `Staff.group` and
/// `StaffGroup.members`.
#[cfg(test)]
mod g3a_tests {
const SOURCE: &str = include_str!("graph.rs");
/// The production portion of this file only, ending right before the
/// first `#[cfg(test)]` module. Every needle this module searches for is
/// itself written, as a string literal, inside *this* test module — so
/// searching the whole file (including this module) risks the exact
/// self-matching trap `spec/CONTRACT_GENESIS_G3A_ENTITIES.md` §4 warns
/// about: a needle that matches the guard's own source cannot fail.
/// Restricting the haystack to the code *above* any test module removes
/// that risk structurally, rather than relying on needle length alone.
fn production_source() -> &'static str {
SOURCE
.split_once("#[cfg(test)]")
.map(|(before, _)| before)
.expect("this file contains at least one #[cfg(test)] module")
}
/// (t14) `Staff.group`'s doc comment states it is authoritative for
/// group membership. Grep-assert, **sliced to that field's doc block
/// only** — `graph.rs` mentions `group` throughout, so a file-wide
/// search cannot fail.
///
/// **Mutation:** delete the doc comment (revert to no doc comment on
/// this field, its pre-G3a state); must fail.
#[test]
fn t14_staff_group_field_doc_comment_states_sole_authority() {
let source = production_source();
let start = source
.find(" /// Which staff group (if any) this staff belongs to.")
.expect("Staff.group's doc comment is present");
let end = source[start..]
.find("pub group: Option<StaffGroupId>,")
.map(|offset| start + offset)
.expect("the `group` field declaration follows its doc comment");
let doc_block = &source[start..end];
assert!(
doc_block.contains("sole authority"),
"Staff.group's doc comment must state it is the sole authority; block was:\n{doc_block}"
);
}
/// (t14) `StaffGroup.members`'s doc comment states it is a
/// non-authoritative projection that may be stale in **both**
/// directions. Grep-assert, **sliced to that field's doc block only** —
/// same discipline as the `Staff.group` guard above.
///
/// **Mutation:** delete the doc comment (revert to no doc comment on
/// this field, its pre-G3a state); must fail.
#[test]
fn t14_staff_group_members_field_doc_comment_states_non_authoritative_projection() {
let source = production_source();
let start = source
.find(" /// A **non-authoritative denormalized projection** of group")
.expect("StaffGroup.members's doc comment is present");
let end = source[start..]
.find("pub members: Vec<StaffId>,")
.map(|offset| start + offset)
.expect("the `members` field declaration follows its doc comment");
let doc_block = &source[start..end];
assert!(
doc_block.contains("non-authoritative"),
"StaffGroup.members's doc comment must state it is non-authoritative; block was:\n{doc_block}"
);
assert!(
doc_block.contains("MUST NOT be read"),
"StaffGroup.members's doc comment must forbid reading it to decide membership; block was:\n{doc_block}"
);
assert!(
doc_block.contains("both** directions"),
"StaffGroup.members's doc comment must permit staleness in both directions; block was:\n{doc_block}"
);
}
}

View File

@ -59,7 +59,15 @@ pub enum GraphInvariant {
/// 10. Every graph reference resolves to an extant object: cross-cutting /// 10. Every graph reference resolves to an extant object: cross-cutting
/// structures (incl. anchor targets, annotation layers, tuplet parents, /// structures (incl. anchor targets, annotation layers, tuplet parents,
/// graphic objects) and event-internal references (indeterminate /// graphic objects) and event-internal references (indeterminate
/// alternatives, trajectory event-pitches, graphic objects, cue sources). /// alternatives, trajectory event-pitches, graphic objects, cue sources);
/// structural top-level references (a staff's declared instrument, a
/// staff's group, a staff group's members, a part's staves, a view's
/// active layers — genesis tranche G3a repairs this prose to name what
/// the check body already enforced); and meter/time-signature
/// references at every level a `MeterChange` can appear (a region's
/// time-model meter changes, a region's default metric grid, a
/// measure's declared time signature, a staff instance's local metric
/// grid).
CrossCuttingRefsResolve, CrossCuttingRefsResolve,
/// 11. Identifiers are unique within their kind (every id kind), with /// 11. Identifiers are unique within their kind (every id kind), with
/// reserved-namespace (`SYSTEM_DERIVED`) misuse, tombstone/live /// reserved-namespace (`SYSTEM_DERIVED`) misuse, tombstone/live
@ -4074,3 +4082,60 @@ mod accidental_compatibility_tests {
.all(|v| !v.witness.contains("accidental-modification-compatibility"))); .all(|v| !v.witness.contains("accidental-modification-compatibility")));
} }
} }
/// Genesis tranche G3a (`spec/CONTRACT_GENESIS_G3A_ENTITIES.md` pin 6): the
/// invariant-10 doc-comment reconciliation guard.
#[cfg(test)]
mod g3a_tests {
const SOURCE: &str = include_str!("invariants.rs");
/// The production portion of this file only, ending right before the
/// first `#[cfg(test)]` module. Every needle this module searches for is
/// itself written, as a string literal, inside a test module — so
/// searching the whole file risks the exact self-matching trap
/// `spec/CONTRACT_GENESIS_G3A_ENTITIES.md` §4 warns about (G2b hit it
/// twice: once via a needle matching the guard's own source, once via an
/// assertion message). Restricting the haystack structurally removes
/// that risk rather than relying on needle length alone.
fn production_source() -> &'static str {
SOURCE
.split_once("#[cfg(test)]")
.map(|(before, _)| before)
.expect("this file contains at least one #[cfg(test)] module")
}
/// (t12) Invariant 10's doc comment names the four reference classes its
/// body checks (pin 6). Grep-assert the repaired prose is present
/// **within the invariant-10 doc block only** — slice the source from
/// the `/// 10.` line to the `CrossCuttingRefsResolve,` line and search
/// *that*, since searching the whole file would pass on the
/// implementation body, which contains the same identifiers the doc
/// comment is supposed to gain.
///
/// **Mutation:** revert the doc comment to its pre-G3a text (naming only
/// cross-cutting structures and event-internal references); must fail.
#[test]
fn t12_invariant_10_doc_comment_names_the_four_reference_classes() {
let source = production_source();
let start = source
.find(" /// 10. Every graph reference resolves")
.expect("invariant 10's doc comment is present");
let end = source[start..]
.find("CrossCuttingRefsResolve,")
.map(|offset| start + offset)
.expect("the CrossCuttingRefsResolve variant follows its doc comment");
let doc_block = &source[start..end];
for needle in [
"staff's group",
"group's members",
"part's staves",
"active layers",
] {
assert!(
doc_block.contains(needle),
"invariant 10's doc comment must name `{needle}`; block was:\n{doc_block}"
);
}
}
}

View File

@ -445,6 +445,27 @@ pub(crate) fn subjects_of(kind: &OperationKind, score: &Score) -> BarrierSubject
TypedObjectId::Instrument(op.instrument_id()), TypedObjectId::Instrument(op.instrument_id()),
EditContext::default(), EditContext::default(),
), ),
// Genesis tranche G3a: four more root-level `Score` entity mints,
// exactly like `CreateStaff`/`CreateInstrument` above — each names
// only the object it mints, with no resolvable region or
// staff-instance context, regardless of whether the carried value
// holds an outbound reference (`CreateStaffGroup.members`,
// `CreatePartDefinition.staves`, `CreateView.active_layers`).
OperationKind::CreateStaffGroup(op) => one(
TypedObjectId::StaffGroup(op.staff_group_id()),
EditContext::default(),
),
OperationKind::CreatePartDefinition(op) => one(
TypedObjectId::PartDefinition(op.part_definition_id()),
EditContext::default(),
),
OperationKind::CreateAnalysisLayer(op) => one(
TypedObjectId::AnalysisLayer(op.analysis_layer_id()),
EditContext::default(),
),
OperationKind::CreateView(op) => {
one(TypedObjectId::View(op.view_id()), EditContext::default())
}
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,28 +1153,30 @@ mod tests {
tag: 7 tag: 7
}) })
); );
// Operation-kind tag 35 is one past the vocabulary (the Phase-3 ops // Operation-kind tag 39 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; encodings are append-only). // genesis G2b's `SetTuningContext` 34, genesis G3a's
// `CreateStaffGroup`/`CreatePartDefinition`/`CreateAnalysisLayer`/
// `CreateView` 35..=38; 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, and 34 until genesis G2b — each time, by then, // until genesis G2a, 34 until genesis G2b, and 35 until genesis G3a —
// the number had become a real kind, so the test was pinning a bug: a // each time, by then, the number had become a real kind, so the test
// barrier that prohibited the new operation encoded fine and would // was pinning a bug: a barrier that prohibited the new operation
// not read back. It must be bumped by every tranche that appends a // encoded fine and would not read back. It must be bumped by every
// tag, and it is deliberately a literal rather than // tranche that appends a tag, and it is deliberately a literal rather
// `PAYLOAD_FREE.len()` so the bump is a conscious act. // 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![35u8]])); bytes.extend(set_blob(&[vec![39u8]]));
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: 35 tag: 39
}) })
); );
} }

View File

@ -1957,3 +1957,106 @@ inferred.
tuning context (the canonical base embeds no graph value for any `Score` tuning context (the canonical base embeds no graph value for any `Score`
field), which is exactly why a future prune must stay blocked on disposition field), which is exactly why a future prune must stay blocked on disposition
C; this packet adds no `fn prune` and no scaffolding toward one. C; this packet adds no `fn prune` and no scaffolding toward one.
## Genesis tranche G3a — `CreateStaffGroup`/`CreatePartDefinition`/
## `CreateAnalysisLayer`/`CreateView`, kinds/tags 3538 (2026-07-29)
`spec/CONTRACT_GENESIS_G3A_ENTITIES.md` lands the fourth rung: the four
remaining root-level `Score` entity mints, closing the from-empty
satisfiability gap G1 opened (`CreateStaff`'s `group` precondition was
unsatisfiable under from-empty reduction until a `StaffGroup` could be
minted). All four ride `create_staff`'s set-union mint discipline exactly
(fresh id mints; byte-identical re-carry is idempotent; a differing value
under a live id is `RecreateContentMismatch`; a tombstoned id is
`TargetTombstoned`), all at schema major 0 (pin 2: **no** `schema_major()`
arm — the catch-all `_ => 0` is correct, G2a's shape not G1/G2b's), all at
epoch 11.
**Pin 4a: four more carried-value maps, 28 touch points.**
`staff_group_values`, `part_definition_values`, `analysis_layer_values`,
`view_values` join `staff_values`/`time_signature_values`/`instrument_values`
at the same seven sites each: reducer state declaration, `WorkingSnapshot`
declaration, initialization, base seeding (`seed_from_graph` — the site that
fails silently without it, per G1's documented `instrument_values` hazard),
mint insertion, snapshot, restore. Site 4 is load-bearing and separately
mutation-tested (t13, four sub-mutations, one per family) against a dedicated
base-recarry test (t5b) that a from-empty-only re-carry test (t5) structurally
cannot exercise.
**The tombstoned branch is implemented but, like `create_staff`'s and
`create_instrument`'s, not exercised by any test.** No delete exists for any
of these six mint-only families (`CreateStaff`, `CreateInstrument`, and now
the four G3a kinds), so `ObjectState::Tombstoned` is unreachable for any of
them through the public operation API today. This is the pre-existing
project convention, not a new gap this rung introduces.
**§1.1, disposition B — the `Staff.group`/`StaffGroup.members` authority
ruling, and why `create_staff_group` does the least possible thing.**
`CreateStaffGroup` carries `members` **exactly as given** — no normalization,
no validation beyond the graph-aware liveness loop (pin 4) — and reduction
never writes `StaffGroup.members` from any other operation. `Staff.group` is
the sole authority; `StaffGroup.members` is a stored, non-authoritative,
denormalized projection that both the missing-member and spurious-member
stale forms are permitted to reach (t8b, two independent mutations: one in
`create_staff` proving disposition A's maintenance rule is *not* implemented,
one in `create_staff_group` proving non-empty `members` is *not* normalized
away). Filed as P13-S16; disposition A (the maintenance/enforcement fix) is
sequenced after G3b.
**Referential preconditions, graph-aware only, mirroring `create_staff`
exactly.** `CreateStaffGroup.members` and `CreatePartDefinition.staves` each
precondition every named id resolves to a live `Staff`; `CreateView.
active_layers` preconditions every named id resolves to a live
`AnalysisLayer`; `CreateAnalysisLayer` has no outbound reference and needs no
precondition at all — the `CreateInstrument` shape, not the `CreateStaff`
shape. All three loops are independently mutation-tested (t6, three
sub-mutations) and independently shown unenforced base-free (t7). Pin 5:
these preconditions were verified against invariant 10's existing check body
(`core/src/invariants.rs:1120``:1159`), which already resolved all three
reference classes before this rung — G3a's own contribution to invariant 10
is the doc-comment reconciliation (pin 6, doc-only, no enum entry, no
discriminant, no behaviour change), asserted structurally by a grep guard
(t12) rather than by inspection.
**t8, narrowed per §1.1.** From empty, `CreateInstrument`
`CreateStaffGroup``CreateStaff(group: Some(g))` reaches a note with the
staff's group precondition satisfied — this closes the *satisfiability* half
only. It does **not** claim a bidirectionally consistent group is authorable;
t8b pins both permitted stale forms as the honest complement.
**Decode vectors pinned to literal bytes** (`vectors.rs`, four new tests
mirroring the G1/G2a/G2b precedent), not merely round-tripped. One genuine
finding during construction: `valuegen::analysis_layer`'s original name
format (`"analysis-layer-{n}"`) happened to be exactly 16 bytes for small
counters — the same width as `AnalysisLayerId`'s canonical encoding — which
made a `struct_codec!` field swap on the two-field `AnalysisLayer` type
byte-invisible (decode-under-swap re-encodes to the identical original bytes,
since both fields are equal-width length-prefixed leaves). Fixed by
shortening the name format (`"layer-{n}"`); documented in both the helper and
the corresponding literal-byte test so the hazard does not recur silently.
All four field-swap mutations (`StaffGroup`, `PartDefinition`,
`AnalysisLayer`, `ViewDefinition`) were then observed to kill their own
vector, independently, and only their own.
**Boundary crossings, budgeted as the contract's one-time authorization.**
`editor-core/src/barriers.rs::subjects_of` gains four arms — each names only
the object it mints with `EditContext::default()`, exactly `CreateStaff`'s
and `CreateInstrument`'s shape, regardless of whether the carried value holds
an outbound reference. `layout-ir/src/barrier.rs`'s "one past the vocabulary"
literal moves 35→39. `testkit/src/generators.rs`'s `rng.below` bound moves
35→39 with four new arms and a widened `operation_payload_emits_every_
appended_kind` coverage assertion. `testkit/tests/text_projection_grammar.rs`'s
kind count moves 35→39. `testkit/src/layout_stub.rs`'s prose range comment
moves 30..=34→30..=38 (the derived `PAYLOAD_FREE`-based draw itself needed no
edit, same as G2b).
**`the_canonical_base_is_byte_identical_across_data_model_majors` re-pinned
again**, same reasoning as every prior tranche: `gen_payload` gained four
arms and its bounded draw widened, reshuffling the whole seeded RNG stream.
Nothing leaked — all four kinds are schema major 0 unconditionally and
`MaterializedState` embeds no `Score` field value for any of the four carried
types.
**No pruning or compaction is implemented, enabled, or prepared here** — pin
9's explicit non-goal, restated: G3a adds four more authored families to the
surface a future prune must not discard.

View File

@ -31,17 +31,18 @@
use std::collections::BTreeSet; use std::collections::BTreeSet;
use epiphany_core::{
AnalysisLayer, CanvasLayoutDefaults, EventId, Instrument, InstrumentId, MetricGrid,
MusicalPosition, OperationId, PartDefinition, PitchId, PitchSpelling, RegionId,
RegionTimeModel, RepeatStructureId, ReplicaId, ScoreMetadata, SpellingPrecedence, Staff,
StaffGroup, StaffInstance, StaffInstanceId, StaffLineConfiguration, TimeAnchor, TimeSignature,
TranspositionInterval, TuningContextSettings, TupletId, TypedObjectId, ViewDefinition, Voice,
VoiceId, WallClockTime,
};
use epiphany_core::{ use epiphany_core::{
Beam, Event, IdentifiedPitch, Pitch, Region, RepeatStructure, Rest, Slur, Spanner, Tie, Beam, Event, IdentifiedPitch, Pitch, Region, RepeatStructure, Rest, Slur, Spanner, Tie,
}; };
use epiphany_core::{CanonicalValue, TempoSegment}; use epiphany_core::{CanonicalValue, TempoSegment};
use epiphany_core::{
CanvasLayoutDefaults, EventId, Instrument, InstrumentId, MetricGrid, MusicalPosition,
OperationId, PitchId, PitchSpelling, RegionId, RegionTimeModel, RepeatStructureId, ReplicaId,
ScoreMetadata, SpellingPrecedence, Staff, StaffInstance, StaffInstanceId,
StaffLineConfiguration, TimeAnchor, TimeSignature, TranspositionInterval,
TuningContextSettings, TupletId, TypedObjectId, Voice, VoiceId, WallClockTime,
};
use epiphany_determinism::{CanonicalDecode, CanonicalEncode}; use epiphany_determinism::{CanonicalDecode, CanonicalEncode};
use crate::causal::CausalContext; use crate::causal::CausalContext;
@ -599,6 +600,18 @@ fn operation_kind(r: &mut Reader<'_>) -> Result<OperationKind> {
34 => OperationKind::SetTuningContext(SetTuningContextOp { 34 => OperationKind::SetTuningContext(SetTuningContextOp {
settings: value::<TuningContextSettings>(r, "TuningContextSettings")?, settings: value::<TuningContextSettings>(r, "TuningContextSettings")?,
}), }),
35 => OperationKind::CreateStaffGroup(CreateStaffGroupOp {
group: value::<StaffGroup>(r, "StaffGroup")?,
}),
36 => OperationKind::CreatePartDefinition(CreatePartDefinitionOp {
part: value::<PartDefinition>(r, "PartDefinition")?,
}),
37 => OperationKind::CreateAnalysisLayer(CreateAnalysisLayerOp {
layer: value::<AnalysisLayer>(r, "AnalysisLayer")?,
}),
38 => OperationKind::CreateView(CreateViewOp {
view: value::<ViewDefinition>(r, "ViewDefinition")?,
}),
tag => { tag => {
return Err(EnvelopeDecodeError::InvalidTag { return Err(EnvelopeDecodeError::InvalidTag {
kind: "OperationKind", kind: "OperationKind",
@ -903,6 +916,38 @@ pub(crate) mod tests {
settings: valuegen::tuning_context_settings(1), settings: valuegen::tuning_context_settings(1),
}) })
} }
OperationKindTag::CreateStaffGroup => {
OperationKind::CreateStaffGroup(crate::payload::CreateStaffGroupOp {
group: valuegen::staff_group(
epiphany_core::StaffGroupId::new(ReplicaId(7), 1),
vec![StaffId::new(ReplicaId(7), 1)],
),
})
}
OperationKindTag::CreatePartDefinition => {
OperationKind::CreatePartDefinition(crate::payload::CreatePartDefinitionOp {
part: valuegen::part_definition(
epiphany_core::PartDefinitionId::new(ReplicaId(7), 1),
vec![StaffId::new(ReplicaId(7), 1)],
),
})
}
OperationKindTag::CreateAnalysisLayer => {
OperationKind::CreateAnalysisLayer(crate::payload::CreateAnalysisLayerOp {
layer: valuegen::analysis_layer(epiphany_core::AnalysisLayerId::new(
ReplicaId(7),
1,
)),
})
}
OperationKindTag::CreateView => {
OperationKind::CreateView(crate::payload::CreateViewOp {
view: valuegen::view(
epiphany_core::ViewId::new(ReplicaId(7), 1),
vec![epiphany_core::AnalysisLayerId::new(ReplicaId(7), 1)],
),
})
}
} }
} }

View File

@ -21,9 +21,9 @@
//! those paths are exercised for permutation-invariance too. //! those paths are exercised for permutation-invariance too.
use epiphany_core::{ use epiphany_core::{
EventId, MusicalDuration, MusicalPosition, OperationId, PitchId, RationalTime, RegionId, AnalysisLayerId, EventId, MusicalDuration, MusicalPosition, OperationId, PartDefinitionId,
RepeatStructureId, ReplicaId, SlurId, StaffId, StaffInstanceId, TranspositionInterval, PitchId, RationalTime, RegionId, RepeatStructureId, ReplicaId, SlurId, StaffGroupId, StaffId,
TypedObjectId, VoiceId, StaffInstanceId, TranspositionInterval, TypedObjectId, ViewId, VoiceId,
}; };
use epiphany_determinism::fuzz::SplitMix64; use epiphany_determinism::fuzz::SplitMix64;
@ -32,8 +32,9 @@ use crate::envelope::OperationEnvelope;
use crate::opset::OperationSet; use crate::opset::OperationSet;
use crate::payload::OperationKindTag; use crate::payload::OperationKindTag;
use crate::payload::{ use crate::payload::{
CreateCrossCuttingOp, CreateInstrumentOp, CreateRegionOp, CreateRepeatStructureOp, CreateAnalysisLayerOp, CreateCrossCuttingOp, CreateInstrumentOp, CreatePartDefinitionOp,
CreateStaffInstanceOp, CreateStaffOp, CreateVoiceOp, CrossCuttingValue, DeleteCrossCuttingOp, CreateRegionOp, CreateRepeatStructureOp, CreateStaffGroupOp, CreateStaffInstanceOp,
CreateStaffOp, CreateViewOp, CreateVoiceOp, CrossCuttingValue, DeleteCrossCuttingOp,
DeleteEventOp, DeleteIdentifiedPitchOp, DeleteRegionOp, DeleteRepeatStructureOp, DeleteEventOp, DeleteIdentifiedPitchOp, DeleteRegionOp, DeleteRepeatStructureOp,
DeleteStaffInstanceOp, DeleteVoiceOp, InsertEventOp, InsertIdentifiedPitchOp, DeleteStaffInstanceOp, DeleteVoiceOp, InsertEventOp, InsertIdentifiedPitchOp,
ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp, OperationKind, OperationPayload, ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp, OperationKind, OperationPayload,
@ -90,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(32) { let kind = match rng.below(36) {
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));
@ -304,6 +305,30 @@ fn gen_payload(rng: &mut SplitMix64) -> OperationPayload {
31 => OperationKind::SetTuningContext(crate::payload::SetTuningContextOp { 31 => OperationKind::SetTuningContext(crate::payload::SetTuningContextOp {
settings: valuegen::tuning_context_settings(rng.below(3) as u8), settings: valuegen::tuning_context_settings(rng.below(3) as u8),
}), }),
// Genesis tranche G3a: the four remaining root-level mints, over the
// shared staff/analysis-layer id spaces so mints/re-carries genuinely
// interact with them (mirroring arm 21's `CreateStaff`).
32 => OperationKind::CreateStaffGroup(CreateStaffGroupOp {
group: valuegen::staff_group(
StaffGroupId::new(ReplicaId(7), rng.below(2)),
vec![StaffId::new(ReplicaId(7), rng.below(2))],
),
}),
33 => OperationKind::CreatePartDefinition(CreatePartDefinitionOp {
part: valuegen::part_definition(
PartDefinitionId::new(ReplicaId(7), rng.below(2)),
vec![StaffId::new(ReplicaId(7), rng.below(2))],
),
}),
34 => OperationKind::CreateAnalysisLayer(CreateAnalysisLayerOp {
layer: valuegen::analysis_layer(AnalysisLayerId::new(ReplicaId(7), rng.below(2))),
}),
35 => OperationKind::CreateView(CreateViewOp {
view: valuegen::view(
ViewId::new(ReplicaId(7), rng.below(2)),
vec![AnalysisLayerId::new(ReplicaId(7), rng.below(2))],
),
}),
_ => 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

@ -124,9 +124,10 @@ pub use envelope::{
pub use migrate::{migrate_v0_envelope, project_v1_to_v0, MigrationError}; 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, CreateCrossCuttingOp, operation_block_introduced_minor, ChangeRegionTimeModelOp, CreateAnalysisLayerOp,
CreateInstrumentOp, CreateRegionOp, CreateRepeatStructureOp, CreateStaffInstanceOp, CreateCrossCuttingOp, CreateInstrumentOp, CreatePartDefinitionOp, CreateRegionOp,
CreateStaffOp, CreateVoiceOp, CrossCuttingValue, DeleteCrossCuttingOp, DeleteEventOp, CreateRepeatStructureOp, CreateStaffGroupOp, CreateStaffInstanceOp, CreateStaffOp,
CreateViewOp, CreateVoiceOp, CrossCuttingValue, DeleteCrossCuttingOp, DeleteEventOp,
DeleteIdentifiedPitchOp, DeleteRegionOp, DeleteRepeatStructureOp, DeleteStaffInstanceOp, DeleteIdentifiedPitchOp, DeleteRegionOp, DeleteRepeatStructureOp, DeleteStaffInstanceOp,
DeleteVoiceOp, InsertEventOp, InsertIdentifiedPitchOp, ModifyCrossCuttingOp, ModifyEventOp, DeleteVoiceOp, InsertEventOp, InsertIdentifiedPitchOp, ModifyCrossCuttingOp, ModifyEventOp,
ModifyIdentifiedPitchOp, OperationKind, OperationKindTag, OperationPayload, PositionRemapping, ModifyIdentifiedPitchOp, OperationKind, OperationKindTag, OperationPayload, PositionRemapping,

View File

@ -190,6 +190,13 @@ fn project_kind(kind: &OperationKind) -> V0OperationKind {
} }
// Genesis tranche G2b: born past v0; projected verbatim. // Genesis tranche G2b: born past v0; projected verbatim.
OperationKind::SetTuningContext(op) => V0OperationKind::SetTuningContext(op.clone()), OperationKind::SetTuningContext(op) => V0OperationKind::SetTuningContext(op.clone()),
// Genesis tranche G3a: born past v0; projected verbatim.
OperationKind::CreateStaffGroup(op) => V0OperationKind::CreateStaffGroup(op.clone()),
OperationKind::CreatePartDefinition(op) => {
V0OperationKind::CreatePartDefinition(op.clone())
}
OperationKind::CreateAnalysisLayer(op) => V0OperationKind::CreateAnalysisLayer(op.clone()),
OperationKind::CreateView(op) => V0OperationKind::CreateView(op.clone()),
} }
} }
@ -354,6 +361,13 @@ fn migrate_kind(kind: &V0OperationKind, context: &Score) -> Result<OperationKind
} }
// Genesis tranche G2b: identity round-trip (no lossy v0 form). // Genesis tranche G2b: identity round-trip (no lossy v0 form).
V0OperationKind::SetTuningContext(op) => OperationKind::SetTuningContext(op.clone()), V0OperationKind::SetTuningContext(op) => OperationKind::SetTuningContext(op.clone()),
// Genesis tranche G3a: identity round-trip (no lossy v0 form).
V0OperationKind::CreateStaffGroup(op) => OperationKind::CreateStaffGroup(op.clone()),
V0OperationKind::CreatePartDefinition(op) => {
OperationKind::CreatePartDefinition(op.clone())
}
V0OperationKind::CreateAnalysisLayer(op) => OperationKind::CreateAnalysisLayer(op.clone()),
V0OperationKind::CreateView(op) => OperationKind::CreateView(op.clone()),
}) })
} }

View File

@ -32,13 +32,14 @@
//! payloads. //! payloads.
use epiphany_core::{ use epiphany_core::{
Beam, CanonicalValue, CanvasLayoutDefaults, Event, EventDuration, EventId, EventPosition, AnalysisLayer, AnalysisLayerId, Beam, CanonicalValue, CanvasLayoutDefaults, Event,
IdentifiedPitch, Instrument, InstrumentId, MetricGrid, MusicalDuration, MusicalPosition, EventDuration, EventId, EventPosition, IdentifiedPitch, Instrument, InstrumentId, MetricGrid,
OperationId, Pitch, PitchId, PitchSpelling, Region, RegionId, RegionTimeModel, RepeatStructure, MusicalDuration, MusicalPosition, OperationId, PartDefinition, PartDefinitionId, Pitch,
RepeatStructureId, Rest, ScoreMetadata, Slur, Spanner, SpellingPrecedence, Staff, StaffId, PitchId, PitchSpelling, Region, RegionId, RegionTimeModel, RepeatStructure, RepeatStructureId,
StaffInstance, StaffInstanceId, StaffLineConfiguration, TempoSegment, Tie, TimeAnchor, Rest, ScoreMetadata, Slur, Spanner, SpellingPrecedence, Staff, StaffGroup, StaffGroupId,
StaffId, StaffInstance, StaffInstanceId, StaffLineConfiguration, TempoSegment, Tie, TimeAnchor,
TimeSignature, TransactionId, TranspositionInterval, TuningContextSettings, TupletId, TimeSignature, TransactionId, TranspositionInterval, TuningContextSettings, TupletId,
TypedObjectId, Voice, VoiceId, TypedObjectId, ViewDefinition, ViewId, Voice, VoiceId,
}; };
use epiphany_determinism::{ use epiphany_determinism::{
sorted_canonical, CanonicalDecode, CanonicalEncode, CanonicalSet, DecodeError, sorted_canonical, CanonicalDecode, CanonicalEncode, CanonicalSet, DecodeError,
@ -273,6 +274,26 @@ pub enum OperationKind {
/// `ScoreTuningContext` — `accidental_extensions` is not on the wire and /// `ScoreTuningContext` — `accidental_extensions` is not on the wire and
/// is left untouched by reduction (contract §1). /// is left untouched by reduction (contract §1).
SetTuningContext(SetTuningContextOp), SetTuningContext(SetTuningContextOp),
// --- Genesis tranche G3a (`spec/CONTRACT_GENESIS_G3A_ENTITIES.md`): the
// four remaining root-level `Score` entity mints. Discriminant extends
// additively past 34. ---
/// Mint a staff group on the score root (set-union creation). Graph-aware
/// reduction preconditions every carried member resolves to a live
/// `Staff`; the mint stores `members` as given and neither maintains nor
/// trusts it thereafter (contract §1.1, disposition B).
CreateStaffGroup(CreateStaffGroupOp),
/// Mint a part-extraction view definition on the score root (set-union
/// creation). Graph-aware reduction preconditions every carried staff
/// resolves to a live `Staff`.
CreatePartDefinition(CreatePartDefinitionOp),
/// Mint a first-class analysis layer on the score root (set-union
/// creation). Holds no outbound entity reference, so needs no referential
/// precondition — only mint and idempotence, exactly `CreateInstrument`.
CreateAnalysisLayer(CreateAnalysisLayerOp),
/// Mint a view recipe on the score root (set-union creation). Graph-aware
/// reduction preconditions every carried active layer resolves to a live
/// `AnalysisLayer`.
CreateView(CreateViewOp),
} }
impl OperationKind { impl OperationKind {
@ -388,6 +409,12 @@ impl OperationKind {
// Genesis tranche G2b; appended past 33. Coincides with tag 34 by // Genesis tranche G2b; appended past 33. Coincides with tag 34 by
// the same accident as G1/G2a, not by rule. // the same accident as G1/G2a, not by rule.
OperationKind::SetTuningContext(_) => 34, OperationKind::SetTuningContext(_) => 34,
// Genesis tranche G3a; appended past 34. Coincide with tags
// 3538 by the same accident as G1/G2a/G2b, not by rule.
OperationKind::CreateStaffGroup(_) => 35,
OperationKind::CreatePartDefinition(_) => 36,
OperationKind::CreateAnalysisLayer(_) => 37,
OperationKind::CreateView(_) => 38,
} }
} }
@ -447,6 +474,13 @@ impl OperationKind {
// Minor 10 (Genesis tranche G2b), ratified // Minor 10 (Genesis tranche G2b), ratified
// `spec/PLAN_GMINOR_SCHEMA_MINOR.md` §4. // `spec/PLAN_GMINOR_SCHEMA_MINOR.md` §4.
OperationKind::SetTuningContext(_) => Some(10), OperationKind::SetTuningContext(_) => Some(10),
// Minor 11 (Genesis tranche G3a), ratified
// `spec/PLAN_GMINOR_SCHEMA_MINOR.md` §4: one epoch for one
// additive event, the G2a precedent (two kinds at epoch 9).
OperationKind::CreateStaffGroup(_)
| OperationKind::CreatePartDefinition(_)
| OperationKind::CreateAnalysisLayer(_)
| OperationKind::CreateView(_) => Some(11),
} }
} }
@ -495,6 +529,13 @@ impl OperationKind {
OperationKind::SetCanvasLayoutDefaults(_) => OperationKindTag::SetCanvasLayoutDefaults, OperationKind::SetCanvasLayoutDefaults(_) => OperationKindTag::SetCanvasLayoutDefaults,
OperationKind::SetSpellingPrecedence(_) => OperationKindTag::SetSpellingPrecedence, OperationKind::SetSpellingPrecedence(_) => OperationKindTag::SetSpellingPrecedence,
OperationKind::SetTuningContext(_) => OperationKindTag::SetTuningContext, OperationKind::SetTuningContext(_) => OperationKindTag::SetTuningContext,
// Genesis tranche G3a. Name-verbatim, as the four most recent
// additions are (contract pin 3's precedent — not the tag
// layer's older Create→Insert convention).
OperationKind::CreateStaffGroup(_) => OperationKindTag::CreateStaffGroup,
OperationKind::CreatePartDefinition(_) => OperationKindTag::CreatePartDefinition,
OperationKind::CreateAnalysisLayer(_) => OperationKindTag::CreateAnalysisLayer,
OperationKind::CreateView(_) => OperationKindTag::CreateView,
} }
} }
} }
@ -541,6 +582,10 @@ impl CanonicalEncode for OperationKind {
OperationKind::SetCanvasLayoutDefaults(op) => op.encode_canonical(out), OperationKind::SetCanvasLayoutDefaults(op) => op.encode_canonical(out),
OperationKind::SetSpellingPrecedence(op) => op.encode_canonical(out), OperationKind::SetSpellingPrecedence(op) => op.encode_canonical(out),
OperationKind::SetTuningContext(op) => op.encode_canonical(out), OperationKind::SetTuningContext(op) => op.encode_canonical(out),
OperationKind::CreateStaffGroup(op) => op.encode_canonical(out),
OperationKind::CreatePartDefinition(op) => op.encode_canonical(out),
OperationKind::CreateAnalysisLayer(op) => op.encode_canonical(out),
OperationKind::CreateView(op) => op.encode_canonical(out),
} }
} }
} }
@ -597,6 +642,14 @@ pub enum OperationKindTag {
SetSpellingPrecedence, SetSpellingPrecedence,
/// Genesis tranche G2b. /// Genesis tranche G2b.
SetTuningContext, SetTuningContext,
/// Genesis tranche G3a.
CreateStaffGroup,
/// Genesis tranche G3a.
CreatePartDefinition,
/// Genesis tranche G3a.
CreateAnalysisLayer,
/// Genesis tranche G3a.
CreateView,
} }
/// The discriminant of [`OperationKindTag::Registered`], the one tag that /// The discriminant of [`OperationKindTag::Registered`], the one tag that
@ -712,6 +765,10 @@ operation_kind_tag_vocabulary! {
SetCanvasLayoutDefaults = 32 => "set-canvas-layout-defaults" @ Some(9), SetCanvasLayoutDefaults = 32 => "set-canvas-layout-defaults" @ Some(9),
SetSpellingPrecedence = 33 => "set-spelling-precedence" @ Some(9), SetSpellingPrecedence = 33 => "set-spelling-precedence" @ Some(9),
SetTuningContext = 34 => "set-tuning-context" @ Some(10), SetTuningContext = 34 => "set-tuning-context" @ Some(10),
CreateStaffGroup = 35 => "create-staff-group" @ Some(11),
CreatePartDefinition = 36 => "create-part-definition" @ Some(11),
CreateAnalysisLayer = 37 => "create-analysis-layer" @ Some(11),
CreateView = 38 => "create-view" @ Some(11),
} }
impl CanonicalEncode for OperationKindTag { impl CanonicalEncode for OperationKindTag {
@ -1702,6 +1759,103 @@ impl CanonicalEncode for SetTuningContextOp {
} }
} }
// --- Genesis tranche G3a (`spec/CONTRACT_GENESIS_G3A_ENTITIES.md`): the four
// remaining root-level `Score` entity mints. All four ride the `CreateStaff`
// set-union mint pattern (`reduce.rs:4075`) with byte-identical re-carry
// idempotence. ---
/// Mint a global [`StaffGroup`] on the score root (operation_catalog
/// §CreateStaffGroup). Carries the full staff-group value: identity, optional
/// name, kind, and the carried `members` list. Graph-aware reduction
/// preconditions every carried member resolves to a live `Staff`; per §1.1
/// (disposition B), the mint stores `members` exactly as given and neither
/// maintains nor trusts it thereafter — `Staff.group` is the sole authority
/// for membership.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct CreateStaffGroupOp {
pub group: StaffGroup,
}
impl CreateStaffGroupOp {
/// The minted staff group's identifier.
pub fn staff_group_id(&self) -> StaffGroupId {
self.group.id
}
}
impl CanonicalEncode for CreateStaffGroupOp {
fn encode_canonical(&self, out: &mut Vec<u8>) {
push_lp_bytes(out, &self.group.canonical_bytes());
}
}
/// Mint a [`PartDefinition`] on the score root (operation_catalog
/// §CreatePartDefinition). Carries the full part-extraction value: identity,
/// name, and the carried `staves` list. Graph-aware reduction preconditions
/// every carried staff resolves to a live `Staff`.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct CreatePartDefinitionOp {
pub part: PartDefinition,
}
impl CreatePartDefinitionOp {
/// The minted part definition's identifier.
pub fn part_definition_id(&self) -> PartDefinitionId {
self.part.id
}
}
impl CanonicalEncode for CreatePartDefinitionOp {
fn encode_canonical(&self, out: &mut Vec<u8>) {
push_lp_bytes(out, &self.part.canonical_bytes());
}
}
/// Mint an [`AnalysisLayer`] on the score root (operation_catalog
/// §CreateAnalysisLayer). Carries the full value: identity and name.
/// `AnalysisLayer` holds no outbound entity reference, so this operation
/// needs no referential precondition at all — only mint and idempotence,
/// exactly the `CreateInstrument` discipline.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct CreateAnalysisLayerOp {
pub layer: AnalysisLayer,
}
impl CreateAnalysisLayerOp {
/// The minted analysis layer's identifier.
pub fn analysis_layer_id(&self) -> AnalysisLayerId {
self.layer.id
}
}
impl CanonicalEncode for CreateAnalysisLayerOp {
fn encode_canonical(&self, out: &mut Vec<u8>) {
push_lp_bytes(out, &self.layer.canonical_bytes());
}
}
/// Mint a [`ViewDefinition`] on the score root (operation_catalog
/// §CreateView). Carries the full view-recipe value: identity, name, and the
/// carried `active_layers` list. Graph-aware reduction preconditions every
/// carried active layer resolves to a live `AnalysisLayer`.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct CreateViewOp {
pub view: ViewDefinition,
}
impl CreateViewOp {
/// The minted view's identifier.
pub fn view_id(&self) -> ViewId {
self.view.id
}
}
impl CanonicalEncode for CreateViewOp {
fn encode_canonical(&self, out: &mut Vec<u8>) {
push_lp_bytes(out, &self.view.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
@ -2473,6 +2627,12 @@ mod tests {
// Genesis G2b. Kept in step with pin 1's table; an epoch omitted // Genesis G2b. Kept in step with pin 1's table; an epoch omitted
// here is an epoch this test cannot see go wrong. // here is an epoch this test cannot see go wrong.
(OperationKindTag::SetTuningContext, 10), (OperationKindTag::SetTuningContext, 10),
// Genesis G3a. Same rationale: omitting any of the four here is
// an epoch this test cannot see go wrong.
(OperationKindTag::CreateStaffGroup, 11),
(OperationKindTag::CreatePartDefinition, 11),
(OperationKindTag::CreateAnalysisLayer, 11),
(OperationKindTag::CreateView, 11),
] { ] {
assert_eq!( assert_eq!(
tag.introduced_minor(), tag.introduced_minor(),

File diff suppressed because it is too large Load Diff

View File

@ -8,15 +8,16 @@ use epiphany_determinism::{sorted_canonical, CanonicalEncode};
use unicode_normalization::UnicodeNormalization; use unicode_normalization::UnicodeNormalization;
use crate::payload::{ use crate::payload::{
ChangeRegionTimeModelOp, CreateCrossCuttingOp, CreateInstrumentOp, CreateRegionOp, ChangeRegionTimeModelOp, CreateAnalysisLayerOp, CreateCrossCuttingOp, CreateInstrumentOp,
CreateRepeatStructureOp, CreateStaffInstanceOp, CreateStaffOp, CreateVoiceOp, CreatePartDefinitionOp, CreateRegionOp, CreateRepeatStructureOp, CreateStaffGroupOp,
DeleteCrossCuttingOp, DeleteEventOp, DeleteIdentifiedPitchOp, DeleteRegionOp, CreateStaffInstanceOp, CreateStaffOp, CreateViewOp, CreateVoiceOp, DeleteCrossCuttingOp,
DeleteRepeatStructureOp, DeleteStaffInstanceOp, DeleteVoiceOp, InsertEventOp, DeleteEventOp, DeleteIdentifiedPitchOp, DeleteRegionOp, DeleteRepeatStructureOp,
InsertIdentifiedPitchOp, ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp, DeleteStaffInstanceOp, DeleteVoiceOp, InsertEventOp, InsertIdentifiedPitchOp,
OperationKind, OperationKindTag, RespellPitchOp, SetCanvasLayoutDefaultsOp, SetMetadataOp, ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp, OperationKind, OperationKindTag,
SetMetricGridOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp, RespellPitchOp, SetCanvasLayoutDefaultsOp, SetMetadataOp, SetMetricGridOp,
SetTimeSignatureOp, SetTuningContextOp, SetUserPageBreakOp, SetUserSystemBreakOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp, SetTimeSignatureOp,
TransactionDescriptor, TransposeIntervalOp, TransposeOp, SetTuningContextOp, SetUserPageBreakOp, SetUserSystemBreakOp, TransactionDescriptor,
TransposeIntervalOp, TransposeOp,
}; };
use crate::support::OperationKindRegistryId; use crate::support::OperationKindRegistryId;
@ -232,6 +233,14 @@ impl TextValue for OperationKind {
OperationKind::SetTuningContext(op) => { OperationKind::SetTuningContext(op) => {
production(self.tag(), vec![op.settings.project()]) production(self.tag(), vec![op.settings.project()])
} }
OperationKind::CreateStaffGroup(op) => production(self.tag(), vec![op.group.project()]),
OperationKind::CreatePartDefinition(op) => {
production(self.tag(), vec![op.part.project()])
}
OperationKind::CreateAnalysisLayer(op) => {
production(self.tag(), vec![op.layer.project()])
}
OperationKind::CreateView(op) => production(self.tag(), vec![op.view.project()]),
} }
} }
@ -577,6 +586,38 @@ impl TextValue for OperationKind {
settings: TextValue::parse(settings)?, settings: TextValue::parse(settings)?,
}) })
} }
OperationKindTag::CreateStaffGroup => {
let [group] = fields(s, tag, 1)? else {
unreachable!("the arity-1 check returned one field")
};
OperationKind::CreateStaffGroup(CreateStaffGroupOp {
group: TextValue::parse(group)?,
})
}
OperationKindTag::CreatePartDefinition => {
let [part] = fields(s, tag, 1)? else {
unreachable!("the arity-1 check returned one field")
};
OperationKind::CreatePartDefinition(CreatePartDefinitionOp {
part: TextValue::parse(part)?,
})
}
OperationKindTag::CreateAnalysisLayer => {
let [layer] = fields(s, tag, 1)? else {
unreachable!("the arity-1 check returned one field")
};
OperationKind::CreateAnalysisLayer(CreateAnalysisLayerOp {
layer: TextValue::parse(layer)?,
})
}
OperationKindTag::CreateView => {
let [view] = fields(s, tag, 1)? else {
unreachable!("the arity-1 check returned one field")
};
OperationKind::CreateView(CreateViewOp {
view: TextValue::parse(view)?,
})
}
}) })
} }
} }
@ -630,7 +671,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(), 35, "the grammar has 35 kind productions"); assert_eq!(tags.len(), 39, "the grammar has 39 kind productions");
for tag in tags { for tag in tags {
round_trip(&sample_kind(tag)); round_trip(&sample_kind(tag));
} }

View File

@ -116,6 +116,13 @@ pub enum V0OperationKind {
// predates the catalog entirely), so it round-trips by identity like // predates the catalog entirely), so it round-trips by identity like
// every other v1-native kind above. // every other v1-native kind above.
SetTuningContext(crate::payload::SetTuningContextOp), SetTuningContext(crate::payload::SetTuningContextOp),
// Genesis tranche G3a — born at wire-discs 35..=38; no lossy v0 form (v0
// predates the catalog entirely), so all four round-trip by identity like
// every other v1-native kind above.
CreateStaffGroup(crate::payload::CreateStaffGroupOp),
CreatePartDefinition(crate::payload::CreatePartDefinitionOp),
CreateAnalysisLayer(crate::payload::CreateAnalysisLayerOp),
CreateView(crate::payload::CreateViewOp),
} }
/// 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

@ -16,14 +16,15 @@ use std::collections::BTreeMap;
use epiphany_core::{ use epiphany_core::{
AcousticPitch, AcousticRealization, AleatoricAnchoringDiscipline, AleatoricTimeModel, AcousticPitch, AcousticRealization, AleatoricAnchoringDiscipline, AleatoricTimeModel,
AnchorOffset, Beam, BeamId, CmnNominal, Event, EventId, EventOrderingDAG, EventPosition, AnalysisLayerId, AnchorOffset, Beam, BeamId, CmnNominal, Event, EventId, EventOrderingDAG,
IdentifiedPitch, MetricTimeModel, MusicalDuration, MusicalPosition, Pitch, PitchId, EventPosition, IdentifiedPitch, MetricTimeModel, MusicalDuration, MusicalPosition,
PitchSpaceId, PitchSpacePosition, PitchSpelling, PitchedEvent, ProportionalTimeModel, Region, PartDefinitionId, Pitch, PitchId, PitchSpaceId, PitchSpacePosition, PitchSpelling,
RegionContent, RegionEdge, RegionId, RegionTimeModel, RepeatKind, RepeatStructure, PitchedEvent, ProportionalTimeModel, Region, RegionContent, RegionEdge, RegionId,
RepeatStructureId, Rest, ScalePosition, Slur, SlurId, SpellingAttachment, SpellingDirective, RegionTimeModel, RepeatKind, RepeatStructure, RepeatStructureId, Rest, ScalePosition, Slur,
SpellingScope, SpellingSource, StaffBasedContent, StaffExtent, StaffId, StaffInstance, SlurId, SpellingAttachment, SpellingDirective, SpellingScope, SpellingSource,
StaffInstanceId, StemConfiguration, Tie, TieClass, TieId, TimeAnchor, TimeExtent, Voice, StaffBasedContent, StaffExtent, StaffGroupId, StaffId, StaffInstance, StaffInstanceId,
VoiceId, VoiceOrigin, Volta, WallClockDuration, WallClockTime, StemConfiguration, Tie, TieClass, TieId, TimeAnchor, TimeExtent, 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
@ -368,6 +369,61 @@ pub fn instrument(id: epiphany_core::InstrumentId) -> epiphany_core::Instrument
epiphany_core::Instrument::new(id, format!("instrument-{}", id.counter())) epiphany_core::Instrument::new(id, format!("instrument-{}", id.counter()))
} }
/// A minimal [`StaffGroup`](epiphany_core::StaffGroup) (genesis tranche G3a) —
/// the value a `CreateStaffGroup` mints: named for its counter, a grand-staff
/// kind, and the given `members` list carried exactly as given (contract
/// §1.1, disposition B — this helper never normalizes `members`).
pub fn staff_group(id: StaffGroupId, members: Vec<StaffId>) -> epiphany_core::StaffGroup {
epiphany_core::StaffGroup {
id,
name: Some(format!("staff-group-{}", id.counter())),
kind: epiphany_core::StaffGroupKind::GrandStaff,
members,
}
}
/// A minimal [`PartDefinition`](epiphany_core::PartDefinition) (genesis
/// tranche G3a) — the value a `CreatePartDefinition` mints: named for its
/// counter, referencing the given `staves`.
pub fn part_definition(
id: PartDefinitionId,
staves: Vec<StaffId>,
) -> epiphany_core::PartDefinition {
epiphany_core::PartDefinition {
id,
name: format!("part-{}", id.counter()),
staves,
}
}
/// A minimal [`AnalysisLayer`](epiphany_core::AnalysisLayer) (genesis tranche
/// G3a) — the value a `CreateAnalysisLayer` mints: named for its counter, with
/// no outbound entity reference.
pub fn analysis_layer(id: AnalysisLayerId) -> epiphany_core::AnalysisLayer {
epiphany_core::AnalysisLayer {
id,
// Deliberately NOT `id`-width (16 bytes): a name that happens to
// share its encoded byte length with the 16-byte `id` field would
// make a `struct_codec!` field swap byte-invisible for this specific
// value (both fields are length-prefixed leaves; swapping two
// same-width leaves reproduces identical bytes) — silently defeating
// the one referential guard a two-field struct's literal-byte vector
// (contract t4) has to catch a reorder with.
name: format!("layer-{}", id.counter()),
}
}
/// A minimal [`ViewDefinition`](epiphany_core::ViewDefinition) (genesis
/// tranche G3a) — the value a `CreateView` mints: named for its counter,
/// referencing the given `active_layers`.
pub fn view(id: ViewId, active_layers: Vec<AnalysisLayerId>) -> epiphany_core::ViewDefinition {
epiphany_core::ViewDefinition {
id,
name: format!("view-{}", id.counter()),
active_layers,
}
}
/// 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

@ -16,7 +16,10 @@
//! The `class` string is informative, not normative: implementations need not //! The `class` string is informative, not normative: implementations need not
//! agree on error taxonomy, only on the accept/reject verdict. //! agree on error taxonomy, only on the accept/reject verdict.
use epiphany_core::{EventId, InstrumentId, OperationId, ReplicaId, TypedObjectId}; use epiphany_core::{
AnalysisLayerId, EventId, InstrumentId, OperationId, PartDefinitionId, ReplicaId, StaffGroupId,
StaffId, TypedObjectId, ViewId,
};
use epiphany_determinism::CanonicalEncode; use epiphany_determinism::CanonicalEncode;
use crate::{ use crate::{
@ -411,6 +414,156 @@ pub fn decode_vectors() -> Vec<DecodeVector> {
tuning_trailing, tuning_trailing,
)); ));
// --- OperationEnvelope carrying the four genesis tranche G3a root-level
// mints (`spec/CONTRACT_GENESIS_G3A_ENTITIES.md`) — same rationale as the
// siblings above: nothing else in this corpus exercises any of these four
// payloads' decode paths, and a round-trip check alone cannot see a
// self-consistent encoder/decoder reorder (the 3b-i lesson; contract t4).
let staff_group_envelope = OperationEnvelope {
id: OperationId::new(ReplicaId(1), 5),
author: crate::support::AuthorId(0),
stamp: crate::stamp::OperationStamp::new(
crate::stamp::HybridLogicalClock::new(epiphany_core::WallClockTime(1), 1),
OperationId::new(ReplicaId(1), 5),
),
causal_context: crate::causal::CausalContext::new(),
transaction: None,
payload: crate::payload::OperationPayload::Primitive(
crate::payload::OperationKind::CreateStaffGroup(crate::payload::CreateStaffGroupOp {
group: crate::valuegen::staff_group(
StaffGroupId::new(ReplicaId(1), 1),
vec![StaffId::new(ReplicaId(1), 1)],
),
}),
),
};
let staff_group_envelope_bytes = staff_group_envelope.to_canonical_bytes();
v.push(row(
OE,
"accept",
"-",
"create_staff_group",
staff_group_envelope_bytes.clone(),
));
let mut staff_group_trailing = staff_group_envelope_bytes;
staff_group_trailing.push(0);
v.push(row(
OE,
"reject",
"trailing-bytes",
"create_staff_group_trailing",
staff_group_trailing,
));
let part_definition_envelope = OperationEnvelope {
id: OperationId::new(ReplicaId(1), 6),
author: crate::support::AuthorId(0),
stamp: crate::stamp::OperationStamp::new(
crate::stamp::HybridLogicalClock::new(epiphany_core::WallClockTime(1), 1),
OperationId::new(ReplicaId(1), 6),
),
causal_context: crate::causal::CausalContext::new(),
transaction: None,
payload: crate::payload::OperationPayload::Primitive(
crate::payload::OperationKind::CreatePartDefinition(
crate::payload::CreatePartDefinitionOp {
part: crate::valuegen::part_definition(
PartDefinitionId::new(ReplicaId(1), 1),
vec![StaffId::new(ReplicaId(1), 1)],
),
},
),
),
};
let part_definition_envelope_bytes = part_definition_envelope.to_canonical_bytes();
v.push(row(
OE,
"accept",
"-",
"create_part_definition",
part_definition_envelope_bytes.clone(),
));
let mut part_definition_trailing = part_definition_envelope_bytes;
part_definition_trailing.push(0);
v.push(row(
OE,
"reject",
"trailing-bytes",
"create_part_definition_trailing",
part_definition_trailing,
));
let analysis_layer_envelope = OperationEnvelope {
id: OperationId::new(ReplicaId(1), 7),
author: crate::support::AuthorId(0),
stamp: crate::stamp::OperationStamp::new(
crate::stamp::HybridLogicalClock::new(epiphany_core::WallClockTime(1), 1),
OperationId::new(ReplicaId(1), 7),
),
causal_context: crate::causal::CausalContext::new(),
transaction: None,
payload: crate::payload::OperationPayload::Primitive(
crate::payload::OperationKind::CreateAnalysisLayer(
crate::payload::CreateAnalysisLayerOp {
layer: crate::valuegen::analysis_layer(AnalysisLayerId::new(ReplicaId(1), 1)),
},
),
),
};
let analysis_layer_envelope_bytes = analysis_layer_envelope.to_canonical_bytes();
v.push(row(
OE,
"accept",
"-",
"create_analysis_layer",
analysis_layer_envelope_bytes.clone(),
));
let mut analysis_layer_trailing = analysis_layer_envelope_bytes;
analysis_layer_trailing.push(0);
v.push(row(
OE,
"reject",
"trailing-bytes",
"create_analysis_layer_trailing",
analysis_layer_trailing,
));
let view_envelope = OperationEnvelope {
id: OperationId::new(ReplicaId(1), 8),
author: crate::support::AuthorId(0),
stamp: crate::stamp::OperationStamp::new(
crate::stamp::HybridLogicalClock::new(epiphany_core::WallClockTime(1), 1),
OperationId::new(ReplicaId(1), 8),
),
causal_context: crate::causal::CausalContext::new(),
transaction: None,
payload: crate::payload::OperationPayload::Primitive(
crate::payload::OperationKind::CreateView(crate::payload::CreateViewOp {
view: crate::valuegen::view(
ViewId::new(ReplicaId(1), 1),
vec![AnalysisLayerId::new(ReplicaId(1), 1)],
),
}),
),
};
let view_envelope_bytes = view_envelope.to_canonical_bytes();
v.push(row(
OE,
"accept",
"-",
"create_view",
view_envelope_bytes.clone(),
));
let mut view_trailing = view_envelope_bytes;
view_trailing.push(0);
v.push(row(
OE,
"reject",
"trailing-bytes",
"create_view_trailing",
view_trailing,
));
v v
} }
@ -622,4 +775,128 @@ mod tests {
"the committed literal bytes must decode and re-encode injectively" "the committed literal bytes must decode and re-encode injectively"
); );
} }
/// (t4) Genesis tranche G3a (`spec/CONTRACT_GENESIS_G3A_ENTITIES.md`): the
/// `CreateStaffGroup` envelope decode vector, pinned to a literal byte
/// array copied from the committed corpus — not derived by calling
/// `.to_canonical_bytes()` here, for the same reason as the sibling tests
/// above (the 3b-i lesson: round-trip locking alone cannot see a
/// self-consistent encoder/decoder reorder). **Mutation:** swap two
/// fields in `StaffGroup`'s `struct_codec!` declaration
/// (`core/src/codec.rs:2329`, e.g. `{ id, name, kind, members }` →
/// `{ id, kind, name, members }`); this literal-byte vector must fail
/// while every round-trip test stays green.
#[test]
fn create_staff_group_envelope_decode_vector_is_pinned_to_literal_bytes() {
#[rustfmt::skip]
let bytes: Vec<u8> = vec![
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
35, 63, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 13, 0,
0, 0, 115, 116, 97, 102, 102, 45, 103, 114, 111, 117, 112, 45,
49, 0, 1, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
];
let result = check("ops.operation_envelope", &bytes)
.expect("ops.operation_envelope is owned by this crate");
assert_eq!(
result,
Ok(true),
"the committed literal bytes must decode and re-encode injectively"
);
}
/// (t4) Same rationale as `create_staff_group_envelope_decode_vector_is_
/// pinned_to_literal_bytes` above. **Mutation:** swap two fields in
/// `PartDefinition`'s `struct_codec!` declaration
/// (`core/src/codec.rs:1790`, `{ id, name, staves }` →
/// `{ id, staves, name }`); this literal-byte vector must fail while
/// every round-trip test stays green.
#[test]
fn create_part_definition_envelope_decode_vector_is_pinned_to_literal_bytes() {
#[rustfmt::skip]
let bytes: Vec<u8> = vec![
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
36, 54, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 6, 0, 0,
0, 112, 97, 114, 116, 45, 49, 1, 0, 0, 0, 16, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 1,
];
let result = check("ops.operation_envelope", &bytes)
.expect("ops.operation_envelope is owned by this crate");
assert_eq!(
result,
Ok(true),
"the committed literal bytes must decode and re-encode injectively"
);
}
/// (t4) Same rationale as the sibling tests above. **Mutation:** swap two
/// fields in `AnalysisLayer`'s `struct_codec!` declaration
/// (`core/src/codec.rs:1791`, `{ id, name }` → `{ name, id }`); this
/// literal-byte vector must fail while every round-trip test stays
/// green. `valuegen::analysis_layer`'s name is deliberately not 16 bytes
/// (the `id` field's width): a same-width swap of two length-prefixed
/// leaves re-encodes byte-identically regardless of which field is
/// which, so an accidental width match would make this vector blind to
/// exactly the reorder it exists to catch.
#[test]
fn create_analysis_layer_envelope_decode_vector_is_pinned_to_literal_bytes() {
#[rustfmt::skip]
let bytes: Vec<u8> = vec![
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
37, 31, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 7, 0, 0,
0, 108, 97, 121, 101, 114, 45, 49,
];
let result = check("ops.operation_envelope", &bytes)
.expect("ops.operation_envelope is owned by this crate");
assert_eq!(
result,
Ok(true),
"the committed literal bytes must decode and re-encode injectively"
);
}
/// (t4) Same rationale as the sibling tests above. **Mutation:** swap two
/// fields in `ViewDefinition`'s `struct_codec!` declaration
/// (`core/src/codec.rs:1792`, `{ id, name, active_layers }` →
/// `{ id, active_layers, name }`); this literal-byte vector must fail
/// while every round-trip test stays green.
#[test]
fn create_view_envelope_decode_vector_is_pinned_to_literal_bytes() {
#[rustfmt::skip]
let bytes: Vec<u8> = vec![
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
38, 54, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 6, 0, 0,
0, 118, 105, 101, 119, 45, 49, 1, 0, 0, 0, 16, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 1,
];
let result = check("ops.operation_envelope", &bytes)
.expect("ops.operation_envelope is owned by this crate");
assert_eq!(
result,
Ok(true),
"the committed literal bytes must decode and re-encode injectively"
);
}
} }

View File

@ -33,23 +33,24 @@ use epiphany_ops::valuegen;
use epiphany_ops::{ use epiphany_ops::{
AnomalousReplicaSegment, AuthorId, CausalContext, ChangeRegionTimeModelOp, ConflictId, AnomalousReplicaSegment, AuthorId, CausalContext, ChangeRegionTimeModelOp, ConflictId,
ConflictKind, ConflictKindRegistryId, ConflictRecord, ConflictRegistry, ConflictKind, ConflictKindRegistryId, ConflictRecord, ConflictRegistry,
ConflictResolutionState, CreateCrossCuttingOp, CreateInstrumentOp, CreateRegionOp, ConflictResolutionState, CreateAnalysisLayerOp, CreateCrossCuttingOp, CreateInstrumentOp,
CreateRepeatStructureOp, CreateStaffInstanceOp, CreateStaffOp, CreateVoiceOp, CreatePartDefinitionOp, CreateRegionOp, CreateRepeatStructureOp, CreateStaffGroupOp,
CrossCuttingValue, DeleteCrossCuttingOp, DeleteEventOp, DeleteIdentifiedPitchOp, CreateStaffInstanceOp, CreateStaffOp, CreateViewOp, CreateVoiceOp, CrossCuttingValue,
DeleteRegionOp, DeleteRepeatStructureOp, DeleteStaffInstanceOp, DeleteVoiceOp, DeleteCrossCuttingOp, DeleteEventOp, DeleteIdentifiedPitchOp, DeleteRegionOp,
ExtensionPreconditionId, FieldPath, HybridLogicalClock, InsertEventOp, InsertIdentifiedPitchOp, DeleteRepeatStructureOp, DeleteStaffInstanceOp, DeleteVoiceOp, ExtensionPreconditionId,
IntegrityAnomaly, IntegrityAnomalyKind, IntegrityAnomalyRegistryId, MaterializedState, FieldPath, HybridLogicalClock, InsertEventOp, InsertIdentifiedPitchOp, IntegrityAnomaly,
ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp, NoOpReason, ObjectKind, IntegrityAnomalyKind, IntegrityAnomalyRegistryId, MaterializedState, ModifyCrossCuttingOp,
ObjectState, OperationEffect, OperationEnvelope, OperationKind, OperationKindRegistryId, ModifyEventOp, ModifyIdentifiedPitchOp, NoOpReason, ObjectKind, ObjectState, OperationEffect,
OperationPayload, OperationSet, OperationStamp, PendingReason, PositionRemapping, OperationEnvelope, OperationKind, OperationKindRegistryId, OperationPayload, OperationSet,
PreconditionFailureReason, PreconditionFailureRegistryId, ReanchorReason, OperationStamp, PendingReason, PositionRemapping, PreconditionFailureReason,
ReanchorReasonRegistryId, ReanchorResult, RepairKind, RepairKindRegistryId, RepairRecord, PreconditionFailureRegistryId, ReanchorReason, ReanchorReasonRegistryId, ReanchorResult,
ReplicaAnomalyReason, ReplicaAnomalyRegistryId, ResolutionAction, ResolutionRegistryId, RepairKind, RepairKindRegistryId, RepairRecord, ReplicaAnomalyReason, ReplicaAnomalyRegistryId,
ResolveConflictPayload, RespellPitchOp, SerializedCanonicalInputs, SetCanvasLayoutDefaultsOp, ResolutionAction, ResolutionRegistryId, ResolveConflictPayload, RespellPitchOp,
SetMetadataOp, SetMetricGridOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp, SerializedCanonicalInputs, SetCanvasLayoutDefaultsOp, SetMetadataOp, SetMetricGridOp,
SetTimeSignatureOp, SetTuningContextOp, SetUserPageBreakOp, SetUserSystemBreakOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp, SetTimeSignatureOp,
TransactionCategory, TransactionDescriptor, TransposeIntervalOp, TransposeOp, SetTuningContextOp, SetUserPageBreakOp, SetUserSystemBreakOp, TransactionCategory,
TupletCompensation, TupletCompensationKind, UndoPolicy, UndoTransactionPayload, TransactionDescriptor, TransposeIntervalOp, TransposeOp, TupletCompensation,
TupletCompensationKind, UndoPolicy, UndoTransactionPayload,
}; };
use crate::rng::Rng; use crate::rng::Rng;
@ -646,7 +647,7 @@ pub fn operation_payload(rng: &mut Rng, events: u64, pitches: u64) -> OperationP
} }
_ => {} _ => {}
} }
let kind = match rng.below(35) { let kind = match rng.below(39) {
0 => { 0 => {
let pitches = if rng.boolean() { let pitches = if rng.boolean() {
vec![obj_pitch(rng.below(pitches))] vec![obj_pitch(rng.below(pitches))]
@ -875,6 +876,29 @@ pub fn operation_payload(rng: &mut Rng, events: u64, pitches: u64) -> OperationP
33 => OperationKind::SetTuningContext(SetTuningContextOp { 33 => OperationKind::SetTuningContext(SetTuningContextOp {
settings: valuegen::tuning_context_settings(rng.below(3) as u8), settings: valuegen::tuning_context_settings(rng.below(3) as u8),
}), }),
// Genesis tranche G3a: the four remaining root-level mints, over the
// shared staff/analysis-layer id spaces.
34 => OperationKind::CreateStaffGroup(CreateStaffGroupOp {
group: valuegen::staff_group(
StaffGroupId::new(OBJ_REPLICA, rng.below(2)),
vec![StaffId::new(OBJ_REPLICA, rng.below(2))],
),
}),
35 => OperationKind::CreatePartDefinition(CreatePartDefinitionOp {
part: valuegen::part_definition(
PartDefinitionId::new(OBJ_REPLICA, rng.below(2)),
vec![StaffId::new(OBJ_REPLICA, rng.below(2))],
),
}),
36 => OperationKind::CreateAnalysisLayer(CreateAnalysisLayerOp {
layer: valuegen::analysis_layer(AnalysisLayerId::new(OBJ_REPLICA, rng.below(2))),
}),
37 => OperationKind::CreateView(CreateViewOp {
view: valuegen::view(
ViewId::new(OBJ_REPLICA, rng.below(2)),
vec![AnalysisLayerId::new(OBJ_REPLICA, rng.below(2))],
),
}),
_ => 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),
@ -1905,7 +1929,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..=34), /// appended past the historically-tested range (discriminants 30..=38),
/// 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() {
@ -1913,6 +1937,8 @@ mod tests {
let (mut saw_transpose_interval, mut saw_create_instrument) = (false, false); let (mut saw_transpose_interval, mut saw_create_instrument) = (false, false);
let (mut saw_canvas_layout_defaults, mut saw_spelling_precedence) = (false, false); let (mut saw_canvas_layout_defaults, mut saw_spelling_precedence) = (false, false);
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_analysis_layer, mut saw_create_view) = (false, 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;
@ -1923,6 +1949,10 @@ mod tests {
OperationKind::SetCanvasLayoutDefaults(_) => saw_canvas_layout_defaults = true, OperationKind::SetCanvasLayoutDefaults(_) => saw_canvas_layout_defaults = true,
OperationKind::SetSpellingPrecedence(_) => saw_spelling_precedence = true, OperationKind::SetSpellingPrecedence(_) => saw_spelling_precedence = true,
OperationKind::SetTuningContext(_) => saw_tuning_context = true, OperationKind::SetTuningContext(_) => saw_tuning_context = true,
OperationKind::CreateStaffGroup(_) => saw_create_staff_group = true,
OperationKind::CreatePartDefinition(_) => saw_create_part_definition = true,
OperationKind::CreateAnalysisLayer(_) => saw_create_analysis_layer = true,
OperationKind::CreateView(_) => saw_create_view = true,
_ => {} _ => {}
} }
} }
@ -1946,6 +1976,22 @@ mod tests {
saw_tuning_context, saw_tuning_context,
"SetTuningContext (kind 34, G2b debt) never drawn in 2000 samples" "SetTuningContext (kind 34, G2b debt) never drawn in 2000 samples"
); );
assert!(
saw_create_staff_group,
"CreateStaffGroup (kind 35, G3a debt) never drawn in 2000 samples"
);
assert!(
saw_create_part_definition,
"CreatePartDefinition (kind 36, G3a debt) never drawn in 2000 samples"
);
assert!(
saw_create_analysis_layer,
"CreateAnalysisLayer (kind 37, G3a debt) never drawn in 2000 samples"
);
assert!(
saw_create_view,
"CreateView (kind 38, G3a debt) never drawn in 2000 samples"
);
} }
#[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..=34, which would pass even if the `Registered` /// discriminants 30..=38, 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

@ -305,14 +305,16 @@ fn the_kind_productions_are_the_operation_vocabulary() {
// above warns about — derived list, literal total. Every tranche that // above warns about — derived list, literal total. Every tranche that
// 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 takes // `SetCanvasLayoutDefaults` and `SetSpellingPrecedence`; genesis G2b took
// it from 34 to 35 by adding `SetTuningContext`). It stays a literal on // it from 34 to 35 by adding `SetTuningContext`; genesis G3a takes it
// from 35 to 39 by adding `CreateStaffGroup`, `CreatePartDefinition`,
// `CreateAnalysisLayer`, and `CreateView`). It stays a literal on
// purpose: deriving it from `PAYLOAD_FREE.len()` would make the assertion // 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(),
35, 39,
"34 payload-free kinds plus `Registered`" "38 payload-free kinds plus `Registered`"
); );
let actual = alternatives("kind"); let actual = alternatives("kind");

View File

@ -49,7 +49,14 @@ use epiphany_ops::OperationEnvelope;
/// `set-tuning-context` to the `kind` production — the same reasoning as G1 /// `set-tuning-context` to the `kind` production — the same reasoning as G1
/// and G2a: extending the grammar without moving this constant would leave /// and G2a: extending the grammar without moving this constant would leave
/// two incompatible grammars both claiming `(0 10 0)`. /// two incompatible grammars both claiming `(0 10 0)`.
pub const COMPANION_VERSION: (u32, u32, u32) = (0, 11, 0); ///
/// Bumped again 0.11.0 → 0.12.0 by the genesis tranche G3a
/// (`spec/CONTRACT_GENESIS_G3A_ENTITIES.md`), which appended
/// `create-staff-group`, `create-part-definition`, `create-analysis-layer`,
/// and `create-view` to the `kind` production — the same reasoning as every
/// prior kind append: extending the grammar without moving this constant
/// would leave two incompatible grammars both claiming `(0 11 0)`.
pub const COMPANION_VERSION: (u32, u32, u32) = (0, 12, 0);
/// A parsed canonical Text Projection document. /// A parsed canonical Text Projection document.
/// ///

View File

@ -650,11 +650,11 @@ 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). Kept a literal because `projection` takes `&[&str]` and a // G2b; 0.11.0 → 0.12.0, genesis G3a). Kept a literal because `projection`
// formatted String would ripple through every call site; // takes `&[&str]` and a formatted String would ripple through every call
// `the_test_header_tracks_the_implemented_version` below fails loudly if // site; `the_test_header_tracks_the_implemented_version` below fails
// the two ever drift. // loudly if the two ever drift.
const HEADER: &str = "(text-projection (0 11 0))"; const HEADER: &str = "(text-projection (0 12 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

@ -21,9 +21,13 @@ use epiphany_bundle::{
ProfileConstraints, ProfileDeclaration, ProfileId, ProfileRegistryId, ProfileConstraints, ProfileDeclaration, ProfileId, ProfileRegistryId,
ReductionAlgorithmVersion, SchemaVersion, SemVer, SnapshotId, ReductionAlgorithmVersion, SchemaVersion, SemVer, SnapshotId,
}; };
use epiphany_core::{OperationId, RegionId, ReplicaId, WallClockTime}; use epiphany_core::{
AnalysisLayerId, OperationId, PartDefinitionId, RegionId, ReplicaId, StaffGroupId, StaffId,
ViewId, WallClockTime,
};
use epiphany_ops::{ use epiphany_ops::{
AuthorId, CausalContext, DeleteRegionOp, HybridLogicalClock, OperationEnvelope, OperationKind, AuthorId, CausalContext, CreateAnalysisLayerOp, CreatePartDefinitionOp, CreateStaffGroupOp,
CreateViewOp, DeleteRegionOp, HybridLogicalClock, OperationEnvelope, OperationKind,
OperationPayload, OperationStamp, SetTuningContextOp, OperationPayload, OperationStamp, SetTuningContextOp,
}; };
@ -177,6 +181,83 @@ fn tuning_context_envelope(counter: u64, physical_time: i64) -> OperationEnvelop
} }
} }
/// The four genesis tranche G3a envelopes (kinds 3538,
/// `spec/CONTRACT_GENESIS_G3A_ENTITIES.md`). Same rationale as
/// `tuning_context_envelope` above: the typed all-kind round-trip test proves
/// the *production* parses, but only a committed vector proves the emitted
/// document text is stable across implementations.
fn staff_group_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::CreateStaffGroup(CreateStaffGroupOp {
group: epiphany_ops::valuegen::staff_group(
StaffGroupId::new(ReplicaId(1), 1),
vec![StaffId::new(ReplicaId(1), 1)],
),
})),
}
}
fn part_definition_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::CreatePartDefinition(
CreatePartDefinitionOp {
part: epiphany_ops::valuegen::part_definition(
PartDefinitionId::new(ReplicaId(1), 1),
vec![StaffId::new(ReplicaId(1), 1)],
),
},
)),
}
}
fn analysis_layer_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::CreateAnalysisLayer(
CreateAnalysisLayerOp {
layer: epiphany_ops::valuegen::analysis_layer(AnalysisLayerId::new(
ReplicaId(1),
1,
)),
},
)),
}
}
fn view_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::CreateView(CreateViewOp {
view: epiphany_ops::valuegen::view(
ViewId::new(ReplicaId(1), 1),
vec![AnalysisLayerId::new(ReplicaId(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 {
@ -291,6 +372,50 @@ fn accept_documents() -> Vec<(&'static str, String)> {
envelopes: vec![tuning_context_envelope(7, 700)], envelopes: vec![tuning_context_envelope(7, 700)],
}; };
// Genesis G3a: kinds 3538 in the committed corpus. Same manifest-version
// discipline as `tuning_context` above — baseline `V0`, since none of
// these documents declares an edit barrier either.
let staff_group = TextDocument {
document_id: DocumentId([6; 16]),
manifest_schema_version: SchemaVersion::V0,
lineage_id: None,
profiles: profiles(false),
extensions: Vec::new(),
canonical_base: None,
blobs: Vec::new(),
envelopes: vec![staff_group_envelope(8, 800)],
};
let part_definition = TextDocument {
document_id: DocumentId([7; 16]),
manifest_schema_version: SchemaVersion::V0,
lineage_id: None,
profiles: profiles(false),
extensions: Vec::new(),
canonical_base: None,
blobs: Vec::new(),
envelopes: vec![part_definition_envelope(9, 900)],
};
let analysis_layer = TextDocument {
document_id: DocumentId([8; 16]),
manifest_schema_version: SchemaVersion::V0,
lineage_id: None,
profiles: profiles(false),
extensions: Vec::new(),
canonical_base: None,
blobs: Vec::new(),
envelopes: vec![analysis_layer_envelope(10, 1000)],
};
let view = TextDocument {
document_id: DocumentId([9; 16]),
manifest_schema_version: SchemaVersion::V0,
lineage_id: None,
profiles: profiles(false),
extensions: Vec::new(),
canonical_base: None,
blobs: Vec::new(),
envelopes: vec![view_envelope(11, 1100)],
};
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)),
@ -303,6 +428,16 @@ fn accept_documents() -> Vec<(&'static str, String)> {
project_text_document(&extension_base_multi), project_text_document(&extension_base_multi),
), ),
("rich_document", project_text_document(&rich)), ("rich_document", project_text_document(&rich)),
("create_staff_group", project_text_document(&staff_group)),
(
"create_part_definition",
project_text_document(&part_definition),
),
(
"create_analysis_layer",
project_text_document(&analysis_layer),
),
("create_view", project_text_document(&view)),
] ]
} }
@ -387,16 +522,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 G2b moved `COMPANION_VERSION` to 0.11.0, which had been this // tranche G3a moved `COMPANION_VERSION` to 0.12.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.10.0, the immediately superseded companion, which is the better test // 0.11.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 12 0))",
"(text-projection (0 11 0))", "(text-projection (0 11 0))",
"(text-projection (0 10 0))",
); );
vectors.push(( vectors.push((
SURFACE, SURFACE,
@ -716,7 +851,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, 14, "the corpus has unexpectedly thinned"), Ok(count) => assert_eq!(count, 18, "the corpus has unexpectedly thinned"),
Err(failures) => panic!( Err(failures) => panic!(
"{} disagreement(s):\n{}", "{} disagreement(s):\n{}",
failures.len(), failures.len(),
@ -754,4 +889,61 @@ mod tests {
2 lineages, 2 multi-envelope documents, and one real rejection in each class" 2 lineages, 2 multi-envelope documents, and one real rejection in each class"
); );
} }
/// (t11) Genesis tranche G3a: text projection round-trips all four new
/// kinds (`create-staff-group`, `create-part-definition`,
/// `create-analysis-layer`, `create-view`), and the companion version is
/// **0.12.0**, with the negative vector rejecting **0.11.0**.
///
/// **Mutation:** drop one parse arm (e.g.
/// `OperationKindTag::CreateStaffGroup` from `OperationKind::parse` in
/// `textproj_kind.rs`); must fail. Separately, leave `COMPANION_VERSION`
/// at `(0, 11, 0)`; the negative vector must fail.
#[test]
fn t11_g3a_kinds_round_trip_and_companion_is_0_12_0_rejecting_0_11_0() {
assert_eq!(
crate::COMPANION_VERSION,
(0, 12, 0),
"the companion version must be 0.12.0"
);
for name in [
"create_staff_group",
"create_part_definition",
"create_analysis_layer",
"create_view",
] {
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
// companion, 0.11.0.
let rows = parse(COMMITTED).expect("the committed corpus parses");
let superseded = rows
.iter()
.find(|r| r.name == "superseded_companion_version")
.expect("the superseded_companion_version vector is present");
assert_eq!(superseded.verdict, "reject");
let text = String::from_utf8(superseded.text.clone()).expect("utf8");
assert!(
text.contains("(text-projection (0 11 0))"),
"the negative vector must name the immediately superseded companion 0.11.0, got: {text}"
);
assert!(
parse_document(&text).is_err(),
"the superseded companion version must be rejected"
);
}
} }

View File

@ -6,8 +6,8 @@ reverses Pass-12 K8 and makes every mutable field of `Score` operation-authored.
This plan is the execution scope: what the tranche touches, in what order, and This plan is the execution scope: what the tranche touches, in what order, and
which questions must be answered before a dispatch contract can be written. which questions must be answered before a dispatch contract can be written.
**Status:** the ladder **G1 → G2a → G-minor → G2b** is **complete**; only **G3** **Status:** the ladder **G1 → G2a → G-minor → G2b → G3a** is **complete**;
remains, and it **splits into G3a and G3b** (ratified 2026-07-29, §4). only **G3b** remains (ratified 2026-07-29, §4).
* **G1 landed** (3b09595) — `CreateInstrument`, kind/tag 31. * **G1 landed** (3b09595) — `CreateInstrument`, kind/tag 31.
* **G2a landed** (7df5ca1 + 55eff00) — `SetCanvasLayoutDefaults` and * **G2a landed** (7df5ca1 + 55eff00) — `SetCanvasLayoutDefaults` and
@ -22,12 +22,13 @@ remains, and it **splits into G3a and G3b** (ratified 2026-07-29, §4).
`epiphany_core::TuningContextSettings`, **not** the full graph type — §5 `epiphany_core::TuningContextSettings`, **not** the full graph type — §5
trap 7's holdout, resolved in the contract as *subset over normalization*. trap 7's holdout, resolved in the contract as *subset over normalization*.
Closed **P13-S13**. Closed **P13-S13**.
* **G3a** — the four root-level mint families (`CreateStaffGroup`, * **G3a landed** (commit pending) — the four root-level mint families
`CreatePartDefinition`, `CreateAnalysisLayer`, `CreateView`), kinds/tags (`CreateStaffGroup`, `CreatePartDefinition`, `CreateAnalysisLayer`,
**3538**, epoch **11**, all schema major **0**. Contracted `CreateView`), kinds/tags **3538**, epoch **11**, all schema major **0**.
(`spec/CONTRACT_GENESIS_G3A_ENTITIES.md`) and **ready to dispatch**; §1.1's Executed against `spec/CONTRACT_GENESIS_G3A_ENTITIES.md`; §1.1's
`StaffGroup`/`Staff` authorship-authority pin was ratified 2026-07-29 as `StaffGroup`/`Staff` authorship-authority pin was ratified 2026-07-29 as
disposition B and filed as **P13-S16**. disposition B and filed as **P13-S16**. No `epiphany-bundle` change of any
kind; op-block accept-set stays at 3 where G2b left it.
* **G3b**`CreateMeasure` alone, kind/tag **39**, epoch **12**, carrying * **G3b**`CreateMeasure` alone, kind/tag **39**, epoch **12**, carrying
graph invariant **20** and a new `PreconditionFailureReason` at discriminant graph invariant **20** and a new `PreconditionFailureReason` at discriminant
**16**. Scoped, not contracted. **16**. Scoped, not contracted.

View File

@ -178,6 +178,7 @@ numbering spaces are unrelated and must not be cross-read.
| 8 | Genesis G1 | `OperationKind`/`OperationKindTag` 31 | | 8 | Genesis G1 | `OperationKind`/`OperationKindTag` 31 |
| 9 | Genesis G2a | `OperationKind`/`OperationKindTag` 3233 | | 9 | Genesis G2a | `OperationKind`/`OperationKindTag` 3233 |
| 10 | Genesis G2b | `OperationKind`/`OperationKindTag` 34 (`SetTuningContext`) | | 10 | Genesis G2b | `OperationKind`/`OperationKindTag` 34 (`SetTuningContext`) |
| 11 | Genesis G3a | `OperationKind`/`OperationKindTag` 3538 (`CreateStaffGroup`, `CreatePartDefinition`, `CreateAnalysisLayer`, `CreateView`) |
> **Epoch 10 ratified 2026-07-28**, with G2b as the event. This is the **first > **Epoch 10 ratified 2026-07-28**, with G2b as the event. This is the **first
> exercise of the ladder's own growth path**: G-minor's `introduced_minor()` is > exercise of the ladder's own growth path**: G-minor's `introduced_minor()` is
@ -186,6 +187,13 @@ numbering spaces are unrelated and must not be cross-read.
> (G2b follows G2a) and prefix-closed. Epoch assignment remains a ratified > (G2b follows G2a) and prefix-closed. Epoch assignment remains a ratified
> schema decision, never an implementer's choice. > schema decision, never an implementer's choice.
> **Epoch 11 ratified 2026-07-29**, with G3a as the event (introducing commit
> pending — this rung has not yet landed a commit; update this citation once
> it does, per the same discipline as the G2a correction above). One epoch for
> the whole rung's four kinds, the G2a precedent (two kinds at epoch 9) rather
> than one epoch per kind. The ladder stays monotonic (G3a follows G2b) and
> prefix-closed.
**The ladder is complete against the audit** — every post-baseline variant in **The ladder is complete against the audit** — every post-baseline variant in
`AUDIT_GMINOR_VOCABULARIES.md` appears exactly once: all ten kind/tag pairs, `AUDIT_GMINOR_VOCABULARIES.md` appears exactly once: all ten kind/tag pairs,
`OperationPayload` 3, `ReanchorReason` 6, and all six `OperationPayload` 3, `ReanchorReason` 6, and all six

Binary file not shown.

View File

@ -240,7 +240,7 @@
{\Large\scshape\color{epiphanyslate}Binary Format}\\[6pt] {\Large\scshape\color{epiphanyslate}Binary Format}\\[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.13.0 --- The chunk schema minor becomes a derived record (G-minor)}\\[4pt] {\normalsize\color{epiphanyink}Version 0.14.0 --- The genesis operation tranche completes the root-level entity mints (G3a)}\\[4pt]
{\small\color{epiphanyslate}Normative for the byte layouts it defines} {\small\color{epiphanyslate}Normative for the byte layouts it defines}
\vfill \vfill
\end{titlepage} \end{titlepage}
@ -1462,6 +1462,18 @@ and the reader disagree about the field's type.
\texttt{ScoreTuningContext} layout (Section~\ref{sec:evolution:major3}); \texttt{ScoreTuningContext} layout (Section~\ref{sec:evolution:major3});
born at v3 unconditionally & born at v3 unconditionally &
\sectionsc{SetTuningContext} \\ \sectionsc{SetTuningContext} \\
\tablenums{35} & \texttt{CreateStaffGroup} &
$\mathrm{lp}$(\texttt{StaffGroup}) &
\sectionsc{CreateStaffGroup} \\
\tablenums{36} & \texttt{CreatePartDefinition} &
$\mathrm{lp}$(\texttt{PartDefinition}) &
\sectionsc{CreatePartDefinition} \\
\tablenums{37} & \texttt{CreateAnalysisLayer} &
$\mathrm{lp}$(\texttt{AnalysisLayer}) &
\sectionsc{CreateAnalysisLayer} \\
\tablenums{38} & \texttt{CreateView} &
$\mathrm{lp}$(\texttt{ViewDefinition}) &
\sectionsc{CreateView} \\
\bottomrule \bottomrule
\end{longtable} \end{longtable}
\endgroup \endgroup
@ -1532,7 +1544,9 @@ discriminants and wrong lengths are decode errors. Append-only past
\tablenums{28} & \texttt{CreateRepeatStructure} & \tablenums{29} & \texttt{DeleteRepeatStructure} \\ \tablenums{28} & \texttt{CreateRepeatStructure} & \tablenums{29} & \texttt{DeleteRepeatStructure} \\
\tablenums{30} & \texttt{TransposeInterval} & \tablenums{31} & \texttt{CreateInstrument} \\ \tablenums{30} & \texttt{TransposeInterval} & \tablenums{31} & \texttt{CreateInstrument} \\
\tablenums{32} & \texttt{SetCanvasLayoutDefaults} & \tablenums{33} & \texttt{SetSpellingPrecedence} \\ \tablenums{32} & \texttt{SetCanvasLayoutDefaults} & \tablenums{33} & \texttt{SetSpellingPrecedence} \\
\tablenums{34} & \texttt{SetTuningContext} & & \\ \tablenums{34} & \texttt{SetTuningContext} & \tablenums{35} & \texttt{CreateStaffGroup} \\
\tablenums{36} & \texttt{CreatePartDefinition} & \tablenums{37} & \texttt{CreateAnalysisLayer} \\
\tablenums{38} & \texttt{CreateView} & & \\
\bottomrule \bottomrule
\end{longtable} \end{longtable}
\endgroup \endgroup
@ -2382,7 +2396,7 @@ The \emph{only} minor-additive mechanism in schema major~0 is
\textbf{appending discriminants to open vocabularies}: \textbf{appending discriminants to open vocabularies}:
\begin{itemize} \begin{itemize}
\item \texttt{OperationKind}: append at ${\geq}\,\tablenums{35}$ \item \texttt{OperationKind}: append at ${\geq}\,\tablenums{39}$
(Requirement~\ref{req:binfmt:kind-discriminants}; the Phase-3 (Requirement~\ref{req:binfmt:kind-discriminants}; the Phase-3
tranche took \tablenums{24}--\tablenums{27} under this mechanism, tranche took \tablenums{24}--\tablenums{27} under this mechanism,
the repeat pair \tablenums{28}/\tablenums{29} in the the repeat pair \tablenums{28}/\tablenums{29} in the
@ -2390,18 +2404,23 @@ The \emph{only} minor-additive mechanism in schema major~0 is
(\texttt{TransposeInterval}), genesis tranche G1 took \tablenums{31} (\texttt{TransposeInterval}), genesis tranche G1 took \tablenums{31}
(\texttt{CreateInstrument}), genesis tranche G2a took (\texttt{CreateInstrument}), genesis tranche G2a took
\tablenums{32}/\tablenums{33} (\texttt{SetCanvasLayoutDefaults}, \tablenums{32}/\tablenums{33} (\texttt{SetCanvasLayoutDefaults},
\texttt{SetSpellingPrecedence}), and genesis tranche G2b took \texttt{SetSpellingPrecedence}), genesis tranche G2b took
\tablenums{34} (\texttt{SetTuningContext}) --- the discriminant space is \tablenums{34} (\texttt{SetTuningContext}), and genesis tranche G3a took
\tablenums{35}--\tablenums{38} (\texttt{CreateStaffGroup},
\texttt{CreatePartDefinition}, \texttt{CreateAnalysisLayer},
\texttt{CreateView}) --- the discriminant space is
one append-only table across majors, but a kind's \emph{block stamp} one append-only table across majors, but a kind's \emph{block stamp}
follows minimal stamping over its payload: \tablenums{28}'s payload follows minimal stamping over its payload: \tablenums{28}'s payload
embeds a v2 layout, so its blocks stamp major~2, embeds a v2 layout, so its blocks stamp major~2,
Section~\ref{sec:evolution:major2}; \tablenums{34}'s payload embeds a v3 Section~\ref{sec:evolution:major2}; \tablenums{34}'s payload embeds a v3
layout unconditionally, so its blocks stamp major~3, layout unconditionally, so its blocks stamp major~3,
Section~\ref{sec:evolution:major3} --- the sole appended kind to do so); Section~\ref{sec:evolution:major3} --- the sole appended kind to do so;
\item \texttt{OperationKindTag}: append at ${\geq}\,\tablenums{35}$ \tablenums{35}--\tablenums{38} are each major~0, no versioned walk
(Requirement~\ref{req:binfmt:kind-tag}; the same eleven variants as existing for any of their four carried types);
\texttt{OperationKind}, at the same eleven discriminants, appended by \item \texttt{OperationKindTag}: append at ${\geq}\,\tablenums{39}$
the same six tranches); (Requirement~\ref{req:binfmt:kind-tag}; the same fifteen variants as
\texttt{OperationKind}, at the same fifteen discriminants, appended by
the same seven tranches);
\item \texttt{OperationPayload}: append at ${\geq}\,\tablenums{4}$ \item \texttt{OperationPayload}: append at ${\geq}\,\tablenums{4}$
(Section~\ref{sec:ops:payload}; \texttt{ResolveEquivocation} = 3, Push~3, (Section~\ref{sec:ops:payload}; \texttt{ResolveEquivocation} = 3, Push~3,
is the one and only append this vocabulary has had); is the one and only append this vocabulary has had);
@ -3621,6 +3640,23 @@ only}: implementations need not agree on an error taxonomy.
current. No discriminant, wire layout, or accept-set changes: this is a current. No discriminant, wire layout, or accept-set changes: this is a
correction to prose and a new writer-side derivation, not a new appended correction to prose and a new writer-side derivation, not a new appended
variant. \\ variant. \\
\today & Operation wire forms & 0.14.0 --- Genesis tranche G3a
(\texttt{spec/CONTRACT\_GENESIS\_G3A\_ENTITIES.md}): appends
\texttt{OperationKind} wire discriminants \tablenums{35}--\tablenums{38}
(\texttt{CreateStaffGroup}, \texttt{CreatePartDefinition},
\texttt{CreateAnalysisLayer}, \texttt{CreateView}) with their payload
layouts, and the matching \texttt{OperationKindTag} discriminants
\tablenums{35}--\tablenums{38} (name-verbatim, following the two most
recent additions rather than the tag space's older Create$\rightarrow$Insert
convention) --- a schema-\emph{minor} evolution (epoch~11,
\texttt{spec/PLAN\_GMINOR\_SCHEMA\_MINOR.md} \S4) under this document's own
append-only rules; no existing assignment changed. All four carried types
(\texttt{StaffGroup}, \texttt{PartDefinition}, \texttt{AnalysisLayer},
\texttt{ViewDefinition}) have never been versioned as standalone values, so
no accept-set moves: \texttt{OperationEnvelopeBlock} stays at
\tablenums{3} where genesis tranche G2b left it. Semantics: Operation
Catalog \sectionsc{CreateStaffGroup}, \sectionsc{CreatePartDefinition},
\sectionsc{CreateAnalysisLayer}, \sectionsc{CreateView}, 0.12.0. \\
\bottomrule \bottomrule
\end{longtable} \end{longtable}

Binary file not shown.

View File

@ -4232,6 +4232,13 @@ pub struct StaffGroup {
pub id: StaffGroupId, pub id: StaffGroupId,
pub name: Option<String>, pub name: Option<String>,
pub kind: StaffGroupKind, pub kind: StaffGroupKind,
/// A non-authoritative denormalized projection of group membership
/// (genesis tranche G3a, ratified disposition B, filed as P13-S16).
/// \texttt{Staff.group} below is the sole authority: this field
/// \MUSTNOT{} be read to decide whether a staff is in a group, and MAY
/// be stale in both directions --- a member missing here while
/// \texttt{Staff.group} names this group, or a staff listed here while
/// its own \texttt{Staff.group} is absent or names a different group.
pub members: Vec<StaffId>, pub members: Vec<StaffId>,
} }
@ -5576,7 +5583,12 @@ pub struct Staff {
pub default_staff_lines: StaffLineConfiguration, pub default_staff_lines: StaffLineConfiguration,
/// Visual grouping: which staff group (if any) this staff /// Visual grouping: which staff group (if any) this staff
/// belongs to (e.g., piano grand staff, choral group). /// belongs to (e.g., piano grand staff, choral group). The sole
/// authority for group membership (genesis tranche G3a, ratified
/// disposition B, filed as P13-S16): every consumer \MUST{} read
/// membership from this field, not from \texttt{StaffGroup.members}
/// above, which is a non-authoritative denormalized projection that MAY
/// disagree with this field in either direction.
pub group: Option<StaffGroupId>, pub group: Option<StaffGroupId>,
} }
@ -6969,6 +6981,16 @@ pub enum OperationKind {
// on the wire and is left untouched by reduction). // on the wire and is left untouched by reduction).
SetTuningContext(SetTuningContextOp), SetTuningContext(SetTuningContextOp),
// Genesis tranche G3a: the four remaining root-level Score entity
// mints, on the InsertStaff set-union mint pattern. Staff.group is the
// sole authority for group membership (see the Staff/StaffGroup
// declarations below); CreateStaffGroup stores members as carried and
// neither maintains nor trusts it.
CreateStaffGroup(CreateStaffGroupOp),
CreatePartDefinition(CreatePartDefinitionOp),
CreateAnalysisLayer(CreateAnalysisLayerOp),
CreateView(CreateViewOp),
// Layout-semantic operations // Layout-semantic operations
SetUserSystemBreak(SetUserSystemBreakOp), SetUserSystemBreak(SetUserSystemBreakOp),
SetUserPageBreak(SetUserPageBreakOp), SetUserPageBreak(SetUserPageBreakOp),
@ -11938,6 +11960,12 @@ pub enum OperationKindTag {
SetSpellingPrecedence, SetSpellingPrecedence,
// Genesis tranche G2b: name-verbatim, as the two prior additions are. // Genesis tranche G2b: name-verbatim, as the two prior additions are.
SetTuningContext, SetTuningContext,
// Genesis tranche G3a: the four remaining root-level entity mints,
// name-verbatim, as the three most recent prior additions are.
CreateStaffGroup,
CreatePartDefinition,
CreateAnalysisLayer,
CreateView,
} }
pub enum BarrierScope { pub enum BarrierScope {

Binary file not shown.

View File

@ -231,7 +231,7 @@
{\Large\scshape\color{epiphanyslate}Operation Catalog}\\[6pt] {\Large\scshape\color{epiphanyslate}Operation Catalog}\\[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.11.0 --- The genesis operation tranche reaches schema major 3 (G2b)}\\[4pt] {\normalsize\color{epiphanyink}Version 0.12.0 --- The genesis operation tranche completes the root-level entity mints (G3a)}\\[4pt]
{\small\color{epiphanyslate}Normative for the operation kinds it defines} {\small\color{epiphanyslate}Normative for the operation kinds it defines}
\vfill \vfill
\end{titlepage} \end{titlepage}
@ -417,6 +417,65 @@ context (the canonical base embeds no \texttt{Score} field value for any
setting, \texttt{metadata} included), on the same reasoning that already setting, \texttt{metadata} included), on the same reasoning that already
applied to \texttt{SetMetadata}. applied to \texttt{SetMetadata}.
\medskip
\noindent\textbf{Version 0.12.0 (genesis tranche G3a,
\texttt{spec/CONTRACT\_GENESIS\_G3A\_ENTITIES.md}).} Adds four operation
kinds --- \texttt{CreateStaffGroup} (Section~\ref{sec:k0:create-staff-group}),
\texttt{CreatePartDefinition} (Section~\ref{sec:k0:create-part-definition}),
\texttt{CreateAnalysisLayer} (Section~\ref{sec:k0:create-analysis-layer}),
\texttt{CreateView} (Section~\ref{sec:k0:create-view}) --- completing the
root-level \texttt{Score} entity mints: every remaining vector a Chapter~5
top-level structure declares (\texttt{staff\_groups}, \texttt{parts},
\texttt{analysis\_layers}, \texttt{views}) is now operation-authored. All
four are mint-only (set-union creation, no delete in this catalogue
revision), schema major~0 unconditionally, epoch~11.
\textbf{The defect this closes, and what it does not close.} Until this
rung, all four object kinds became live \emph{only} through canonical-base
ingest; no operation minted any of them. Consequently \texttt{CreateStaff}'s
\texttt{group} precondition (Section~\ref{sec:k0:create-staff}) was
\textbf{unsatisfiable} under from-empty reduction --- a document built only
from operations could never author a grouped staff. G3a closes exactly this
satisfiability half. It does \textbf{not} make a bidirectionally consistent
staff group authorable: with mints only, and no modify or delete operation
for either side, no authoring order can bring \texttt{Staff.group} and
\texttt{StaffGroup.members} into agreement once they disagree.
\textbf{Ruled (disposition B, filed as P13-S16): \texttt{Staff.group} is the
sole authority for group membership; \texttt{StaffGroup.members} is a
non-authoritative denormalized projection.} \texttt{CreateStaffGroup} stores
\texttt{members} exactly as carried and neither maintains nor trusts it
thereafter. Both stale forms are permitted outcomes, not defects: a
\textbf{missing} member (\texttt{Staff.group} names a group whose
\texttt{members} omits that staff) and a \textbf{spurious} member
(\texttt{StaffGroup.members} names a staff whose own \texttt{Staff.group} is
absent or names a different group). Every consumer \MUST{} read group
membership from \texttt{Staff.group} only; core specification Chapter~5's
\texttt{Staff}/\texttt{StaffGroup} declarations (\sectionsc{Top-Level Score
Structure}) now state this normatively, and Section~\ref{sec:k0:create-staff}
above states the corresponding authoring-order consequence for
\texttt{CreateStaff}. Disposition A (maintaining \texttt{members} by
reduction, making it a derived field) remains the later
maintenance/enforcement fix, sequenced after G3b.
\textbf{Referential preconditions, graph-aware only, mirroring
\texttt{CreateStaff} exactly.} \texttt{CreateStaffGroup.members} and
\texttt{CreatePartDefinition.staves} each precondition every named id
resolves to a live \texttt{Staff}; \texttt{CreateView.active\_layers}
preconditions every named id resolves to a live analysis layer;
\texttt{CreateAnalysisLayer} carries no outbound reference and needs no
referential precondition at all, the \texttt{CreateInstrument} shape rather
than the \texttt{CreateStaff} shape. Base-free reduction enforces none of
these, exactly as for \texttt{CreateStaff}: there is no universe to check
against. No new \texttt{PreconditionFailureReason} --- every referential
refusal reuses \texttt{TargetMissing} (discriminant 0).
No accept-set change: all four carried types have exactly one wire layout
(core specification's \sectionsc{Binary Format Companion} confirms no
versioned walk exists for any of the four), so none gains a
\texttt{schema\_major()} arm beyond the existing catch-all.
% =========================================================================== % ===========================================================================
\chapter{The Catalog Framework} \chapter{The Catalog Framework}
\label{ch:framework} \label{ch:framework}
@ -1137,6 +1196,21 @@ With staves mintable, \texttt{CreateStaffInstance}
instance's referenced \texttt{Staff} is live (previously the reference was instance's referenced \texttt{Staff} is live (previously the reference was
satisfiable only from the seeded base, so the check was vacuous). satisfiable only from the seeded base, so the check was vacuous).
\textbf{Stale-form semantics (genesis tranche G3a, disposition B, filed as
P13-S16).} \texttt{Staff.group} is the \textbf{sole authority} for group
membership; \texttt{StaffGroup.members}
(Section~\ref{sec:k0:create-staff-group}) is a non-authoritative denormalized
projection no consumer may read to decide membership. \texttt{CreateStaff}
is the operation that authors the \textbf{missing-member} stale form: a
\texttt{CreateStaffGroup(g, members: [])} followed by a
\texttt{CreateStaff(s, group: Some(g))} leaves \texttt{s.group == Some(g)}
while \texttt{g.members} omits \texttt{s} --- a \textbf{permitted} outcome,
not a defect, since G3a mints only and no operation maintains
\texttt{StaffGroup.members} by reduction. The mirror-image \textbf{spurious}
form (a staff named in \texttt{members} whose own \texttt{group} is absent or
different) is authored by \texttt{CreateStaffGroup} instead; see
Section~\ref{sec:k0:create-staff-group}'s own stale-form paragraph.
\textbf{Conflict cases.} None at reduction time (set-union; the differing-value \textbf{Conflict cases.} None at reduction time (set-union; the differing-value
re-create is a precondition gate, not a conflict). re-create is a precondition gate, not a conflict).
@ -1355,6 +1429,162 @@ undo leaves it exactly as it found it.
\textbf{Re-anchoring.} Not applicable: the field is a score singleton with no \textbf{Re-anchoring.} Not applicable: the field is a score singleton with no
tombstonable anchor. tombstonable anchor.
\section{CreateStaffGroup}
\label{sec:k0:create-staff-group}
Ratified with the genesis operation tranche's G3a rung (\texttt{spec/
CONTRACT\_GENESIS\_G3A\_ENTITIES.md}, executing \texttt{spec/RULING\_
GENESIS\_PERSISTENCE.md}): a global staff grouping (\texttt{Score.
staff\_groups}) joins the operation-authored surfaces, on the
\texttt{CreateStaff} set-union mint pattern (Section~\ref{sec:k0:create-staff}).
\textbf{Payload schema.} \texttt{CreateStaffGroupOp \{ group: StaffGroup \}}
--- the full staff-group value: identity, optional name, kind (grand staff,
bracket, sub-bracket, choral, or a registered extension kind), and the
carried \texttt{members} list.
\textbf{Canonical encoding.} The length-framed canonical bytes of
\texttt{group}. \texttt{StaffGroup} has never been versioned, so this
operation is schema major~0 unconditionally.
\textbf{Reduction rule.} Set-union creation, mirroring \texttt{CreateStaff}
exactly: a create mints the group live if its id is fresh; a repeat create
carrying a byte-identical value reduces idempotently
(\texttt{NoOpReason::AlreadyApplied}); a create whose id is already live with
a differing value is a precondition no-op with \texttt{RecreateContentMismatch};
a create naming a tombstoned id is a precondition no-op with
\texttt{TargetTombstoned}. Graph-aware reduction additionally preconditions
that every id in \texttt{members} resolves to a live \texttt{Staff} ---
reusing \texttt{TargetMissing} (discriminant 0), no new
\texttt{PreconditionFailureReason} --- and is skipped entirely base-free,
which has no staff universe to check against.
\textbf{Stale-form semantics (disposition B, filed as P13-S16).}
\texttt{Staff.group} (Section~\ref{sec:k0:create-staff}) is the \textbf{sole
authority} for group membership; \texttt{members} here is a
\textbf{non-authoritative denormalized projection}, stored exactly as carried
and \textbf{neither maintained nor trusted} by any subsequent reduction. This
operation authors the \textbf{spurious-member} stale form: a
\texttt{CreateStaff(s, group: None)} followed by
\texttt{CreateStaffGroup(g, members: [s])} leaves \texttt{g.members == [s]}
while \texttt{s.group} stays \texttt{None} (or names a different group) ---
a \textbf{permitted} outcome, not a defect. No consumer may read
\texttt{members} to decide whether a staff belongs to a group.
\textbf{Conflict cases.} None at reduction time (set-union; the differing-value
re-create is a precondition gate, not a conflict).
\textbf{Undo semantics.} Undo of a create tombstones the minted group
(Section~\ref{sec:k0:undo}); \texttt{StrictInverse} conflicts if a live staff
still names it (a stale reference, not a strand --- \texttt{Staff.group}
degrading to point at a tombstoned id is the same shape core Chapter~6's
re-anchoring rule table already treats for other dangling references).
\textbf{Re-anchoring.} Not applicable (a staff-group mint references no
tombstonable anchor; there is no \texttt{DeleteStaffGroup} in this catalogue
revision, mirroring \texttt{CreateStaff}'s own absent delete).
\section{CreatePartDefinition}
\label{sec:k0:create-part-definition}
Ratified with genesis tranche G3a, alongside \texttt{CreateStaffGroup} above:
a part-extraction view definition (\texttt{Score.parts}) joins the
operation-authored surfaces, on the same \texttt{CreateStaff} set-union mint
pattern.
\textbf{Payload schema.} \texttt{CreatePartDefinitionOp \{ part:
PartDefinition \}} --- identity, name, and the carried \texttt{staves} list.
Parts are projections, not storage (core specification Chapter~5
\sectionsc{Parts}): only references and overrides.
\textbf{Canonical encoding.} The length-framed canonical bytes of
\texttt{part}. \texttt{PartDefinition} has never been versioned, so this
operation is schema major~0 unconditionally.
\textbf{Reduction rule.} Set-union creation, mirroring \texttt{CreateStaff}
exactly (mint/idempotence/mismatch/tombstone as above). Graph-aware reduction
additionally preconditions that every id in \texttt{staves} resolves to a
live \texttt{Staff} (\texttt{TargetMissing}, no new failure reason), skipped
base-free.
\textbf{Conflict cases.} None at reduction time (set-union; the differing-value
re-create is a precondition gate, not a conflict).
\textbf{Undo semantics.} Undo of a create tombstones the minted part
(Section~\ref{sec:k0:undo}); \texttt{StrictInverse} conflicts if concurrently
mutated.
\textbf{Re-anchoring.} Not applicable (a part mint references no tombstonable
anchor; there is no \texttt{DeletePartDefinition} in this catalogue
revision).
\section{CreateAnalysisLayer}
\label{sec:k0:create-analysis-layer}
Ratified with genesis tranche G3a: a first-class analysis layer
(\texttt{Score.analysis\_layers}) joins the operation-authored surfaces, on
the \texttt{CreateInstrument} mint pattern
(Section~\ref{sec:k0:create-instrument}) --- not \texttt{CreateStaff}'s,
since \texttt{AnalysisLayer} holds no outbound entity reference.
\textbf{Payload schema.} \texttt{CreateAnalysisLayerOp \{ layer:
AnalysisLayer \}} --- identity and name only (core specification Chapter~5
\sectionsc{Analysis Layers and Views}).
\textbf{Canonical encoding.} The length-framed canonical bytes of
\texttt{layer}. \texttt{AnalysisLayer} has never been versioned, so this
operation is schema major~0 unconditionally.
\textbf{Reduction rule.} Set-union creation, mirroring \texttt{CreateInstrument}
exactly: mint/idempotence/mismatch/tombstone as above, with \textbf{no}
graph-aware reference-resolution block --- there is nothing for one to check.
\textbf{Conflict cases.} None at reduction time (set-union; the differing-value
re-create is a precondition gate, not a conflict).
\textbf{Undo semantics.} Undo of a create tombstones the minted layer
(Section~\ref{sec:k0:undo}); \texttt{StrictInverse} conflicts if a live view
still names it in \texttt{active\_layers} (Section~\ref{sec:k0:create-view}).
\textbf{Re-anchoring.} Not applicable (an analysis-layer mint references no
tombstonable anchor; there is no \texttt{DeleteAnalysisLayer} in this
catalogue revision).
\section{CreateView}
\label{sec:k0:create-view}
Ratified with genesis tranche G3a, the fourth and final root-level mint of
this rung: a view recipe (\texttt{Score.views}) joins the operation-authored
surfaces, on the \texttt{CreateStaff} set-union mint pattern.
\textbf{Payload schema.} \texttt{CreateViewOp \{ view: ViewDefinition \}} ---
identity, name, and the carried \texttt{active\_layers} list. The
view-\emph{kind} detail (core specification Chapter~7) is out of scope for
this baseline.
\textbf{Canonical encoding.} The length-framed canonical bytes of
\texttt{view}. \texttt{ViewDefinition} has never been versioned, so this
operation is schema major~0 unconditionally.
\textbf{Reduction rule.} Set-union creation, mirroring \texttt{CreateStaff}
exactly (mint/idempotence/mismatch/tombstone as above). Graph-aware reduction
additionally preconditions that every id in \texttt{active\_layers} resolves
to a live \texttt{AnalysisLayer} (\texttt{TargetMissing}, no new failure
reason), skipped base-free. \textbf{This packet is self-contained}: a
\texttt{CreateView}'s precondition target can be minted by a
\texttt{CreateAnalysisLayer} earlier in the same operation set, so the
ordering is testable end-to-end without a canonical base.
\textbf{Conflict cases.} None at reduction time (set-union; the differing-value
re-create is a precondition gate, not a conflict).
\textbf{Undo semantics.} Undo of a create tombstones the minted view
(Section~\ref{sec:k0:undo}); \texttt{StrictInverse} conflicts if concurrently
mutated.
\textbf{Re-anchoring.} Not applicable (a view mint references no tombstonable
anchor; there is no \texttt{DeleteView} in this catalogue revision).
\section{Repeat Structures} \section{Repeat Structures}
\label{sec:k0:repeat-structures} \label{sec:k0:repeat-structures}

Binary file not shown.

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.11.0 --- The genesis tuning-context setter reaches the grammar}\\[4pt] {\normalsize\color{epiphanyink}Version 0.12.0 --- The four remaining genesis root-level entity mints reach 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 11 0)}, the version of the companion it implements. It version: \texttt{(0 12 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.11.0, neither a canonical operation nor canonical reduced state can version~0.12.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}
@ -1062,6 +1062,10 @@ kind ::= "(insert-event " bytes " " value ")"
| "(set-canvas-layout-defaults " value ")" | "(set-canvas-layout-defaults " value ")"
| "(set-spelling-precedence " value ")" | "(set-spelling-precedence " value ")"
| "(set-tuning-context " value ")" | "(set-tuning-context " value ")"
| "(create-staff-group " value ")"
| "(create-part-definition " value ")"
| "(create-analysis-layer " value ")"
| "(create-view " 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* "))"
@ -1138,7 +1142,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 11 0)) (text-projection (0 12 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)
@ -1384,6 +1388,21 @@ absorb it, exactly as the binary decoder does.
version while extending the grammar would leave two mutually incompatible version while extending the grammar would leave two mutually incompatible
grammars both claiming \texttt{(0 10 0)}. Cached projections at grammars both claiming \texttt{(0 10 0)}. Cached projections at
\texttt{(0 10 0)} do not migrate; a stale \texttt{TextProjection} chunk is \texttt{(0 10 0)} do not migrate; a stale \texttt{TextProjection} chunk is
regenerated, not converted. \\
\today & Chapter 5 & 0.12.0 --- The four remaining genesis root-level
entity mints reach the grammar (genesis tranche G3a,
\texttt{spec/CONTRACT\_GENESIS\_G3A\_ENTITIES.md}). The \texttt{kind}
production gains \texttt{"(create-staff-group " value ")"},
\texttt{"(create-part-definition " value ")"},
\texttt{"(create-analysis-layer " value ")"}, and
\texttt{"(create-view " value ")"} (\texttt{req:textproj:operation-vocabulary}),
the fourth appended kind event since the header was gated to a single
version at 0.7.0.
Same forcing reason as every prior grammar-extending bump: holding the
version while extending the grammar would leave two mutually incompatible
grammars both claiming \texttt{(0 11 0)}. Cached projections at
\texttt{(0 11 0)} do not migrate; a stale \texttt{TextProjection} chunk is
regenerated, not converted. \\ regenerated, not converted. \\
\bottomrule \bottomrule
\end{longtable} \end{longtable}

View File

@ -72,8 +72,12 @@ ops.operation_kind_tag accept - tag_31 1f
ops.operation_kind_tag accept - tag_32 20 ops.operation_kind_tag accept - tag_32 20
ops.operation_kind_tag accept - tag_33 21 ops.operation_kind_tag accept - tag_33 21
ops.operation_kind_tag accept - tag_34 22 ops.operation_kind_tag accept - tag_34 22
ops.operation_kind_tag accept - tag_35 23
ops.operation_kind_tag accept - tag_36 24
ops.operation_kind_tag accept - tag_37 25
ops.operation_kind_tag accept - tag_38 26
ops.operation_kind_tag accept - registered 1000000000000000000123456789abcdef ops.operation_kind_tag accept - registered 1000000000000000000123456789abcdef
ops.operation_kind_tag reject unknown-discriminant tag_35_one_past_the_vocabulary 23 ops.operation_kind_tag reject unknown-discriminant tag_39_one_past_the_vocabulary 27
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
@ -88,6 +92,14 @@ ops.operation_envelope accept - set_spelling_precedence 000000000000000100000000
ops.operation_envelope reject trailing-bytes set_spelling_precedence_trailing 00000000000000010000000000000003000000000000000000000000000000000100000000000000010000000000000000000001000000000000000300000000000000000000210900000005000000040302010000 ops.operation_envelope reject trailing-bytes set_spelling_precedence_trailing 00000000000000010000000000000003000000000000000000000000000000000100000000000000010000000000000000000001000000000000000300000000000000000000210900000005000000040302010000
ops.operation_envelope accept - set_tuning_context 00000000000000010000000000000004000000000000000000000000000000000100000000000000010000000000000000000001000000000000000400000000000000000000223000000006000000636d6e2d3132060000007465742d313200050004080000000000000000907b40010028000100280000000000 ops.operation_envelope accept - set_tuning_context 00000000000000010000000000000004000000000000000000000000000000000100000000000000010000000000000000000001000000000000000400000000000000000000223000000006000000636d6e2d3132060000007465742d313200050004080000000000000000907b40010028000100280000000000
ops.operation_envelope reject trailing-bytes set_tuning_context_trailing 00000000000000010000000000000004000000000000000000000000000000000100000000000000010000000000000000000001000000000000000400000000000000000000223000000006000000636d6e2d3132060000007465742d313200050004080000000000000000907b4001002800010028000000000000 ops.operation_envelope reject trailing-bytes set_tuning_context_trailing 00000000000000010000000000000004000000000000000000000000000000000100000000000000010000000000000000000001000000000000000400000000000000000000223000000006000000636d6e2d3132060000007465742d313200050004080000000000000000907b4001002800010028000000000000
ops.operation_envelope accept - create_staff_group 00000000000000010000000000000005000000000000000000000000000000000100000000000000010000000000000000000001000000000000000500000000000000000000233f0000001000000000000000000000010000000000000001010d00000073746166662d67726f75702d3100010000001000000000000000000000010000000000000001
ops.operation_envelope reject trailing-bytes create_staff_group_trailing 00000000000000010000000000000005000000000000000000000000000000000100000000000000010000000000000000000001000000000000000500000000000000000000233f0000001000000000000000000000010000000000000001010d00000073746166662d67726f75702d310001000000100000000000000000000001000000000000000100
ops.operation_envelope accept - create_part_definition 000000000000000100000000000000060000000000000000000000000000000001000000000000000100000000000000000000010000000000000006000000000000000000002436000000100000000000000000000001000000000000000106000000706172742d31010000001000000000000000000000010000000000000001
ops.operation_envelope reject trailing-bytes create_part_definition_trailing 000000000000000100000000000000060000000000000000000000000000000001000000000000000100000000000000000000010000000000000006000000000000000000002436000000100000000000000000000001000000000000000106000000706172742d3101000000100000000000000000000001000000000000000100
ops.operation_envelope accept - create_analysis_layer 00000000000000010000000000000007000000000000000000000000000000000100000000000000010000000000000000000001000000000000000700000000000000000000251f0000001000000000000000000000010000000000000001070000006c617965722d31
ops.operation_envelope reject trailing-bytes create_analysis_layer_trailing 00000000000000010000000000000007000000000000000000000000000000000100000000000000010000000000000000000001000000000000000700000000000000000000251f0000001000000000000000000000010000000000000001070000006c617965722d3100
ops.operation_envelope accept - create_view 000000000000000100000000000000080000000000000000000000000000000001000000000000000100000000000000000000010000000000000008000000000000000000002636000000100000000000000000000001000000000000000106000000766965772d31010000001000000000000000000000010000000000000001
ops.operation_envelope reject trailing-bytes create_view_trailing 000000000000000100000000000000080000000000000000000000000000000001000000000000000100000000000000000000010000000000000008000000000000000000002636000000100000000000000000000001000000000000000106000000766965772d3101000000100000000000000000000001000000000000000100
# bundle.manifest # bundle.manifest
bundle.manifest accept - empty_manifest 6f9e7d11689ab113c4a1f05faf60fe60050505050505050505050505050505050000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000001000000000000000000000400000000010000000001000000000000 bundle.manifest accept - empty_manifest 6f9e7d11689ab113c4a1f05faf60fe60050505050505050505050505050505050000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000001000000000000000000000400000000010000000001000000000000

View File

@ -22,17 +22,21 @@
# 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 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a textproj.document accept - minimal 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a
textproj.document accept - set_tuning_context 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830353035303530353035303530353035303530353035303530353035303530352028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303037202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203730302030202378303030303030303030303030303030313030303030303030303030303030303729202863617573616c2028292028292920282920287072696d697469766520287365742d74756e696e672d636f6e74657874202874756e696e672d636f6e746578742d73657474696e67732022636d6e2d31322220227465742d31322220287265666572656e63652d70697463682028636d6e2061203020342920237830303030303030303030663037623430292028736d75666c2d76657273696f6e2d726571756972656d656e742028736d75666c2d76657273696f6e2031203430292028736d75666c2d76657273696f6e20312034302929202829292929290a textproj.document accept - set_tuning_context 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830353035303530353035303530353035303530353035303530353035303530352028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303037202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203730302030202378303030303030303030303030303030313030303030303030303030303030303729202863617573616c2028292028292920282920287072696d697469766520287365742d74756e696e672d636f6e74657874202874756e696e672d636f6e746578742d73657474696e67732022636d6e2d31322220227465742d31322220287265666572656e63652d70697463682028636d6e2061203020342920237830303030303030303030663037623430292028736d75666c2d76657273696f6e2d726571756972656d656e742028736d75666c2d76657273696f6e2031203430292028736d75666c2d76657273696f6e20312034302929202829292929290a
textproj.document accept - lineage_custom_profile 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830323032303230323032303230323032303230323032303230323032303230322028736368656d612030203129290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a textproj.document accept - lineage_custom_profile 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830323032303230323032303230323032303230323032303230323032303230322028736368656d612030203129290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a
textproj.document accept - extension_base_two_envelopes 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a textproj.document accept - extension_base_two_envelopes 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a
textproj.document accept - rich_document 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830343034303430343034303430343034303430343034303430343034303430342028736368656d612030203129290a286c696e656167652023783134313431343134313431343134313431343134313431343134313431343134290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a28657874656e73696f6e202378303230323032303230323032303230323032303230323032303230323032303220283120302032292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830332929202378303220237830323033290a2863616e6f6e6963616c2d62617365202378303430343034303430343034303430343034303430343034303430343034303420237830313032303420312066756c6c2028736368656d61203020312920237861303034290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303034202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203430302030202378303030303030303030303030303030313030303030303030303030303030303429202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030342929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303035202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203530302030202378303030303030303030303030303030313030303030303030303030303030303529202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030352929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303036202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203630302030202378303030303030303030303030303030313030303030303030303030303030303629202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030362929290a textproj.document accept - rich_document 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830343034303430343034303430343034303430343034303430343034303430342028736368656d612030203129290a286c696e656167652023783134313431343134313431343134313431343134313431343134313431343134290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a28657874656e73696f6e202378303230323032303230323032303230323032303230323032303230323032303220283120302032292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830332929202378303220237830323033290a2863616e6f6e6963616c2d62617365202378303430343034303430343034303430343034303430343034303430343034303420237830313032303420312066756c6c2028736368656d61203020312920237861303034290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303034202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203430302030202378303030303030303030303030303030313030303030303030303030303030303429202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030342929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303035202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203530302030202378303030303030303030303030303030313030303030303030303030303030303529202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030352929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303036202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203630302030202378303030303030303030303030303030313030303030303030303030303030303629202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030362929290a
textproj.document reject wrong-header-version superseded_companion_version 28746578742d70726f6a656374696f6e202830203130203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a textproj.document accept - create_staff_group 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830363036303630363036303630363036303630363036303630363036303630362028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303038202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203830302030202378303030303030303030303030303030313030303030303030303030303030303829202863617573616c2028292028292920282920287072696d697469766520286372656174652d73746166662d67726f7570202873746166662d67726f757020237830303030303030303030303030303031303030303030303030303030303030312028736f6d65202273746166662d67726f75702d312229206772616e642d737461666620282378303030303030303030303030303030313030303030303030303030303030303129292929290a
textproj.document reject blob-line unreferenced_blob 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28626c6f6220226170706c69636174696f6e2f6f637465742d73747265616d222028292023783031290a textproj.document accept - create_part_definition 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830373037303730373037303730373037303730373037303730373037303730372028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303039202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203930302030202378303030303030303030303030303030313030303030303030303030303030303929202863617573616c2028292028292920282920287072696d697469766520286372656174652d706172742d646566696e6974696f6e2028706172742d646566696e6974696f6e20237830303030303030303030303030303031303030303030303030303030303030312022706172742d312220282378303030303030303030303030303030313030303030303030303030303030303129292929290a
textproj.document reject out-of-order-sections canonical_base_before_extension 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a textproj.document accept - create_analysis_layer 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830383038303830383038303830383038303830383038303830383038303830382028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303061202378303030303030303030303030303030303030303030303030303030303030616220287374616d7020313030302030202378303030303030303030303030303030313030303030303030303030303030306129202863617573616c2028292028292920282920287072696d697469766520286372656174652d616e616c797369732d6c617965722028616e616c797369732d6c61796572202378303030303030303030303030303030313030303030303030303030303030303120226c617965722d3122292929290a
textproj.document reject repeated-singular-section lineage_repeated 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830323032303230323032303230323032303230323032303230323032303230322028736368656d612030203129290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a textproj.document accept - create_view 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830393039303930393039303930393039303930393039303930393039303930392028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303062202378303030303030303030303030303030303030303030303030303030303030616220287374616d7020313130302030202378303030303030303030303030303030313030303030303030303030303030306229202863617573616c2028292028292920282920287072696d697469766520286372656174652d766965772028766965772d646566696e6974696f6e20237830303030303030303030303030303031303030303030303030303030303030312022766965772d312220282378303030303030303030303030303030313030303030303030303030303030303129292929290a
textproj.document reject operation-envelope-order envelopes_reversed 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a textproj.document reject wrong-header-version superseded_companion_version 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a
textproj.document reject profile-declaration-order profiles_reversed 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830323032303230323032303230323032303230323032303230323032303230322028736368656d612030203129290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a textproj.document reject blob-line unreferenced_blob 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28626c6f6220226170706c69636174696f6e2f6f637465742d73747265616d222028292023783031290a
textproj.document reject extension-declaration-order extensions_reversed 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830343034303430343034303430343034303430343034303430343034303430342028736368656d612030203129290a286c696e656167652023783134313431343134313431343134313431343134313431343134313431343134290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303230323032303230323032303230323032303230323032303230323032303220283120302032292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830332929202378303220237830323033290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303430343034303430343034303430343034303430343034303430343034303420237830313032303420312066756c6c2028736368656d61203020312920237861303034290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303034202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203430302030202378303030303030303030303030303030313030303030303030303030303030303429202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030342929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303035202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203530302030202378303030303030303030303030303030313030303030303030303030303030303529202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030352929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303036202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203630302030202378303030303030303030303030303030313030303030303030303030303030303629202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030362929290a textproj.document reject out-of-order-sections canonical_base_before_extension 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a
textproj.document reject extension-chunk-order extension_chunks_reversed 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a textproj.document reject repeated-singular-section lineage_repeated 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830323032303230323032303230323032303230323032303230323032303230322028736368656d612030203129290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a
textproj.document reject missing-trailing-lf final_lf_missing 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e20312028292074727565292929 textproj.document reject operation-envelope-order envelopes_reversed 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a
textproj.document reject profile-declaration-order profiles_reversed 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830323032303230323032303230323032303230323032303230323032303230322028736368656d612030203129290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a
textproj.document reject extension-declaration-order extensions_reversed 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830343034303430343034303430343034303430343034303430343034303430342028736368656d612030203129290a286c696e656167652023783134313431343134313431343134313431343134313431343134313431343134290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303230323032303230323032303230323032303230323032303230323032303220283120302032292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830332929202378303220237830323033290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303430343034303430343034303430343034303430343034303430343034303420237830313032303420312066756c6c2028736368656d61203020312920237861303034290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303034202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203430302030202378303030303030303030303030303030313030303030303030303030303030303429202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030342929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303035202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203530302030202378303030303030303030303030303030313030303030303030303030303030303529202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030352929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303036202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203630302030202378303030303030303030303030303030313030303030303030303030303030303629202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030362929290a
textproj.document reject extension-chunk-order extension_chunks_reversed 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a
textproj.document reject missing-trailing-lf final_lf_missing 28746578742d70726f6a656374696f6e202830203132203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e20312028292074727565292929