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
settings/creates that drags `OperationEnvelopeBlock`'s accept-set from 2 to 3
(`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
// reachable per-value, exactly as `ScoreTuningContext` above is.
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)]

View File

@ -816,6 +816,12 @@ pub struct Staff {
pub abbreviation: Option<String>,
pub instrument: InstrumentId,
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>,
/// Default clef for new instances of this staff (schema major 2,
/// appended last per the wire rule; migration default treble).
@ -1611,6 +1617,13 @@ pub struct StaffGroup {
pub id: StaffGroupId,
pub name: Option<String>,
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>,
}
@ -2066,3 +2079,82 @@ mod tests {
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
/// structures (incl. anchor targets, annotation layers, tuplet parents,
/// 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,
/// 11. Identifiers are unique within their kind (every id kind), with
/// reserved-namespace (`SYSTEM_DERIVED`) misuse, tombstone/live
@ -4074,3 +4082,60 @@ mod accidental_compatibility_tests {
.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()),
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) => {
let mut objects = vec![(TypedObjectId::Region(op.region), ctx(Some(op.region), None))];
if let Some(signature) = &op.time_signature {

View File

@ -1153,28 +1153,30 @@ mod tests {
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`
// 30, genesis G1's `CreateInstrument` 31, genesis G2a's
// `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
// until genesis G2a, and 34 until genesis G2b — each time, by then,
// the number had become a real kind, so the test was pinning a bug: a
// barrier that prohibited the new operation encoded fine and would
// not read back. It must be bumped by every tranche that appends a
// tag, and it is deliberately a literal rather than
// `PAYLOAD_FREE.len()` so the bump is a conscious act.
// until genesis G2a, 34 until genesis G2b, and 35 until genesis G3a —
// each time, by then, the number had become a real kind, so the test
// was pinning a bug: a barrier that prohibited the new operation
// encoded fine and would not read back. It must be bumped by every
// tranche that appends a tag, and it is deliberately a literal rather
// than `PAYLOAD_FREE.len()` so the bump is a conscious act.
let mut bytes = vec![0u8];
bytes.extend(set_blob(&[]));
bytes.extend(set_blob(&[vec![35u8]]));
bytes.extend(set_blob(&[vec![39u8]]));
bytes.push(0);
assert_eq!(
EditBarrier::decode_canonical_bytes(&bytes),
Err(BarrierDecodeError::InvalidTag {
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`
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.
## 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 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::{
Beam, Event, IdentifiedPitch, Pitch, Region, RepeatStructure, Rest, Slur, Spanner, Tie,
};
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 crate::causal::CausalContext;
@ -599,6 +600,18 @@ fn operation_kind(r: &mut Reader<'_>) -> Result<OperationKind> {
34 => OperationKind::SetTuningContext(SetTuningContextOp {
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 => {
return Err(EnvelopeDecodeError::InvalidTag {
kind: "OperationKind",
@ -903,6 +916,38 @@ pub(crate) mod tests {
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.
use epiphany_core::{
EventId, MusicalDuration, MusicalPosition, OperationId, PitchId, RationalTime, RegionId,
RepeatStructureId, ReplicaId, SlurId, StaffId, StaffInstanceId, TranspositionInterval,
TypedObjectId, VoiceId,
AnalysisLayerId, EventId, MusicalDuration, MusicalPosition, OperationId, PartDefinitionId,
PitchId, RationalTime, RegionId, RepeatStructureId, ReplicaId, SlurId, StaffGroupId, StaffId,
StaffInstanceId, TranspositionInterval, TypedObjectId, ViewId, VoiceId,
};
use epiphany_determinism::fuzz::SplitMix64;
@ -32,8 +32,9 @@ use crate::envelope::OperationEnvelope;
use crate::opset::OperationSet;
use crate::payload::OperationKindTag;
use crate::payload::{
CreateCrossCuttingOp, CreateInstrumentOp, CreateRegionOp, CreateRepeatStructureOp,
CreateStaffInstanceOp, CreateStaffOp, CreateVoiceOp, CrossCuttingValue, DeleteCrossCuttingOp,
CreateAnalysisLayerOp, CreateCrossCuttingOp, CreateInstrumentOp, CreatePartDefinitionOp,
CreateRegionOp, CreateRepeatStructureOp, CreateStaffGroupOp, CreateStaffInstanceOp,
CreateStaffOp, CreateViewOp, CreateVoiceOp, CrossCuttingValue, DeleteCrossCuttingOp,
DeleteEventOp, DeleteIdentifiedPitchOp, DeleteRegionOp, DeleteRepeatStructureOp,
DeleteStaffInstanceOp, DeleteVoiceOp, InsertEventOp, InsertIdentifiedPitchOp,
ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp, OperationKind, OperationPayload,
@ -90,7 +91,7 @@ fn pitch(n: u64) -> PitchId {
/// Generates a random payload over the shared id space.
fn gen_payload(rng: &mut SplitMix64) -> OperationPayload {
let kind = match rng.below(32) {
let kind = match rng.below(36) {
0 => {
let voice = VoiceId::new(ReplicaId(7), rng.below(3));
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 {
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 {
staff_instance: StaffInstanceId::new(ReplicaId(7), rng.below(3)),
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 opset::{AcceptOutcome, OperationSet};
pub use payload::{
operation_block_introduced_minor, ChangeRegionTimeModelOp, CreateCrossCuttingOp,
CreateInstrumentOp, CreateRegionOp, CreateRepeatStructureOp, CreateStaffInstanceOp,
CreateStaffOp, CreateVoiceOp, CrossCuttingValue, DeleteCrossCuttingOp, DeleteEventOp,
operation_block_introduced_minor, ChangeRegionTimeModelOp, CreateAnalysisLayerOp,
CreateCrossCuttingOp, CreateInstrumentOp, CreatePartDefinitionOp, CreateRegionOp,
CreateRepeatStructureOp, CreateStaffGroupOp, CreateStaffInstanceOp, CreateStaffOp,
CreateViewOp, CreateVoiceOp, CrossCuttingValue, DeleteCrossCuttingOp, DeleteEventOp,
DeleteIdentifiedPitchOp, DeleteRegionOp, DeleteRepeatStructureOp, DeleteStaffInstanceOp,
DeleteVoiceOp, InsertEventOp, InsertIdentifiedPitchOp, ModifyCrossCuttingOp, ModifyEventOp,
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.
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).
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.
use epiphany_core::{
Beam, CanonicalValue, CanvasLayoutDefaults, Event, EventDuration, EventId, EventPosition,
IdentifiedPitch, Instrument, InstrumentId, MetricGrid, MusicalDuration, MusicalPosition,
OperationId, Pitch, PitchId, PitchSpelling, Region, RegionId, RegionTimeModel, RepeatStructure,
RepeatStructureId, Rest, ScoreMetadata, Slur, Spanner, SpellingPrecedence, Staff, StaffId,
StaffInstance, StaffInstanceId, StaffLineConfiguration, TempoSegment, Tie, TimeAnchor,
AnalysisLayer, AnalysisLayerId, Beam, CanonicalValue, CanvasLayoutDefaults, Event,
EventDuration, EventId, EventPosition, IdentifiedPitch, Instrument, InstrumentId, MetricGrid,
MusicalDuration, MusicalPosition, OperationId, PartDefinition, PartDefinitionId, Pitch,
PitchId, PitchSpelling, Region, RegionId, RegionTimeModel, RepeatStructure, RepeatStructureId,
Rest, ScoreMetadata, Slur, Spanner, SpellingPrecedence, Staff, StaffGroup, StaffGroupId,
StaffId, StaffInstance, StaffInstanceId, StaffLineConfiguration, TempoSegment, Tie, TimeAnchor,
TimeSignature, TransactionId, TranspositionInterval, TuningContextSettings, TupletId,
TypedObjectId, Voice, VoiceId,
TypedObjectId, ViewDefinition, ViewId, Voice, VoiceId,
};
use epiphany_determinism::{
sorted_canonical, CanonicalDecode, CanonicalEncode, CanonicalSet, DecodeError,
@ -273,6 +274,26 @@ pub enum OperationKind {
/// `ScoreTuningContext` — `accidental_extensions` is not on the wire and
/// is left untouched by reduction (contract §1).
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 {
@ -388,6 +409,12 @@ impl OperationKind {
// Genesis tranche G2b; appended past 33. Coincides with tag 34 by
// the same accident as G1/G2a, not by rule.
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
// `spec/PLAN_GMINOR_SCHEMA_MINOR.md` §4.
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::SetSpellingPrecedence(_) => OperationKindTag::SetSpellingPrecedence,
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::SetSpellingPrecedence(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,
/// Genesis tranche G2b.
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
@ -712,6 +765,10 @@ operation_kind_tag_vocabulary! {
SetCanvasLayoutDefaults = 32 => "set-canvas-layout-defaults" @ Some(9),
SetSpellingPrecedence = 33 => "set-spelling-precedence" @ Some(9),
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 {
@ -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
/// resolved musical position in a region's default metric grid
/// (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
// here is an epoch this test cannot see go wrong.
(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!(
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 crate::payload::{
ChangeRegionTimeModelOp, CreateCrossCuttingOp, CreateInstrumentOp, CreateRegionOp,
CreateRepeatStructureOp, CreateStaffInstanceOp, CreateStaffOp, CreateVoiceOp,
DeleteCrossCuttingOp, DeleteEventOp, DeleteIdentifiedPitchOp, DeleteRegionOp,
DeleteRepeatStructureOp, DeleteStaffInstanceOp, DeleteVoiceOp, InsertEventOp,
InsertIdentifiedPitchOp, ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp,
OperationKind, OperationKindTag, RespellPitchOp, SetCanvasLayoutDefaultsOp, SetMetadataOp,
SetMetricGridOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp,
SetTimeSignatureOp, SetTuningContextOp, SetUserPageBreakOp, SetUserSystemBreakOp,
TransactionDescriptor, TransposeIntervalOp, TransposeOp,
ChangeRegionTimeModelOp, CreateAnalysisLayerOp, CreateCrossCuttingOp, CreateInstrumentOp,
CreatePartDefinitionOp, CreateRegionOp, CreateRepeatStructureOp, CreateStaffGroupOp,
CreateStaffInstanceOp, CreateStaffOp, CreateViewOp, CreateVoiceOp, DeleteCrossCuttingOp,
DeleteEventOp, DeleteIdentifiedPitchOp, DeleteRegionOp, DeleteRepeatStructureOp,
DeleteStaffInstanceOp, DeleteVoiceOp, InsertEventOp, InsertIdentifiedPitchOp,
ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp, OperationKind, OperationKindTag,
RespellPitchOp, SetCanvasLayoutDefaultsOp, SetMetadataOp, SetMetricGridOp,
SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp, SetTimeSignatureOp,
SetTuningContextOp, SetUserPageBreakOp, SetUserSystemBreakOp, TransactionDescriptor,
TransposeIntervalOp, TransposeOp,
};
use crate::support::OperationKindRegistryId;
@ -232,6 +233,14 @@ impl TextValue for OperationKind {
OperationKind::SetTuningContext(op) => {
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)?,
})
}
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]
fn every_operation_kind_round_trips_with_canonical_text() {
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 {
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
// every other v1-native kind above.
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

View File

@ -16,14 +16,15 @@ use std::collections::BTreeMap;
use epiphany_core::{
AcousticPitch, AcousticRealization, AleatoricAnchoringDiscipline, AleatoricTimeModel,
AnchorOffset, Beam, BeamId, CmnNominal, Event, EventId, EventOrderingDAG, EventPosition,
IdentifiedPitch, MetricTimeModel, MusicalDuration, MusicalPosition, Pitch, PitchId,
PitchSpaceId, PitchSpacePosition, PitchSpelling, PitchedEvent, ProportionalTimeModel, Region,
RegionContent, RegionEdge, RegionId, RegionTimeModel, RepeatKind, RepeatStructure,
RepeatStructureId, Rest, ScalePosition, Slur, SlurId, SpellingAttachment, SpellingDirective,
SpellingScope, SpellingSource, StaffBasedContent, StaffExtent, StaffId, StaffInstance,
StaffInstanceId, StemConfiguration, Tie, TieClass, TieId, TimeAnchor, TimeExtent, Voice,
VoiceId, VoiceOrigin, Volta, WallClockDuration, WallClockTime,
AnalysisLayerId, AnchorOffset, Beam, BeamId, CmnNominal, Event, EventId, EventOrderingDAG,
EventPosition, IdentifiedPitch, MetricTimeModel, MusicalDuration, MusicalPosition,
PartDefinitionId, Pitch, PitchId, PitchSpaceId, PitchSpacePosition, PitchSpelling,
PitchedEvent, ProportionalTimeModel, Region, RegionContent, RegionEdge, RegionId,
RegionTimeModel, RepeatKind, RepeatStructure, RepeatStructureId, Rest, ScalePosition, Slur,
SlurId, SpellingAttachment, SpellingDirective, SpellingScope, SpellingSource,
StaffBasedContent, StaffExtent, StaffGroupId, StaffId, StaffInstance, StaffInstanceId,
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
@ -368,6 +369,61 @@ pub fn instrument(id: epiphany_core::InstrumentId) -> epiphany_core::Instrument
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
/// G2a) — distinct `nth` give distinct `CanvasLayoutDefaults` values so a
/// 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
//! 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 crate::{
@ -411,6 +414,156 @@ pub fn decode_vectors() -> Vec<DecodeVector> {
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
}
@ -622,4 +775,128 @@ mod tests {
"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::{
AnomalousReplicaSegment, AuthorId, CausalContext, ChangeRegionTimeModelOp, ConflictId,
ConflictKind, ConflictKindRegistryId, ConflictRecord, ConflictRegistry,
ConflictResolutionState, CreateCrossCuttingOp, CreateInstrumentOp, CreateRegionOp,
CreateRepeatStructureOp, CreateStaffInstanceOp, CreateStaffOp, CreateVoiceOp,
CrossCuttingValue, DeleteCrossCuttingOp, DeleteEventOp, DeleteIdentifiedPitchOp,
DeleteRegionOp, DeleteRepeatStructureOp, DeleteStaffInstanceOp, DeleteVoiceOp,
ExtensionPreconditionId, FieldPath, HybridLogicalClock, InsertEventOp, InsertIdentifiedPitchOp,
IntegrityAnomaly, IntegrityAnomalyKind, IntegrityAnomalyRegistryId, MaterializedState,
ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp, NoOpReason, ObjectKind,
ObjectState, OperationEffect, OperationEnvelope, OperationKind, OperationKindRegistryId,
OperationPayload, OperationSet, OperationStamp, PendingReason, PositionRemapping,
PreconditionFailureReason, PreconditionFailureRegistryId, ReanchorReason,
ReanchorReasonRegistryId, ReanchorResult, RepairKind, RepairKindRegistryId, RepairRecord,
ReplicaAnomalyReason, ReplicaAnomalyRegistryId, ResolutionAction, ResolutionRegistryId,
ResolveConflictPayload, RespellPitchOp, SerializedCanonicalInputs, SetCanvasLayoutDefaultsOp,
SetMetadataOp, SetMetricGridOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp,
SetTimeSignatureOp, SetTuningContextOp, SetUserPageBreakOp, SetUserSystemBreakOp,
TransactionCategory, TransactionDescriptor, TransposeIntervalOp, TransposeOp,
TupletCompensation, TupletCompensationKind, UndoPolicy, UndoTransactionPayload,
ConflictResolutionState, CreateAnalysisLayerOp, CreateCrossCuttingOp, CreateInstrumentOp,
CreatePartDefinitionOp, CreateRegionOp, CreateRepeatStructureOp, CreateStaffGroupOp,
CreateStaffInstanceOp, CreateStaffOp, CreateViewOp, CreateVoiceOp, CrossCuttingValue,
DeleteCrossCuttingOp, DeleteEventOp, DeleteIdentifiedPitchOp, DeleteRegionOp,
DeleteRepeatStructureOp, DeleteStaffInstanceOp, DeleteVoiceOp, ExtensionPreconditionId,
FieldPath, HybridLogicalClock, InsertEventOp, InsertIdentifiedPitchOp, IntegrityAnomaly,
IntegrityAnomalyKind, IntegrityAnomalyRegistryId, MaterializedState, ModifyCrossCuttingOp,
ModifyEventOp, ModifyIdentifiedPitchOp, NoOpReason, ObjectKind, ObjectState, OperationEffect,
OperationEnvelope, OperationKind, OperationKindRegistryId, OperationPayload, OperationSet,
OperationStamp, PendingReason, PositionRemapping, PreconditionFailureReason,
PreconditionFailureRegistryId, ReanchorReason, ReanchorReasonRegistryId, ReanchorResult,
RepairKind, RepairKindRegistryId, RepairRecord, ReplicaAnomalyReason, ReplicaAnomalyRegistryId,
ResolutionAction, ResolutionRegistryId, ResolveConflictPayload, RespellPitchOp,
SerializedCanonicalInputs, SetCanvasLayoutDefaultsOp, SetMetadataOp, SetMetricGridOp,
SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp, SetTimeSignatureOp,
SetTuningContextOp, SetUserPageBreakOp, SetUserSystemBreakOp, TransactionCategory,
TransactionDescriptor, TransposeIntervalOp, TransposeOp, TupletCompensation,
TupletCompensationKind, UndoPolicy, UndoTransactionPayload,
};
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 => {
let pitches = if rng.boolean() {
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 {
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(
OperationKindRegistryId(rng.next_u64() as u128),
rng.byte_vec(0, 16),
@ -1905,7 +1929,7 @@ mod tests {
/// Push-4a debt) and `CreateInstrument` (kind 31, G1 debt) went missing
/// from every corpus this generator feeds despite every downstream suite
/// 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.
#[test]
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_canvas_layout_defaults, mut saw_spelling_precedence) = (false, 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 {
let OperationPayload::Primitive(kind) = operation_payload(&mut rng, 8, 8) else {
continue;
@ -1923,6 +1949,10 @@ mod tests {
OperationKind::SetCanvasLayoutDefaults(_) => saw_canvas_layout_defaults = true,
OperationKind::SetSpellingPrecedence(_) => saw_spelling_precedence = 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,
"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]

View File

@ -1372,7 +1372,7 @@ mod tests {
/// (s10, row 29) `gen_operation_kind_tag`'s draw must cover exactly
/// `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
/// variant `PAYLOAD_FREE` excludes by design, `payload.rs:469`) were
/// 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
// 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
// `SetCanvasLayoutDefaults` and `SetSpellingPrecedence`; genesis G2b takes
// it from 34 to 35 by adding `SetTuningContext`). It stays a literal on
// `SetCanvasLayoutDefaults` and `SetSpellingPrecedence`; genesis G2b took
// 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
// vacuous, since that is the very list it exists to pin.
assert_eq!(
expected.len(),
35,
"34 payload-free kinds plus `Registered`"
39,
"38 payload-free kinds plus `Registered`"
);
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
/// and G2a: extending the grammar without moving this constant would leave
/// 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.
///

View File

@ -650,11 +650,11 @@ mod tests {
// 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
// G2b). Kept a literal because `projection` takes `&[&str]` and a
// formatted String would ripple through every call site;
// `the_test_header_tracks_the_implemented_version` below fails loudly if
// the two ever drift.
const HEADER: &str = "(text-projection (0 11 0))";
// G2b; 0.11.0 → 0.12.0, genesis G3a). Kept a literal because `projection`
// takes `&[&str]` and a formatted String would ripple through every call
// site; `the_test_header_tracks_the_implemented_version` below fails
// loudly if the two ever drift.
const HEADER: &str = "(text-projection (0 12 0))";
const DOCUMENT: &str = "(document #x00000000000000000000000000000001 (schema 0 1))";
/// A minimal but complete valid projection: just the two mandatory lines.

View File

@ -21,9 +21,13 @@ use epiphany_bundle::{
ProfileConstraints, ProfileDeclaration, ProfileId, ProfileRegistryId,
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::{
AuthorId, CausalContext, DeleteRegionOp, HybridLogicalClock, OperationEnvelope, OperationKind,
AuthorId, CausalContext, CreateAnalysisLayerOp, CreatePartDefinitionOp, CreateStaffGroupOp,
CreateViewOp, DeleteRegionOp, HybridLogicalClock, OperationEnvelope, OperationKind,
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> {
let mut profiles = vec![ProfileDeclaration::full()];
if custom {
@ -291,6 +372,50 @@ fn accept_documents() -> Vec<(&'static str, String)> {
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![
("minimal", project_text_document(&minimal)),
("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),
),
("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();
// 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 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
// migrate-on-read posture (`req:textproj:header-version`).
let wrong_version = replace_once(
minimal,
"(text-projection (0 12 0))",
"(text-projection (0 11 0))",
"(text-projection (0 10 0))",
);
vectors.push((
SURFACE,
@ -716,7 +851,7 @@ mod tests {
#[test]
fn the_reference_implementation_agrees_with_every_vector() {
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!(
"{} disagreement(s):\n{}",
failures.len(),
@ -754,4 +889,61 @@ mod tests {
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
which questions must be answered before a dispatch contract can be written.
**Status:** the ladder **G1 → G2a → G-minor → G2b** is **complete**; only **G3**
remains, and it **splits into G3a and G3b** (ratified 2026-07-29, §4).
**Status:** the ladder **G1 → G2a → G-minor → G2b → G3a** is **complete**;
only **G3b** remains (ratified 2026-07-29, §4).
* **G1 landed** (3b09595) — `CreateInstrument`, kind/tag 31.
* **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
trap 7's holdout, resolved in the contract as *subset over normalization*.
Closed **P13-S13**.
* **G3a** — the four root-level mint families (`CreateStaffGroup`,
`CreatePartDefinition`, `CreateAnalysisLayer`, `CreateView`), kinds/tags
**3538**, epoch **11**, all schema major **0**. Contracted
(`spec/CONTRACT_GENESIS_G3A_ENTITIES.md`) and **ready to dispatch**; §1.1's
* **G3a landed** (commit pending) — the four root-level mint families
(`CreateStaffGroup`, `CreatePartDefinition`, `CreateAnalysisLayer`,
`CreateView`), kinds/tags **3538**, epoch **11**, all schema major **0**.
Executed against `spec/CONTRACT_GENESIS_G3A_ENTITIES.md`; §1.1's
`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
graph invariant **20** and a new `PreconditionFailureReason` at discriminant
**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 |
| 9 | Genesis G2a | `OperationKind`/`OperationKindTag` 3233 |
| 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
> 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
> 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
`AUDIT_GMINOR_VOCABULARIES.md` appears exactly once: all ten kind/tag pairs,
`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\itshape\color{epiphanyslate}A companion to the Core Specification}\\[14pt]
{\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}
\vfill
\end{titlepage}
@ -1462,6 +1462,18 @@ and the reader disagree about the field's type.
\texttt{ScoreTuningContext} layout (Section~\ref{sec:evolution:major3});
born at v3 unconditionally &
\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
\end{longtable}
\endgroup
@ -1532,7 +1544,9 @@ discriminants and wrong lengths are decode errors. Append-only past
\tablenums{28} & \texttt{CreateRepeatStructure} & \tablenums{29} & \texttt{DeleteRepeatStructure} \\
\tablenums{30} & \texttt{TransposeInterval} & \tablenums{31} & \texttt{CreateInstrument} \\
\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
\end{longtable}
\endgroup
@ -2382,7 +2396,7 @@ The \emph{only} minor-additive mechanism in schema major~0 is
\textbf{appending discriminants to open vocabularies}:
\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
tranche took \tablenums{24}--\tablenums{27} under this mechanism,
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{CreateInstrument}), genesis tranche G2a took
\tablenums{32}/\tablenums{33} (\texttt{SetCanvasLayoutDefaults},
\texttt{SetSpellingPrecedence}), and genesis tranche G2b took
\tablenums{34} (\texttt{SetTuningContext}) --- the discriminant space is
\texttt{SetSpellingPrecedence}), genesis tranche G2b took
\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}
follows minimal stamping over its payload: \tablenums{28}'s payload
embeds a v2 layout, so its blocks stamp major~2,
Section~\ref{sec:evolution:major2}; \tablenums{34}'s payload embeds a v3
layout unconditionally, so its blocks stamp major~3,
Section~\ref{sec:evolution:major3} --- the sole appended kind to do so);
\item \texttt{OperationKindTag}: append at ${\geq}\,\tablenums{35}$
(Requirement~\ref{req:binfmt:kind-tag}; the same eleven variants as
\texttt{OperationKind}, at the same eleven discriminants, appended by
the same six tranches);
Section~\ref{sec:evolution:major3} --- the sole appended kind to do so;
\tablenums{35}--\tablenums{38} are each major~0, no versioned walk
existing for any of their four carried types);
\item \texttt{OperationKindTag}: append at ${\geq}\,\tablenums{39}$
(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}$
(Section~\ref{sec:ops:payload}; \texttt{ResolveEquivocation} = 3, Push~3,
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
correction to prose and a new writer-side derivation, not a new appended
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
\end{longtable}

Binary file not shown.

View File

@ -4232,6 +4232,13 @@ pub struct StaffGroup {
pub id: StaffGroupId,
pub name: Option<String>,
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>,
}
@ -5576,7 +5583,12 @@ pub struct Staff {
pub default_staff_lines: StaffLineConfiguration,
/// 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>,
}
@ -6969,6 +6981,16 @@ pub enum OperationKind {
// on the wire and is left untouched by reduction).
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
SetUserSystemBreak(SetUserSystemBreakOp),
SetUserPageBreak(SetUserPageBreakOp),
@ -11938,6 +11960,12 @@ pub enum OperationKindTag {
SetSpellingPrecedence,
// Genesis tranche G2b: name-verbatim, as the two prior additions are.
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 {

Binary file not shown.

View File

@ -231,7 +231,7 @@
{\Large\scshape\color{epiphanyslate}Operation Catalog}\\[6pt]
{\large\itshape\color{epiphanyslate}A companion to the Core Specification}\\[14pt]
{\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}
\vfill
\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
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}
\label{ch:framework}
@ -1137,6 +1196,21 @@ With staves mintable, \texttt{CreateStaffInstance}
instance's referenced \texttt{Staff} is live (previously the reference was
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
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
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}
\label{sec:k0:repeat-structures}

Binary file not shown.

View File

@ -234,7 +234,7 @@
{\Large\scshape\color{epiphanyslate}Text Projection}\\[6pt]
{\large\itshape\color{epiphanyslate}A companion to the Core Specification}\\[14pt]
{\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}
\vfill
\end{titlepage}
@ -483,7 +483,7 @@ A projection is, in order:
\begin{requirement}
\label{req:textproj:header-version}
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.
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
unreferenced by canonical state
(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,
and a parser \MUST{} reject every \texttt{(blob ...)} line.
\end{requirement}
@ -1062,6 +1062,10 @@ kind ::= "(insert-event " bytes " " value ")"
| "(set-canvas-layout-defaults " value ")"
| "(set-spelling-precedence " 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 ")"
| "(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:
\begin{lstlisting}
(text-projection (0 11 0))
(text-projection (0 12 0))
(document #x05050505050505050505050505050505 (schema 0 1))
(profile full (0 1 0) (constraints 67108864 (retention 1 () true)))
(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
grammars both claiming \texttt{(0 10 0)}. Cached projections at
\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. \\
\bottomrule
\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_33 21
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 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 truncated tag_empty -
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 accept - set_tuning_context 00000000000000010000000000000004000000000000000000000000000000000100000000000000010000000000000000000001000000000000000400000000000000000000223000000006000000636d6e2d3132060000007465742d313200050004080000000000000000907b40010028000100280000000000
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 accept - empty_manifest 6f9e7d11689ab113c4a1f05faf60fe60050505050505050505050505050505050000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000001000000000000000000000400000000010000000001000000000000

View File

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