Genesis G2a: two settings setters, and the vocabulary's documentation catches up
SetCanvasLayoutDefaults and SetSpellingPrecedence, kinds and tags 32/33, on the
SetMetadata LWW pattern: advisory last-writer-wins, no conflict, no idempotence
short-circuit, seeded from the base so a value-restoring undo of the first
operational write reaches the pre-operational value. Both carried types already
had Codec impls, so the packet designs no wire layout -- canonical_value!
delegation and one push_lp_bytes each, inheriting strict canonical-form
rejection rather than writing it.
Both stamp schema major 0 unconditionally, staying in the catch-all arm. The
op-block accept-set is untouched at 2; epiphany-bundle has an empty diff. The
raise to 3 belongs to G2b, and the chunk schema minor -- a MUST no writer has
ever honoured -- belongs to G-minor, filed as P13-S14 and deliberately not
fixed here.
Most of this commit is documentation the vocabulary had outgrown. G1 shipped
five normative falsehoods because its contract declared the wire surfaces out
of scope, and Push 4a left TransposeInterval out of both of core_spec's
normative listings. So binary_format's payload-layout and tag tables now reach
33 rather than 30, its snapshot-only bullet records that it is empty and why,
two spelled-out payload counts move from eight to nine, and core_spec's
listings gain all four missing kinds. The Pass-12 K8 doctrine is narrowed
rather than reversed: the root and canvas remain structural givens no operation
mints, and only the claim that the score's contents arrive outside the
operation set is superseded.
Two generators were stale by two tranches and fed corpora other suites treat as
exhaustive. layout_stub's is now derived from PAYLOAD_FREE with an explicit
Registered append instead of a hand-written match, so future built-ins follow
structurally; s10 asserts PAYLOAD_FREE union {Registered} so deleting that
append cannot pass.
Companion 0.8.0 -> 0.9.0, binary format 0.11.0 -> 0.12.0, catalog 0.9.0 ->
0.10.0 (covering G1 retroactively). 102 decode vectors, regenerated.
Coordinator verification: 1371 passed / 0 failed, clippy 0 warnings, fmt clean,
conformance 8/8 and 9/9, requirement_labels 6/6, four PDFs at 0 undefined
references, goldens byte-identical, accept-set confirmed still 2. Mutations
s3/s5/s7/s10 re-run independently and each observed to kill its test.
Two findings beyond the contract. max_supported_major is not reachable outside
epiphany-bundle -- mod bundle is private and the symbol is absent from its
pub use -- so the gate's "assert it in code" was unsatisfiable without touching
a crate the contract forbids; verified by reading the unedited source instead.
And core_spec carries two P12-K8 references, not one; the contract named only
the first, so the second is annotated here for consistency.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QjsEnYhm1gPpf6ii2iFxFV
This commit is contained in:
parent
4a4988ce88
commit
7df5ca17ce
|
|
@ -1421,3 +1421,23 @@ does not exercise `Instrument` directly (the generator corpus does not walk
|
|||
(`epiphany-ops::vectors`) now pins a `CreateInstrument` envelope's literal
|
||||
bytes, which round-trips the same `Instrument` encoding through the op
|
||||
payload's `push_lp_bytes` wrapper — see that crate's own DECISIONS.md entry.
|
||||
|
||||
## Genesis tranche G2a — `CanvasLayoutDefaults` and `SpellingPrecedence` join
|
||||
## `canonical_value!` (2026-07-28)
|
||||
|
||||
`spec/CONTRACT_GENESIS_G2A_SETTINGS.md` adds `SetCanvasLayoutDefaults` and
|
||||
`SetSpellingPrecedence` to `epiphany-ops`, the G2a rung of the genesis ladder
|
||||
(`spec/PLAN_GENESIS_OPS.md` §4). Both payloads embed the full carried value —
|
||||
`CanvasLayoutDefaults` (already `Codec` via `struct_codec!`, `codec.rs:2115`)
|
||||
and `SpellingPrecedence` (already a hand-written `impl Codec`, `codec.rs:1144`)
|
||||
— so this crate's one required change is two more `canonical_value!` lines. No
|
||||
new byte layout, same as G1's `Instrument` entry above.
|
||||
|
||||
Both types are schema major 0 as standalone payloads: `SpellingPrecedence` has
|
||||
never been versioned (the v0/v1/v2 decode walks and the live `Codec` all read
|
||||
it through plain `Codec::dec`), and `CanvasLayoutDefaults`'s versioning lives
|
||||
in the *containing* `Canvas` walk (`dec_canvas_v0` default-fills the field;
|
||||
`enc_canvas_v1` writes it through the live `Codec`), not in the leaf type
|
||||
itself. So neither op gains a `schema_major()` arm — both fall into the
|
||||
existing `_ => 0` catch-all in `epiphany-ops`. This is unlike G1's
|
||||
`CreateInstrument`, whose carried `Instrument` has mandatory major-2 appends.
|
||||
|
|
|
|||
|
|
@ -3535,6 +3535,16 @@ canonical_value! {
|
|||
TuningScope,
|
||||
SmuflVersionRequirement,
|
||||
SmuflVersion,
|
||||
// Genesis tranche G2a (`CONTRACT_GENESIS_G2A_SETTINGS.md`) —
|
||||
// SetCanvasLayoutDefaults and SetSpellingPrecedence embed the full value,
|
||||
// mirroring SetMetadata's `ScoreMetadata`. Both already have a `Codec`
|
||||
// (`struct_codec!` for `CanvasLayoutDefaults` at `:2115`; the hand-written
|
||||
// `impl Codec for SpellingPrecedence` at `:1144`) and already ship inside
|
||||
// `Score`; this makes that existing layout reachable per-value, same as
|
||||
// every other entry here. Neither carries a schema-major-1+ layout of its
|
||||
// own — see the contract's "Why these two" table.
|
||||
CanvasLayoutDefaults,
|
||||
SpellingPrecedence,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
|
|
@ -19,8 +19,9 @@
|
|||
//! event sits in, say) are *not* treated as edited objects; protecting a
|
||||
//! container is what the barrier's **scope** is for, and scope is matched
|
||||
//! against the target's real containment, precisely.
|
||||
//! * **Score-level operations** (`SetMetadata`, the transaction descriptor)
|
||||
//! name no graph object: only a score-wide barrier (empty
|
||||
//! * **Score-level operations** (`SetMetadata`, the transaction descriptor,
|
||||
//! `SetCanvasLayoutDefaults`, `SetSpellingPrecedence`) name no graph object:
|
||||
//! only a score-wide barrier (empty
|
||||
//! `affected_object_kinds`, `WholeScore`/`TuningContext`/`Registered` scope)
|
||||
//! can match them.
|
||||
//! * **Extension-defined operations** (`OperationKind::Registered`) carry a
|
||||
|
|
@ -465,9 +466,10 @@ pub(crate) fn subjects_of(kind: &OperationKind, score: &Score) -> BarrierSubject
|
|||
Some(op.staff_instance),
|
||||
),
|
||||
),
|
||||
OperationKind::SetMetadata(_) | OperationKind::DeclareTransaction(_) => {
|
||||
BarrierSubjects::ScoreWide
|
||||
}
|
||||
OperationKind::SetMetadata(_)
|
||||
| OperationKind::DeclareTransaction(_)
|
||||
| OperationKind::SetCanvasLayoutDefaults(_)
|
||||
| OperationKind::SetSpellingPrecedence(_) => BarrierSubjects::ScoreWide,
|
||||
OperationKind::CreateRepeatStructure(op) => one(
|
||||
TypedObjectId::RepeatStructure(op.repeat_structure_id()),
|
||||
repeat_context(score, &op.repeat),
|
||||
|
|
|
|||
|
|
@ -1100,25 +1100,28 @@ mod tests {
|
|||
tag: 7
|
||||
})
|
||||
);
|
||||
// Operation-kind tag 32 is one past the vocabulary (the Phase-3 ops
|
||||
// Operation-kind tag 34 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; encodings are append-only).
|
||||
// 30, genesis G1's `CreateInstrument` 31, genesis G2a's
|
||||
// `SetCanvasLayoutDefaults` 32 and `SetSpellingPrecedence` 33;
|
||||
// encodings are append-only).
|
||||
//
|
||||
// This assertion named 30 until Push 5 / P4, and 31 until genesis G1 —
|
||||
// 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.
|
||||
// This assertion named 30 until Push 5 / P4, 31 until genesis G1, and
|
||||
// 32 until genesis G2a — 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![32u8]]));
|
||||
bytes.extend(set_blob(&[vec![34u8]]));
|
||||
bytes.push(0);
|
||||
assert_eq!(
|
||||
EditBarrier::decode_canonical_bytes(&bytes),
|
||||
Err(BarrierDecodeError::InvalidTag {
|
||||
kind: "OperationKindTag",
|
||||
tag: 32
|
||||
tag: 34
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1813,3 +1813,78 @@ are green (`epiphany-layout-ir` excepted, for the one stale-vocabulary test
|
|||
above). This is reported to the coordinator rather than worked around; see
|
||||
the packet's final report for the exact reproduction commands and error
|
||||
text.
|
||||
|
||||
## Genesis tranche G2a — `SetCanvasLayoutDefaults` / `SetSpellingPrecedence`,
|
||||
## kind 32/33, tag 32/33 (2026-07-28)
|
||||
|
||||
`spec/CONTRACT_GENESIS_G2A_SETTINGS.md` lands the second rung of the genesis
|
||||
ladder: two more `Score` fields become operation-authored, both on the
|
||||
`SetMetadata` LWW pattern (`reduce.rs`) — advisory last-writer-wins, no
|
||||
conflict, no idempotence short-circuit, seeded from the base for
|
||||
value-restoring undo. Unlike G1's `CreateInstrument`, both new kinds are
|
||||
schema major 0 *unconditionally*: neither carried type (`CanvasLayoutDefaults`,
|
||||
`SpellingPrecedence`) has ever had more than one wire layout as a standalone
|
||||
value, so both fall through `OperationKind::schema_major`'s existing `_ => 0`
|
||||
catch-all with **no new arm** — pin 3's explicit trap (adding them to the
|
||||
`=> 2` arm alongside `SetMetadata` would be the bug, since `SetMetadata`
|
||||
sits there for a property of `ScoreMetadata`, not of the LWW pattern itself).
|
||||
Verified by mutation: temporarily joining the `=> 2` arm kills both
|
||||
`schema_majors_follow_the_minimal_stamping_rule` (`reduce.rs`) and a
|
||||
dedicated `epiphany-testkit` assertion.
|
||||
|
||||
**This packet does not touch `epiphany-bundle`, and the boundary crossing
|
||||
this time is exactly the three sites the contract named** — `barriers.rs`,
|
||||
`layout-ir/src/barrier.rs`, and `text_projection_grammar.rs` — no wider than
|
||||
scoped, unlike G1's discovery that the crossing itself was mis-scoped in the
|
||||
contract. Both new kinds join the existing `SetMetadata(_) |
|
||||
DeclareTransaction(_)` score-wide arm in `barriers.rs::subjects_of` (they are
|
||||
score-level field overwrites with no resolvable region or object, exactly
|
||||
like `SetMetadata`); the layout-ir "one past the vocabulary" literal moves
|
||||
32→34; the testkit grammar kind-count literal moves 32→34.
|
||||
|
||||
**`ops/src/envdecode.rs::sample_kind` and `ops/src/textproj_kind.rs::parse`
|
||||
are both `match` statements exhaustive over `OperationKindTag`**
|
||||
(compile-enforced, unlike `OperationKind::discriminant()`), so both needed a
|
||||
new arm per kind — correctly named by the contract's touch-point table
|
||||
(`envdecode.rs`'s "tag→kind (:819)" is exactly `sample_kind`;
|
||||
`textproj_kind.rs`'s "parse (:443)" is exactly this match), verified against
|
||||
the tree rather than assumed. Both compiled to a hard error the moment the
|
||||
new `OperationKindTag` variants existed without a corresponding arm, so
|
||||
neither site could have been missed silently.
|
||||
|
||||
**Two more hand-maintained generator sites went stale by two tranches, not
|
||||
one**, confirming the contract's row-28/29 framing: `testkit/src/
|
||||
generators.rs::operation_payload`'s `rng.below(30)` bound had never grown
|
||||
past the repeat pair (28/29), so `TransposeInterval` (kind 30, Push-4a debt)
|
||||
and `CreateInstrument` (kind 31, G1 debt) were absent from every corpus this
|
||||
generator feeds, alongside this packet's own new kinds. Widened to
|
||||
`rng.below(34)` with all four appended; `testkit/src/
|
||||
layout_stub.rs::gen_operation_kind_tag` was rewritten to derive its built-in
|
||||
draw from `OperationKindTag::PAYLOAD_FREE` (excluding `Registered`, appended
|
||||
explicitly) rather than extended by hand — the structural fix the contract's
|
||||
blast-radius note asked for, following the in-crate `all_tags()` precedent
|
||||
(`payload.rs`). Five of the six hand-maintained sites the contract's
|
||||
blast-radius note lists remain manual for the next append; only row 29 was
|
||||
convertible to a derivation.
|
||||
|
||||
**Test s7's three-times-wrong framing is now four-times right.** The
|
||||
contract's own text records that two earlier framings of "transaction
|
||||
rollback discards the write, not just the field" could not see their own
|
||||
mutation. The third framing — author inside a failed transaction, write
|
||||
again in a second transaction, undo the second, and assert the restored
|
||||
value is the pre-failure predecessor rather than the rolled-back write —
|
||||
was mutation-verified live: omitting `canvas_layout_defaults_chain` from
|
||||
`Reducer::restore` (keeping it in `snapshot`) makes the test observe the
|
||||
rolled-back transaction's value survive the undo instead of the genuine
|
||||
predecessor. Confirmed to fail for exactly that reason, not incidentally.
|
||||
|
||||
**The canonical-base re-pin (`the_canonical_base_is_byte_identical_across_
|
||||
data_model_majors`) is a corpus shift, not a value leak** — verified by
|
||||
construction, not by re-running and hoping: `MaterializedState` embeds no
|
||||
`Score` field value for any setting, `SetMetadata` included, and both new
|
||||
kinds are schema major 0 unconditionally, so there is no schema-major
|
||||
surface for a leak to appear on even before checking the hash. `gen_payload`
|
||||
(`fuzz.rs`) widened from `rng.below(29)` to `rng.below(31)` with the two new
|
||||
arms appended, reshuffling the seeded RNG stream exactly as at Phase D, Push
|
||||
4a, and G1; the digest moved and was re-pinned with that reasoning recorded
|
||||
in the test's own comment.
|
||||
|
|
|
|||
|
|
@ -36,10 +36,11 @@ use epiphany_core::{
|
|||
};
|
||||
use epiphany_core::{CanonicalValue, TempoSegment};
|
||||
use epiphany_core::{
|
||||
EventId, Instrument, InstrumentId, MetricGrid, MusicalPosition, OperationId, PitchId,
|
||||
PitchSpelling, RegionId, RegionTimeModel, RepeatStructureId, ReplicaId, ScoreMetadata, Staff,
|
||||
StaffInstance, StaffInstanceId, StaffLineConfiguration, TimeAnchor, TimeSignature,
|
||||
TranspositionInterval, TupletId, TypedObjectId, Voice, VoiceId, WallClockTime,
|
||||
CanvasLayoutDefaults, EventId, Instrument, InstrumentId, MetricGrid, MusicalPosition,
|
||||
OperationId, PitchId, PitchSpelling, RegionId, RegionTimeModel, RepeatStructureId, ReplicaId,
|
||||
ScoreMetadata, SpellingPrecedence, Staff, StaffInstance, StaffInstanceId,
|
||||
StaffLineConfiguration, TimeAnchor, TimeSignature, TranspositionInterval, TupletId,
|
||||
TypedObjectId, Voice, VoiceId, WallClockTime,
|
||||
};
|
||||
use epiphany_determinism::{CanonicalDecode, CanonicalEncode};
|
||||
|
||||
|
|
@ -589,6 +590,12 @@ fn operation_kind(r: &mut Reader<'_>) -> Result<OperationKind> {
|
|||
31 => OperationKind::CreateInstrument(CreateInstrumentOp {
|
||||
instrument: value::<Instrument>(r, "Instrument")?,
|
||||
}),
|
||||
32 => OperationKind::SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp {
|
||||
layout_defaults: value::<CanvasLayoutDefaults>(r, "CanvasLayoutDefaults")?,
|
||||
}),
|
||||
33 => OperationKind::SetSpellingPrecedence(SetSpellingPrecedenceOp {
|
||||
precedence: value::<SpellingPrecedence>(r, "SpellingPrecedence")?,
|
||||
}),
|
||||
tag => {
|
||||
return Err(EnvelopeDecodeError::InvalidTag {
|
||||
kind: "OperationKind",
|
||||
|
|
@ -878,6 +885,16 @@ pub(crate) mod tests {
|
|||
instrument: valuegen::instrument(InstrumentId::new(ReplicaId(7), 1)),
|
||||
})
|
||||
}
|
||||
OperationKindTag::SetCanvasLayoutDefaults => {
|
||||
OperationKind::SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp {
|
||||
layout_defaults: valuegen::canvas_layout_defaults(1),
|
||||
})
|
||||
}
|
||||
OperationKindTag::SetSpellingPrecedence => {
|
||||
OperationKind::SetSpellingPrecedence(SetSpellingPrecedenceOp {
|
||||
precedence: valuegen::spelling_precedence(1),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,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(29) {
|
||||
let kind = match rng.below(31) {
|
||||
0 => {
|
||||
let voice = VoiceId::new(ReplicaId(7), rng.below(3));
|
||||
let position = MusicalPosition(RationalTime::from_int(rng.below(4) as i32));
|
||||
|
|
@ -293,6 +293,13 @@ fn gen_payload(rng: &mut SplitMix64) -> OperationPayload {
|
|||
rng.below(2),
|
||||
)),
|
||||
}),
|
||||
// Genesis tranche G2a: the two major-0 settings setters.
|
||||
29 => OperationKind::SetCanvasLayoutDefaults(crate::payload::SetCanvasLayoutDefaultsOp {
|
||||
layout_defaults: valuegen::canvas_layout_defaults(rng.below(3) as u8),
|
||||
}),
|
||||
30 => OperationKind::SetSpellingPrecedence(crate::payload::SetSpellingPrecedenceOp {
|
||||
precedence: valuegen::spelling_precedence(rng.below(3) as u8),
|
||||
}),
|
||||
_ => OperationKind::SetStaffLayout(SetStaffLayoutOp {
|
||||
staff_instance: StaffInstanceId::new(ReplicaId(7), rng.below(3)),
|
||||
instrument_override: None,
|
||||
|
|
|
|||
|
|
@ -130,10 +130,10 @@ pub use payload::{
|
|||
DeleteRegionOp, DeleteRepeatStructureOp, DeleteStaffInstanceOp, DeleteVoiceOp, InsertEventOp,
|
||||
InsertIdentifiedPitchOp, ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp,
|
||||
OperationKind, OperationKindTag, OperationPayload, PositionRemapping, ResolveConflictPayload,
|
||||
ResolveEquivocationPayload, RespellPitchOp, SetMetadataOp, SetMetricGridOp, SetStaffLayoutOp,
|
||||
SetTempoSegmentOp, SetTimeSignatureOp, SetUserPageBreakOp, SetUserSystemBreakOp,
|
||||
TransactionCategory, TransactionDescriptor, TransposeIntervalOp, TransposeOp,
|
||||
TupletCompensation,
|
||||
ResolveEquivocationPayload, RespellPitchOp, SetCanvasLayoutDefaultsOp, SetMetadataOp,
|
||||
SetMetricGridOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp,
|
||||
SetTimeSignatureOp, SetUserPageBreakOp, SetUserSystemBreakOp, TransactionCategory,
|
||||
TransactionDescriptor, TransposeIntervalOp, TransposeOp, TupletCompensation,
|
||||
};
|
||||
pub use reduce::{
|
||||
canonical_reduction_order, GraphMaterialization, MaterializedState, ObjectState, PendingReason,
|
||||
|
|
|
|||
|
|
@ -181,6 +181,13 @@ fn project_kind(kind: &OperationKind) -> V0OperationKind {
|
|||
OperationKind::TransposeInterval(op) => V0OperationKind::TransposeInterval(op.clone()),
|
||||
// Genesis tranche G1: born past v0; projected verbatim.
|
||||
OperationKind::CreateInstrument(op) => V0OperationKind::CreateInstrument(op.clone()),
|
||||
// Genesis tranche G2a: born past v0; projected verbatim.
|
||||
OperationKind::SetCanvasLayoutDefaults(op) => {
|
||||
V0OperationKind::SetCanvasLayoutDefaults(op.clone())
|
||||
}
|
||||
OperationKind::SetSpellingPrecedence(op) => {
|
||||
V0OperationKind::SetSpellingPrecedence(op.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -336,6 +343,13 @@ fn migrate_kind(kind: &V0OperationKind, context: &Score) -> Result<OperationKind
|
|||
V0OperationKind::DeleteRepeatStructure(op) => OperationKind::DeleteRepeatStructure(*op),
|
||||
// Genesis tranche G1: identity round-trip (no lossy v0 form).
|
||||
V0OperationKind::CreateInstrument(op) => OperationKind::CreateInstrument(op.clone()),
|
||||
// Genesis tranche G2a: identity round-trip (no lossy v0 form).
|
||||
V0OperationKind::SetCanvasLayoutDefaults(op) => {
|
||||
OperationKind::SetCanvasLayoutDefaults(op.clone())
|
||||
}
|
||||
V0OperationKind::SetSpellingPrecedence(op) => {
|
||||
OperationKind::SetSpellingPrecedence(op.clone())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,12 +32,12 @@
|
|||
//! payloads.
|
||||
|
||||
use epiphany_core::{
|
||||
Beam, CanonicalValue, Event, EventDuration, EventId, EventPosition, IdentifiedPitch,
|
||||
Instrument, InstrumentId, MetricGrid, MusicalDuration, MusicalPosition, OperationId, Pitch,
|
||||
PitchId, PitchSpelling, Region, RegionId, RegionTimeModel, RepeatStructure, RepeatStructureId,
|
||||
Rest, ScoreMetadata, Slur, Spanner, Staff, StaffId, StaffInstance, StaffInstanceId,
|
||||
StaffLineConfiguration, TempoSegment, Tie, TimeAnchor, TimeSignature, TransactionId,
|
||||
TranspositionInterval, TupletId, TypedObjectId, Voice, VoiceId,
|
||||
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,
|
||||
TimeSignature, TransactionId, TranspositionInterval, TupletId, TypedObjectId, Voice, VoiceId,
|
||||
};
|
||||
use epiphany_determinism::{
|
||||
sorted_canonical, CanonicalDecode, CanonicalEncode, CanonicalSet, DecodeError,
|
||||
|
|
@ -203,6 +203,15 @@ pub enum OperationKind {
|
|||
/// `CreateStaff` already demands a live `Instrument` and nothing else can
|
||||
/// create one.
|
||||
CreateInstrument(CreateInstrumentOp),
|
||||
// --- Genesis tranche G2a (`spec/CONTRACT_GENESIS_G2A_SETTINGS.md`): the
|
||||
// two major-0 settings setters. Discriminants extend additively past 31.
|
||||
// ---
|
||||
/// Overwrite the canvas's default layout advisories (later-in-canonical-
|
||||
/// order wins).
|
||||
SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp),
|
||||
/// Overwrite the score's spelling precedence (later-in-canonical-order
|
||||
/// wins).
|
||||
SetSpellingPrecedence(SetSpellingPrecedenceOp),
|
||||
}
|
||||
|
||||
impl OperationKind {
|
||||
|
|
@ -304,6 +313,10 @@ impl OperationKind {
|
|||
// accident, not by rule — the two spaces are independent and
|
||||
// misaligned elsewhere (`RespellPitch` is kind 2 / tag 3).
|
||||
OperationKind::CreateInstrument(_) => 31,
|
||||
// Genesis tranche G2a; appended past 31. Coincide with tags 32/33
|
||||
// by the same accident as above, not by rule.
|
||||
OperationKind::SetCanvasLayoutDefaults(_) => 32,
|
||||
OperationKind::SetSpellingPrecedence(_) => 33,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -349,6 +362,8 @@ impl OperationKind {
|
|||
// `CreateRepeatStructure`) are — the tag layer's older
|
||||
// Create→Insert convention is not followed here (contract pin 3).
|
||||
OperationKind::CreateInstrument(_) => OperationKindTag::CreateInstrument,
|
||||
OperationKind::SetCanvasLayoutDefaults(_) => OperationKindTag::SetCanvasLayoutDefaults,
|
||||
OperationKind::SetSpellingPrecedence(_) => OperationKindTag::SetSpellingPrecedence,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -392,6 +407,8 @@ impl CanonicalEncode for OperationKind {
|
|||
OperationKind::CreateRepeatStructure(op) => op.encode_canonical(out),
|
||||
OperationKind::DeleteRepeatStructure(op) => op.encode_canonical(out),
|
||||
OperationKind::CreateInstrument(op) => op.encode_canonical(out),
|
||||
OperationKind::SetCanvasLayoutDefaults(op) => op.encode_canonical(out),
|
||||
OperationKind::SetSpellingPrecedence(op) => op.encode_canonical(out),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -442,6 +459,10 @@ pub enum OperationKindTag {
|
|||
/// older Create→Insert convention (`InsertStaff` for `CreateStaff`) is not
|
||||
/// followed here, matching the two most recent additions.
|
||||
CreateInstrument,
|
||||
/// Genesis tranche G2a.
|
||||
SetCanvasLayoutDefaults,
|
||||
/// Genesis tranche G2a.
|
||||
SetSpellingPrecedence,
|
||||
}
|
||||
|
||||
/// The discriminant of [`OperationKindTag::Registered`], the one tag that
|
||||
|
|
@ -540,6 +561,8 @@ operation_kind_tag_vocabulary! {
|
|||
DeleteRepeatStructure = 29 => "delete-repeat-structure",
|
||||
TransposeInterval = 30 => "transpose-interval",
|
||||
CreateInstrument = 31 => "create-instrument",
|
||||
SetCanvasLayoutDefaults = 32 => "set-canvas-layout-defaults",
|
||||
SetSpellingPrecedence = 33 => "set-spelling-precedence",
|
||||
}
|
||||
|
||||
impl CanonicalEncode for OperationKindTag {
|
||||
|
|
@ -1470,6 +1493,42 @@ impl CanonicalEncode for CreateInstrumentOp {
|
|||
}
|
||||
}
|
||||
|
||||
// --- Genesis tranche G2a (`spec/CONTRACT_GENESIS_G2A_SETTINGS.md`): the two
|
||||
// major-0 settings setters. LWW field-overwrite, exactly the `SetMetadata`
|
||||
// discipline (advisory last-writer-wins, no conflict, no idempotence
|
||||
// short-circuit). ---
|
||||
|
||||
/// Overwrite the canvas's default layout advisories (operation_catalog
|
||||
/// §SetCanvasLayoutDefaults). Carries the full [`CanvasLayoutDefaults`]; the
|
||||
/// score-singleton field-overwrite is *advisory* last-writer-wins — the latest
|
||||
/// write in canonical order silently wins and no conflict is recorded, exactly
|
||||
/// `SetMetadata`.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct SetCanvasLayoutDefaultsOp {
|
||||
pub layout_defaults: CanvasLayoutDefaults,
|
||||
}
|
||||
|
||||
impl CanonicalEncode for SetCanvasLayoutDefaultsOp {
|
||||
fn encode_canonical(&self, out: &mut Vec<u8>) {
|
||||
push_lp_bytes(out, &self.layout_defaults.canonical_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
/// Overwrite the score's spelling precedence (operation_catalog
|
||||
/// §SetSpellingPrecedence). Carries the full [`SpellingPrecedence`]; the
|
||||
/// score-singleton field-overwrite is *advisory* last-writer-wins, exactly
|
||||
/// `SetMetadata`.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct SetSpellingPrecedenceOp {
|
||||
pub precedence: SpellingPrecedence,
|
||||
}
|
||||
|
||||
impl CanonicalEncode for SetSpellingPrecedenceOp {
|
||||
fn encode_canonical(&self, out: &mut Vec<u8>) {
|
||||
push_lp_bytes(out, &self.precedence.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
|
||||
|
|
|
|||
|
|
@ -33,14 +33,14 @@ use std::collections::{BTreeMap, BTreeSet, BinaryHeap};
|
|||
|
||||
use epiphany_core::{
|
||||
canonical_pitch_bytes, derive_promoted_voice_id, simplest_spelling, AnchorOffset,
|
||||
AnnotationAnchor, CanonicalValue, Event, EventDuration, EventId, EventPosition,
|
||||
GestureAnchoring, Instrument, InstrumentId, MeterChange, MetricGrid, MusicalDuration,
|
||||
MusicalPosition, OperationId, Pitch, PitchId, PitchSpelling, RationalTime, RegionEdge,
|
||||
RegionId, RegionTimeModel, ReplicaId, Score, ScoreMetadata, SpellingAttachment,
|
||||
SpellingDirective, SpellingScope, SpellingSource, Staff, StaffId, StaffInstance,
|
||||
StaffInstanceId, StaffLineConfiguration, TempoMap, TempoSegment, TempoShape, TimeAnchor,
|
||||
TimeSignature, TimeSignatureId, TransactionId, TransposeRefusal, TranspositionInterval,
|
||||
TypedObjectId, Voice, VoiceId, VoiceOrigin,
|
||||
AnnotationAnchor, CanonicalValue, CanvasLayoutDefaults, Event, EventDuration, EventId,
|
||||
EventPosition, GestureAnchoring, Instrument, InstrumentId, MeterChange, MetricGrid,
|
||||
MusicalDuration, MusicalPosition, OperationId, Pitch, PitchId, PitchSpelling, RationalTime,
|
||||
RegionEdge, RegionId, RegionTimeModel, ReplicaId, Score, ScoreMetadata, SpellingAttachment,
|
||||
SpellingDirective, SpellingPrecedence, SpellingScope, SpellingSource, Staff, StaffId,
|
||||
StaffInstance, StaffInstanceId, StaffLineConfiguration, TempoMap, TempoSegment, TempoShape,
|
||||
TimeAnchor, TimeSignature, TimeSignatureId, TransactionId, TransposeRefusal,
|
||||
TranspositionInterval, TypedObjectId, Voice, VoiceId, VoiceOrigin,
|
||||
};
|
||||
use epiphany_determinism::CanonicalEncode;
|
||||
|
||||
|
|
@ -61,9 +61,9 @@ use crate::payload::{
|
|||
CrossCuttingValue, DeleteCrossCuttingOp, DeleteEventOp, DeleteIdentifiedPitchOp,
|
||||
DeleteRegionOp, DeleteRepeatStructureOp, DeleteStaffInstanceOp, DeleteVoiceOp, InsertEventOp,
|
||||
InsertIdentifiedPitchOp, ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp,
|
||||
OperationKind, OperationPayload, RespellPitchOp, SetMetadataOp, SetMetricGridOp,
|
||||
SetStaffLayoutOp, SetTempoSegmentOp, SetTimeSignatureOp, SetUserPageBreakOp,
|
||||
TransposeIntervalOp, TransposeOp, TupletCompensation,
|
||||
OperationKind, OperationPayload, RespellPitchOp, SetCanvasLayoutDefaultsOp, SetMetadataOp,
|
||||
SetMetricGridOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp,
|
||||
SetTimeSignatureOp, SetUserPageBreakOp, TransposeIntervalOp, TransposeOp, TupletCompensation,
|
||||
};
|
||||
use crate::stamp::StampTuple;
|
||||
use crate::support::{ObjectKind, SerializedCanonicalInputs};
|
||||
|
|
@ -785,6 +785,14 @@ enum ValueRestoration {
|
|||
Metadata {
|
||||
value: Option<ScoreMetadata>,
|
||||
},
|
||||
/// Genesis tranche G2a.
|
||||
CanvasLayoutDefaults {
|
||||
value: Option<CanvasLayoutDefaults>,
|
||||
},
|
||||
/// Genesis tranche G2a.
|
||||
SpellingPrecedence {
|
||||
value: Option<SpellingPrecedence>,
|
||||
},
|
||||
MetricGrid {
|
||||
region: RegionId,
|
||||
value: Option<MetricGrid>,
|
||||
|
|
@ -899,6 +907,13 @@ struct Reducer<'a> {
|
|||
cross_cutting_modify_chain: BTreeMap<TypedObjectId, WriteChain<CrossCuttingValue>>,
|
||||
metric_grid_chain: BTreeMap<RegionId, WriteChain<Option<MetricGrid>>>,
|
||||
metadata_chain: WriteChain<ScoreMetadata>,
|
||||
// Genesis tranche G2a (`CONTRACT_GENESIS_G2A_SETTINGS.md` pin 6/7/8):
|
||||
// score-singleton LWW chains for the two new settings setters, mirroring
|
||||
// `metadata_chain` exactly — advisory last-writer-wins, seeded from the
|
||||
// base so a value-restoring undo of the first operational write restores
|
||||
// the pre-operational value.
|
||||
canvas_layout_defaults_chain: WriteChain<CanvasLayoutDefaults>,
|
||||
spelling_precedence_chain: WriteChain<SpellingPrecedence>,
|
||||
break_chain: BTreeMap<(RegionId, MusicalPosition), WriteChain<(TimeAnchor, bool)>>,
|
||||
page_break_chain: BTreeMap<(RegionId, MusicalPosition), WriteChain<(TimeAnchor, bool)>>,
|
||||
// Meter/tempo overwrite chains (Phase-3 tranche): `Some` = a set/replace at
|
||||
|
|
@ -1010,6 +1025,8 @@ struct WorkingSnapshot {
|
|||
cross_cutting_modify_chain: BTreeMap<TypedObjectId, WriteChain<CrossCuttingValue>>,
|
||||
metric_grid_chain: BTreeMap<RegionId, WriteChain<Option<MetricGrid>>>,
|
||||
metadata_chain: WriteChain<ScoreMetadata>,
|
||||
canvas_layout_defaults_chain: WriteChain<CanvasLayoutDefaults>,
|
||||
spelling_precedence_chain: WriteChain<SpellingPrecedence>,
|
||||
break_chain: BTreeMap<(RegionId, MusicalPosition), WriteChain<(TimeAnchor, bool)>>,
|
||||
page_break_chain: BTreeMap<(RegionId, MusicalPosition), WriteChain<(TimeAnchor, bool)>>,
|
||||
meter_change_chain: BTreeMap<(RegionId, MusicalPosition), WriteChain<Option<MeterChange>>>,
|
||||
|
|
@ -1290,6 +1307,8 @@ impl<'a> Reducer<'a> {
|
|||
cross_cutting_modify_chain: BTreeMap::new(),
|
||||
metric_grid_chain: BTreeMap::new(),
|
||||
metadata_chain: WriteChain::new(),
|
||||
canvas_layout_defaults_chain: WriteChain::new(),
|
||||
spelling_precedence_chain: WriteChain::new(),
|
||||
break_chain: BTreeMap::new(),
|
||||
page_break_chain: BTreeMap::new(),
|
||||
meter_change_chain: BTreeMap::new(),
|
||||
|
|
@ -1383,6 +1402,15 @@ impl<'a> Reducer<'a> {
|
|||
// value-restoring undo of the first operational write can restore the
|
||||
// pre-operational state (operation_catalog §UndoTransaction).
|
||||
self.metadata_chain.seed(score.metadata.clone());
|
||||
// Genesis tranche G2a (contract pin 6): same discipline for the two new
|
||||
// settings setters. Both are always-valued `Score` fields — like
|
||||
// `metadata`, not a map key — so there is no "never authored" state to
|
||||
// distinguish; restoring the seeded base default is correct whether the
|
||||
// base was authored-to-default or never touched.
|
||||
self.canvas_layout_defaults_chain
|
||||
.seed(score.canvas.layout_defaults);
|
||||
self.spelling_precedence_chain
|
||||
.seed(score.spelling_precedence.clone());
|
||||
for segment in &score.tempo_map.segments {
|
||||
self.tempo_segment_chain
|
||||
.entry((None, resolved_anchor_position(&segment.start)))
|
||||
|
|
@ -2743,6 +2771,10 @@ impl<'a> Reducer<'a> {
|
|||
OperationKind::CreateRepeatStructure(op) => self.create_repeat_structure(env, op),
|
||||
OperationKind::DeleteRepeatStructure(op) => self.delete_repeat_structure(env, op),
|
||||
OperationKind::CreateInstrument(op) => self.create_instrument(env, op),
|
||||
OperationKind::SetCanvasLayoutDefaults(op) => {
|
||||
self.set_canvas_layout_defaults(env, op)
|
||||
}
|
||||
OperationKind::SetSpellingPrecedence(op) => self.set_spelling_precedence(env, op),
|
||||
},
|
||||
OperationPayload::ResolveConflict(op) => self.resolve_conflict(env, op),
|
||||
OperationPayload::UndoTransaction(op) => self.undo_transaction(env, op),
|
||||
|
|
@ -2823,6 +2855,40 @@ impl<'a> Reducer<'a> {
|
|||
OperationEffect::Applied
|
||||
}
|
||||
|
||||
/// Genesis tranche G2a (`CONTRACT_GENESIS_G2A_SETTINGS.md` pin 5): copies
|
||||
/// `set_metadata` structurally — advisory LWW, no conflict, no idempotence
|
||||
/// short-circuit. A re-write of an identical value is a legitimate new
|
||||
/// write, not a no-op.
|
||||
fn set_canvas_layout_defaults(
|
||||
&mut self,
|
||||
env: &OperationEnvelope,
|
||||
op: &SetCanvasLayoutDefaultsOp,
|
||||
) -> OperationEffect {
|
||||
self.canvas_layout_defaults_chain
|
||||
.record(env.id, env.transaction, op.layout_defaults);
|
||||
if let Some(score) = self.graph.as_mut() {
|
||||
score.canvas.layout_defaults = op.layout_defaults;
|
||||
}
|
||||
OperationEffect::Applied
|
||||
}
|
||||
|
||||
/// Genesis tranche G2a (`CONTRACT_GENESIS_G2A_SETTINGS.md` pin 5): copies
|
||||
/// `set_metadata` structurally — advisory LWW, no conflict, no idempotence
|
||||
/// short-circuit. A re-write of an identical value is a legitimate new
|
||||
/// write, not a no-op.
|
||||
fn set_spelling_precedence(
|
||||
&mut self,
|
||||
env: &OperationEnvelope,
|
||||
op: &SetSpellingPrecedenceOp,
|
||||
) -> OperationEffect {
|
||||
self.spelling_precedence_chain
|
||||
.record(env.id, env.transaction, op.precedence.clone());
|
||||
if let Some(score) = self.graph.as_mut() {
|
||||
score.spelling_precedence = op.precedence.clone();
|
||||
}
|
||||
OperationEffect::Applied
|
||||
}
|
||||
|
||||
fn set_metric_grid(
|
||||
&mut self,
|
||||
env: &OperationEnvelope,
|
||||
|
|
@ -5190,6 +5256,26 @@ impl<'a> Reducer<'a> {
|
|||
})
|
||||
}
|
||||
}
|
||||
// Genesis tranche G2a (contract pin 7): mirror `metadata_chain` for
|
||||
// the two new score-singleton settings chains.
|
||||
match self.canvas_layout_defaults_chain.undo_verdict(tx) {
|
||||
ChainUndoVerdict::NotWritten => {}
|
||||
ChainUndoVerdict::Superseded { by } => superseded.push(by),
|
||||
ChainUndoVerdict::Restore(predecessor) => {
|
||||
restorations.push(ValueRestoration::CanvasLayoutDefaults {
|
||||
value: predecessor.map(Predecessor::into_value),
|
||||
})
|
||||
}
|
||||
}
|
||||
match self.spelling_precedence_chain.undo_verdict(tx) {
|
||||
ChainUndoVerdict::NotWritten => {}
|
||||
ChainUndoVerdict::Superseded { by } => superseded.push(by),
|
||||
ChainUndoVerdict::Restore(predecessor) => {
|
||||
restorations.push(ValueRestoration::SpellingPrecedence {
|
||||
value: predecessor.map(Predecessor::into_value),
|
||||
})
|
||||
}
|
||||
}
|
||||
for (region, chain) in &self.metric_grid_chain {
|
||||
if !slot_live(TypedObjectId::Region(*region)) {
|
||||
continue;
|
||||
|
|
@ -5409,6 +5495,27 @@ impl<'a> Reducer<'a> {
|
|||
self.metadata_chain.record(env.id, env.transaction, value);
|
||||
}
|
||||
}
|
||||
// Genesis tranche G2a (contract pin 7): mirror `Metadata`'s
|
||||
// restoration-apply shape for the two new score-singleton
|
||||
// settings chains.
|
||||
ValueRestoration::CanvasLayoutDefaults { value } => {
|
||||
if let Some(value) = value {
|
||||
if let Some(score) = self.graph.as_mut() {
|
||||
score.canvas.layout_defaults = value;
|
||||
}
|
||||
self.canvas_layout_defaults_chain
|
||||
.record(env.id, env.transaction, value);
|
||||
}
|
||||
}
|
||||
ValueRestoration::SpellingPrecedence { value } => {
|
||||
if let Some(value) = value {
|
||||
if let Some(score) = self.graph.as_mut() {
|
||||
score.spelling_precedence = value.clone();
|
||||
}
|
||||
self.spelling_precedence_chain
|
||||
.record(env.id, env.transaction, value);
|
||||
}
|
||||
}
|
||||
ValueRestoration::MetricGrid { region, value } => {
|
||||
self.metric_grid_chain
|
||||
.entry(region)
|
||||
|
|
@ -7384,6 +7491,8 @@ impl<'a> Reducer<'a> {
|
|||
cross_cutting_modify_chain: self.cross_cutting_modify_chain.clone(),
|
||||
metric_grid_chain: self.metric_grid_chain.clone(),
|
||||
metadata_chain: self.metadata_chain.clone(),
|
||||
canvas_layout_defaults_chain: self.canvas_layout_defaults_chain.clone(),
|
||||
spelling_precedence_chain: self.spelling_precedence_chain.clone(),
|
||||
break_chain: self.break_chain.clone(),
|
||||
page_break_chain: self.page_break_chain.clone(),
|
||||
meter_change_chain: self.meter_change_chain.clone(),
|
||||
|
|
@ -7421,6 +7530,8 @@ impl<'a> Reducer<'a> {
|
|||
self.cross_cutting_modify_chain = s.cross_cutting_modify_chain;
|
||||
self.metric_grid_chain = s.metric_grid_chain;
|
||||
self.metadata_chain = s.metadata_chain;
|
||||
self.canvas_layout_defaults_chain = s.canvas_layout_defaults_chain;
|
||||
self.spelling_precedence_chain = s.spelling_precedence_chain;
|
||||
self.break_chain = s.break_chain;
|
||||
self.page_break_chain = s.page_break_chain;
|
||||
self.meter_change_chain = s.meter_change_chain;
|
||||
|
|
@ -10667,6 +10778,41 @@ mod tests {
|
|||
2,
|
||||
"CreateInstrument is unconditionally v2, even for the minimal instrument"
|
||||
);
|
||||
|
||||
// (s5) Genesis tranche G2a: both new setters fall into the catch-all
|
||||
// `_ => 0` arm — contract pin 3 is explicit that adding them to the
|
||||
// `=> 2` arm alongside `SetMetadata` would be the bug, since
|
||||
// `SetMetadata` sits there because `ScoreMetadata` has mandatory
|
||||
// major-2 appends, a property of *that* type and nothing else.
|
||||
// Asserted on non-default values so an arm that becomes
|
||||
// value-dependent in the wrong direction cannot hide behind the
|
||||
// `Default`.
|
||||
let non_default_layout = {
|
||||
let mut d = epiphany_core::CanvasLayoutDefaults::default();
|
||||
d.page_size.width = epiphany_determinism::CanonicalF64::new(200.0).unwrap();
|
||||
d
|
||||
};
|
||||
assert_eq!(
|
||||
OperationKind::SetCanvasLayoutDefaults(crate::payload::SetCanvasLayoutDefaultsOp {
|
||||
layout_defaults: non_default_layout,
|
||||
})
|
||||
.schema_major(),
|
||||
0,
|
||||
"SetCanvasLayoutDefaults stays in the major-0 catch-all"
|
||||
);
|
||||
let non_default_precedence = crate::valuegen::spelling_precedence(1);
|
||||
assert_ne!(
|
||||
non_default_precedence,
|
||||
epiphany_core::SpellingPrecedence::default()
|
||||
);
|
||||
assert_eq!(
|
||||
OperationKind::SetSpellingPrecedence(crate::payload::SetSpellingPrecedenceOp {
|
||||
precedence: non_default_precedence,
|
||||
})
|
||||
.schema_major(),
|
||||
0,
|
||||
"SetSpellingPrecedence stays in the major-0 catch-all"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -10743,6 +10889,23 @@ mod tests {
|
|||
// (unconditionally, contract pin 4), but `MaterializedState` stamps
|
||||
// no schema major at all — that is an `OperationEnvelopeBlock`
|
||||
// concern in `epiphany-bundle`, which this packet does not touch.
|
||||
//
|
||||
// Re-pinned again at genesis tranche G2a
|
||||
// (`spec/CONTRACT_GENESIS_G2A_SETTINGS.md`): `gen_payload` gained
|
||||
// `SetCanvasLayoutDefaults` (arm 29) and `SetSpellingPrecedence`
|
||||
// (arm 30), and `rng.below(29)` became `below(31)` — the same
|
||||
// reshuffle, for the same reason: every operation id, effect, and
|
||||
// conflict downstream of the first draw moves. Confirmed a corpus
|
||||
// shift, not a value leak, by construction rather than inspection:
|
||||
// `MaterializedState` (`reduce.rs:504`) embeds no `Score` field value
|
||||
// for *any* setting, `SetMetadata` included — the base carries only
|
||||
// effects, conflicts, anomalies, objects, spellings, breaks,
|
||||
// page-breaks, and pending state. Neither new payload changes that
|
||||
// shape, and both are schema major 0 unconditionally (pin 3: no new
|
||||
// `schema_major()` arm), so there is no schema-major surface for a
|
||||
// leak to appear on even if the base did stamp one (it does not —
|
||||
// that is `OperationEnvelopeBlock`'s concern in `epiphany-bundle`,
|
||||
// untouched by this packet).
|
||||
let mut rng = epiphany_determinism::fuzz::SplitMix64::new(0xBA5E);
|
||||
let envelopes = crate::fuzz::gen_envelope_set(&mut rng, 200);
|
||||
let mut set = OperationSet::new();
|
||||
|
|
@ -10752,7 +10915,7 @@ mod tests {
|
|||
let hex: String = digest.iter().map(|b| format!("{b:02x}")).collect();
|
||||
assert_eq!(
|
||||
hex,
|
||||
"61af8ebbba1c4d98360ec44812e5d97a89a720738c1e3573d865f26b48addd1d"
|
||||
"7fd6455a6ae304101774ba981d01702ad37c567575707b1e814dad6e153ab07d"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -12948,4 +13111,339 @@ mod tests {
|
|||
"graph-aware reduction enforces the precondition base-free skipped"
|
||||
);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Genesis tranche G2a (`spec/CONTRACT_GENESIS_G2A_SETTINGS.md`): the two
|
||||
// major-0 settings setters, `SetCanvasLayoutDefaults` and
|
||||
// `SetSpellingPrecedence`, on the `SetMetadata` LWW pattern.
|
||||
// =========================================================================
|
||||
|
||||
/// (s1) From-empty authoring: through `reduce_operation_set_onto`, each
|
||||
/// new setter produces its authored value in the materialized `Score`.
|
||||
///
|
||||
/// **Mutation:** drop the graph write in the setter fn (`score.canvas.
|
||||
/// layout_defaults = op.layout_defaults;` / `score.spelling_precedence =
|
||||
/// op.precedence.clone();`) -> the field stays at its `Default` while the
|
||||
/// effect still reads `Applied`.
|
||||
#[test]
|
||||
fn from_empty_settings_setters_materialize_the_authored_value() {
|
||||
let identity = IdentityContext::new(ReplicaId(1));
|
||||
let layout = crate::valuegen::canvas_layout_defaults(1);
|
||||
let precedence = crate::valuegen::spelling_precedence(1);
|
||||
let set_layout = prim_env(
|
||||
1,
|
||||
0,
|
||||
10,
|
||||
CausalContext::new(),
|
||||
OperationKind::SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp {
|
||||
layout_defaults: layout,
|
||||
}),
|
||||
);
|
||||
let set_precedence = prim_env(
|
||||
1,
|
||||
1,
|
||||
11,
|
||||
seen_r1(0),
|
||||
OperationKind::SetSpellingPrecedence(SetSpellingPrecedenceOp {
|
||||
precedence: precedence.clone(),
|
||||
}),
|
||||
);
|
||||
let mut set = OperationSet::new();
|
||||
set.accept_all(vec![set_layout.clone(), set_precedence.clone()]);
|
||||
let out = reduce_operation_set_onto(&set, &Score::empty(identity));
|
||||
|
||||
assert_eq!(
|
||||
out.score.canvas.layout_defaults, layout,
|
||||
"SetCanvasLayoutDefaults materializes in the graph"
|
||||
);
|
||||
assert_eq!(
|
||||
out.score.spelling_precedence, precedence,
|
||||
"SetSpellingPrecedence materializes in the graph"
|
||||
);
|
||||
assert_eq!(effect_at(&out.state, 0), Some(&OperationEffect::Applied));
|
||||
assert_eq!(effect_at(&out.state, 1), Some(&OperationEffect::Applied));
|
||||
}
|
||||
|
||||
/// (s2) LWW: two concurrent differing writes (neither sees the other)
|
||||
/// resolve to the later in canonical order, recording **no** conflict —
|
||||
/// matching `SetMetadata` (`ops/tests/graph_reduction.rs:1408`).
|
||||
///
|
||||
/// **Mutation:** *not* a reversed comparison — `set_canvas_layout_
|
||||
/// defaults`/`set_spelling_precedence` contain no comparison at all; they
|
||||
/// record and overwrite unconditionally. Mutate setter-locally to
|
||||
/// first-write-wins instead (skip the record-and-overwrite when the chain
|
||||
/// already holds a write) -> the earlier value survives and this test
|
||||
/// dies.
|
||||
#[test]
|
||||
fn concurrent_differing_settings_setters_are_advisory_lww_no_conflict() {
|
||||
let identity = IdentityContext::new(ReplicaId(1));
|
||||
let layout_a = crate::valuegen::canvas_layout_defaults(1);
|
||||
let layout_b = crate::valuegen::canvas_layout_defaults(2);
|
||||
assert_ne!(layout_a, layout_b);
|
||||
// Neither sees the other: both start from an empty causal context, so
|
||||
// they are genuinely concurrent.
|
||||
let a = prim_env(
|
||||
1,
|
||||
0,
|
||||
10,
|
||||
CausalContext::new(),
|
||||
OperationKind::SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp {
|
||||
layout_defaults: layout_a,
|
||||
}),
|
||||
);
|
||||
let b = prim_env(
|
||||
2,
|
||||
0,
|
||||
20,
|
||||
CausalContext::new(),
|
||||
OperationKind::SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp {
|
||||
layout_defaults: layout_b,
|
||||
}),
|
||||
);
|
||||
let mut set = OperationSet::new();
|
||||
set.accept_all(vec![a.clone(), b.clone()]);
|
||||
let out = reduce_operation_set_onto(&set, &Score::empty(identity));
|
||||
|
||||
assert!(
|
||||
out.state.conflicts.records().is_empty(),
|
||||
"concurrent differing SetCanvasLayoutDefaults is advisory — no conflict"
|
||||
);
|
||||
assert!(
|
||||
out.state.is_clean(),
|
||||
"an advisory layout-defaults edit keeps the materialized state clean"
|
||||
);
|
||||
// `b` has the later physical time, so canonical order places it last;
|
||||
// its value must be the one that survives.
|
||||
assert_eq!(
|
||||
out.score.canvas.layout_defaults, layout_b,
|
||||
"the later-in-canonical-order write wins"
|
||||
);
|
||||
}
|
||||
|
||||
/// (s3) A re-write of an identical value is a **new write**, not a
|
||||
/// no-op: assert the effect is `Applied` and not `AlreadyApplied`. This
|
||||
/// test exists because pin 5 is the most likely thing for a subagent to
|
||||
/// get wrong by pattern-matching on `create_staff`'s mint discipline.
|
||||
///
|
||||
/// **Mutation:** add an `AlreadyApplied` short-circuit to the setter fn
|
||||
/// (skip the record-and-write when the new value equals the current one)
|
||||
/// -> dies.
|
||||
#[test]
|
||||
fn rewriting_an_identical_settings_value_is_a_new_write_not_a_no_op() {
|
||||
let identity = IdentityContext::new(ReplicaId(1));
|
||||
let precedence = crate::valuegen::spelling_precedence(1);
|
||||
let first = prim_env(
|
||||
1,
|
||||
0,
|
||||
10,
|
||||
CausalContext::new(),
|
||||
OperationKind::SetSpellingPrecedence(SetSpellingPrecedenceOp {
|
||||
precedence: precedence.clone(),
|
||||
}),
|
||||
);
|
||||
let second = prim_env(
|
||||
1,
|
||||
1,
|
||||
11,
|
||||
seen_r1(0),
|
||||
OperationKind::SetSpellingPrecedence(SetSpellingPrecedenceOp {
|
||||
precedence: precedence.clone(),
|
||||
}),
|
||||
);
|
||||
let mut set = OperationSet::new();
|
||||
set.accept_all(vec![first.clone(), second.clone()]);
|
||||
let out = reduce_operation_set_onto(&set, &Score::empty(identity));
|
||||
|
||||
assert_eq!(
|
||||
effect_at(&out.state, 0),
|
||||
Some(&OperationEffect::Applied),
|
||||
"the first write applies"
|
||||
);
|
||||
assert_eq!(
|
||||
effect_at(&out.state, 1),
|
||||
Some(&OperationEffect::Applied),
|
||||
"a byte-identical re-write is still a new Applied write, not AlreadyApplied"
|
||||
);
|
||||
}
|
||||
|
||||
/// (s4) Value-restoring undo reaches the seeded base — run both
|
||||
/// from-empty (base = `Default`) and onto a loaded base with a
|
||||
/// non-default value, so the test distinguishes "restored the base" from
|
||||
/// "restored the type default".
|
||||
///
|
||||
/// **Mutation:** remove the `.seed(...)` calls in `seed_from_graph` ->
|
||||
/// the undo produces `Restore(None)` and the field does not move (it
|
||||
/// stays at the transaction's authored value instead of reverting).
|
||||
#[test]
|
||||
fn value_restoring_undo_of_settings_setters_reaches_the_seeded_base() {
|
||||
// Case A: from-empty. Base = Score::empty, so the seed is the type
|
||||
// Default.
|
||||
{
|
||||
let identity = IdentityContext::new(ReplicaId(1));
|
||||
let tx = TransactionId::from_raw(1);
|
||||
let authored = crate::valuegen::canvas_layout_defaults(3);
|
||||
let envelopes = vec![
|
||||
declare_transaction(1, 0, 10, CausalContext::new(), tx),
|
||||
tx_member(
|
||||
1,
|
||||
1,
|
||||
11,
|
||||
seen_r1(0),
|
||||
tx,
|
||||
OperationKind::SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp {
|
||||
layout_defaults: authored,
|
||||
}),
|
||||
),
|
||||
undo_env(1, 2, 12, seen_r1(1), tx, UndoPolicy::StrictInverse),
|
||||
];
|
||||
let mut set = OperationSet::new();
|
||||
set.accept_all(envelopes);
|
||||
let out = reduce_operation_set_onto(&set, &Score::empty(identity));
|
||||
assert_eq!(
|
||||
out.score.canvas.layout_defaults,
|
||||
CanvasLayoutDefaults::default(),
|
||||
"from-empty undo restores the seeded type Default"
|
||||
);
|
||||
}
|
||||
|
||||
// Case B: onto a loaded base whose value is already non-default —
|
||||
// undo must restore *that* value, not the type Default.
|
||||
{
|
||||
let mut base = Score::empty(IdentityContext::new(ReplicaId(1)));
|
||||
let base_value = crate::valuegen::spelling_precedence(1);
|
||||
base.spelling_precedence = base_value.clone();
|
||||
assert_ne!(base_value, SpellingPrecedence::default());
|
||||
|
||||
let tx = TransactionId::from_raw(2);
|
||||
let authored = crate::valuegen::spelling_precedence(2);
|
||||
let envelopes = vec![
|
||||
declare_transaction(1, 0, 10, CausalContext::new(), tx),
|
||||
tx_member(
|
||||
1,
|
||||
1,
|
||||
11,
|
||||
seen_r1(0),
|
||||
tx,
|
||||
OperationKind::SetSpellingPrecedence(SetSpellingPrecedenceOp {
|
||||
precedence: authored,
|
||||
}),
|
||||
),
|
||||
undo_env(1, 2, 12, seen_r1(1), tx, UndoPolicy::StrictInverse),
|
||||
];
|
||||
let mut set = OperationSet::new();
|
||||
set.accept_all(envelopes);
|
||||
let out = reduce_operation_set_onto(&set, &base);
|
||||
assert_eq!(
|
||||
out.score.spelling_precedence, base_value,
|
||||
"undo onto a loaded base restores the base's own value, not the type Default"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// (s7) Transaction rollback discards the write — and the assertion must
|
||||
/// not be on the field. `WorkingSnapshot` (`:7480`) is the transaction
|
||||
/// **rollback** mechanism: snapshot before, restore on failure. But
|
||||
/// `restore` reassigns the whole graph independently of every write
|
||||
/// chain, so a setter's *field* rolls back whether or not its chain was
|
||||
/// snapshotted — an assertion on the field alone cannot see a missing
|
||||
/// chain in the snapshot/restore pair.
|
||||
///
|
||||
/// Shaped so the stale chain is observable: author inside a **failed**
|
||||
/// transaction, then perform a **successful** write in a second
|
||||
/// transaction, then **undo that second transaction** and assert it
|
||||
/// restores the genuine predecessor — the pre-failure value, not the
|
||||
/// rolled-back one.
|
||||
///
|
||||
/// **Mutation:** omit `canvas_layout_defaults_chain` /
|
||||
/// `spelling_precedence_chain` from the snapshot/restore pair (`:7480`
|
||||
/// `snapshot`, `:7518` `restore`) -> the failed transaction's write
|
||||
/// survives in the chain and the second undo restores it instead of the
|
||||
/// true (pre-failure) predecessor.
|
||||
#[test]
|
||||
fn transaction_rollback_discards_the_write_from_the_chain_not_just_the_field() {
|
||||
let identity = IdentityContext::new(ReplicaId(1));
|
||||
let pre_failure = crate::valuegen::canvas_layout_defaults(1);
|
||||
let failed_tx_value = crate::valuegen::canvas_layout_defaults(2);
|
||||
let second_tx_value = crate::valuegen::canvas_layout_defaults(3);
|
||||
assert_ne!(pre_failure, failed_tx_value);
|
||||
assert_ne!(pre_failure, second_tx_value);
|
||||
assert_ne!(failed_tx_value, second_tx_value);
|
||||
|
||||
let fail_tx = TransactionId::from_raw(10);
|
||||
let ok_tx = TransactionId::from_raw(11);
|
||||
|
||||
// 1: a genuine, successful pre-failure write (not itself part of any
|
||||
// transaction) — this is the predecessor the final undo must reach.
|
||||
let pre = prim_env(
|
||||
1,
|
||||
0,
|
||||
10,
|
||||
CausalContext::new(),
|
||||
OperationKind::SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp {
|
||||
layout_defaults: pre_failure,
|
||||
}),
|
||||
);
|
||||
// 2: a transaction whose only member operation targets a missing
|
||||
// staff instance, so the transaction as a whole fails and rolls
|
||||
// back — `WorkingSnapshot` restores the graph, but a chain missing
|
||||
// from the snapshot/restore pair would leak this write into the
|
||||
// chain regardless.
|
||||
let missing_instance = StaffInstanceId::new(ReplicaId(1), 99);
|
||||
let fail_decl = declare_transaction(1, 1, 11, seen_r1(0), fail_tx);
|
||||
let fail_write = tx_member(
|
||||
1,
|
||||
2,
|
||||
12,
|
||||
seen_r1(1),
|
||||
fail_tx,
|
||||
OperationKind::SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp {
|
||||
layout_defaults: failed_tx_value,
|
||||
}),
|
||||
);
|
||||
let fail_doomed = tx_member(
|
||||
1,
|
||||
3,
|
||||
13,
|
||||
seen_r1(2),
|
||||
fail_tx,
|
||||
OperationKind::SetStaffLayout(SetStaffLayoutOp {
|
||||
staff_instance: missing_instance,
|
||||
instrument_override: None,
|
||||
staff_lines_override: None,
|
||||
visible: true,
|
||||
}),
|
||||
);
|
||||
// 3: a second, successful transaction that writes again.
|
||||
let ok_decl = declare_transaction(1, 4, 14, seen_r1(3), ok_tx);
|
||||
let ok_write = tx_member(
|
||||
1,
|
||||
5,
|
||||
15,
|
||||
seen_r1(4),
|
||||
ok_tx,
|
||||
OperationKind::SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp {
|
||||
layout_defaults: second_tx_value,
|
||||
}),
|
||||
);
|
||||
// 4: undo the second (successful) transaction.
|
||||
let undo = undo_env(1, 6, 16, seen_r1(5), ok_tx, UndoPolicy::StrictInverse);
|
||||
|
||||
let mut set = OperationSet::new();
|
||||
set.accept_all(vec![
|
||||
pre,
|
||||
fail_decl,
|
||||
fail_write,
|
||||
fail_doomed,
|
||||
ok_decl,
|
||||
ok_write,
|
||||
undo,
|
||||
]);
|
||||
let out = reduce_operation_set_onto(&set, &Score::empty(identity));
|
||||
|
||||
assert_eq!(
|
||||
out.score.canvas.layout_defaults, pre_failure,
|
||||
"undo of the second transaction must restore the genuine (pre-failure) \
|
||||
predecessor, not the rolled-back transaction's write"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,9 +13,10 @@ use crate::payload::{
|
|||
DeleteCrossCuttingOp, DeleteEventOp, DeleteIdentifiedPitchOp, DeleteRegionOp,
|
||||
DeleteRepeatStructureOp, DeleteStaffInstanceOp, DeleteVoiceOp, InsertEventOp,
|
||||
InsertIdentifiedPitchOp, ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp,
|
||||
OperationKind, OperationKindTag, RespellPitchOp, SetMetadataOp, SetMetricGridOp,
|
||||
SetStaffLayoutOp, SetTempoSegmentOp, SetTimeSignatureOp, SetUserPageBreakOp,
|
||||
SetUserSystemBreakOp, TransactionDescriptor, TransposeIntervalOp, TransposeOp,
|
||||
OperationKind, OperationKindTag, RespellPitchOp, SetCanvasLayoutDefaultsOp, SetMetadataOp,
|
||||
SetMetricGridOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp,
|
||||
SetTimeSignatureOp, SetUserPageBreakOp, SetUserSystemBreakOp, TransactionDescriptor,
|
||||
TransposeIntervalOp, TransposeOp,
|
||||
};
|
||||
use crate::support::OperationKindRegistryId;
|
||||
|
||||
|
|
@ -222,6 +223,12 @@ impl TextValue for OperationKind {
|
|||
OperationKind::CreateInstrument(op) => {
|
||||
production(self.tag(), vec![op.instrument.project()])
|
||||
}
|
||||
OperationKind::SetCanvasLayoutDefaults(op) => {
|
||||
production(self.tag(), vec![op.layout_defaults.project()])
|
||||
}
|
||||
OperationKind::SetSpellingPrecedence(op) => {
|
||||
production(self.tag(), vec![op.precedence.project()])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -543,6 +550,22 @@ impl TextValue for OperationKind {
|
|||
instrument: TextValue::parse(instrument)?,
|
||||
})
|
||||
}
|
||||
OperationKindTag::SetCanvasLayoutDefaults => {
|
||||
let [layout_defaults] = fields(s, tag, 1)? else {
|
||||
unreachable!("the arity-1 check returned one field")
|
||||
};
|
||||
OperationKind::SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp {
|
||||
layout_defaults: TextValue::parse(layout_defaults)?,
|
||||
})
|
||||
}
|
||||
OperationKindTag::SetSpellingPrecedence => {
|
||||
let [precedence] = fields(s, tag, 1)? else {
|
||||
unreachable!("the arity-1 check returned one field")
|
||||
};
|
||||
OperationKind::SetSpellingPrecedence(SetSpellingPrecedenceOp {
|
||||
precedence: TextValue::parse(precedence)?,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -596,7 +619,7 @@ mod tests {
|
|||
#[test]
|
||||
fn every_operation_kind_round_trips_with_canonical_text() {
|
||||
let tags: Vec<_> = all_tags().collect();
|
||||
assert_eq!(tags.len(), 32, "the grammar has 32 kind productions");
|
||||
assert_eq!(tags.len(), 34, "the grammar has 34 kind productions");
|
||||
for tag in tags {
|
||||
round_trip(&sample_kind(tag));
|
||||
}
|
||||
|
|
@ -615,6 +638,34 @@ mod tests {
|
|||
assert!(OperationKind::parse(&Sexp::List(items)).is_err());
|
||||
}
|
||||
|
||||
/// (s9, round-trip half) Genesis tranche G2a: a `set-canvas-layout-
|
||||
/// defaults` production carrying `set-spelling-precedence`'s field shape
|
||||
/// (relabeled under the other kind's tag) must not parse — the two
|
||||
/// carried types have incompatible projected shapes (`CanvasLayoutDefaults`
|
||||
/// projects a 2-field struct; `SpellingPrecedence` projects a 1-field
|
||||
/// struct wrapping a sequence), so mislabeling one as the other is
|
||||
/// rejected rather than mis-round-tripped.
|
||||
///
|
||||
/// **Mutation:** none needed to demonstrate the reject — this test *is*
|
||||
/// the reject-path exercise the contract asks for; a genuine defect
|
||||
/// would be a decoder that silently accepted the mismatched shape.
|
||||
#[test]
|
||||
fn one_settings_kind_production_under_the_others_tag_is_rejected() {
|
||||
let precedence_sample = sample_kind(OperationKindTag::SetSpellingPrecedence);
|
||||
let Sexp::List(mut items) = precedence_sample.project() else {
|
||||
panic!("operation projection is a list")
|
||||
};
|
||||
// Relabel the head symbol from `set-spelling-precedence` to
|
||||
// `set-canvas-layout-defaults`, keeping SpellingPrecedence's field
|
||||
// shape underneath.
|
||||
items[0] = Sexp::sym(OperationKindTag::SetCanvasLayoutDefaults.catalog_name());
|
||||
let mislabeled = Sexp::List(items);
|
||||
assert!(
|
||||
OperationKind::parse(&mislabeled).is_err(),
|
||||
"a production under the wrong kind's tag must not parse"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_label_projects_nfc_and_rejects_non_nfc_text() {
|
||||
let mut sample = sample_kind(OperationKindTag::DeclareTransaction);
|
||||
|
|
|
|||
|
|
@ -107,6 +107,11 @@ pub enum V0OperationKind {
|
|||
// the catalog entirely), so it round-trips by identity like every other
|
||||
// v1-native kind above.
|
||||
CreateInstrument(crate::payload::CreateInstrumentOp),
|
||||
// Genesis tranche G2a — born at wire-discs 32/33; no lossy v0 form (v0
|
||||
// predates the catalog entirely), so both round-trip by identity like
|
||||
// every other v1-native kind above.
|
||||
SetCanvasLayoutDefaults(crate::payload::SetCanvasLayoutDefaultsOp),
|
||||
SetSpellingPrecedence(crate::payload::SetSpellingPrecedenceOp),
|
||||
}
|
||||
|
||||
/// v0 `InsertEvent`: the event was a bare [`EventId`] plus the reduction-relevant
|
||||
|
|
|
|||
|
|
@ -368,6 +368,47 @@ pub fn instrument(id: epiphany_core::InstrumentId) -> epiphany_core::Instrument
|
|||
epiphany_core::Instrument::new(id, format!("instrument-{}", id.counter()))
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// field that resolves by canonical order with no conflict.
|
||||
pub fn canvas_layout_defaults(nth: u8) -> epiphany_core::CanvasLayoutDefaults {
|
||||
let mut defaults = epiphany_core::CanvasLayoutDefaults::default();
|
||||
defaults.page_size.width = epiphany_determinism::CanonicalF64::new(105.0 + f64::from(nth))
|
||||
.expect("a small positive offset from the A4 default stays finite");
|
||||
defaults
|
||||
}
|
||||
|
||||
/// Spelling precedence with an `nth`-distinct order (genesis tranche G2a) — for
|
||||
/// even `nth`, the type default (`UserChosen > Imported > Propagated >
|
||||
/// Inferred > Analytical`); for odd `nth`, that order reversed. Both are total
|
||||
/// orderings over the five source kinds, so `SpellingPrecedence::new` always
|
||||
/// succeeds; distinct `nth` parities give distinct values so a harness can
|
||||
/// drive concurrent `SetSpellingPrecedence`s, an advisory LWW field that
|
||||
/// resolves by canonical order with no conflict.
|
||||
pub fn spelling_precedence(nth: u8) -> epiphany_core::SpellingPrecedence {
|
||||
use epiphany_core::SpellingSourceKind;
|
||||
let order = if nth % 2 == 0 {
|
||||
vec![
|
||||
SpellingSourceKind::UserChosen,
|
||||
SpellingSourceKind::Imported,
|
||||
SpellingSourceKind::Propagated,
|
||||
SpellingSourceKind::Inferred,
|
||||
SpellingSourceKind::Analytical,
|
||||
]
|
||||
} else {
|
||||
vec![
|
||||
SpellingSourceKind::Analytical,
|
||||
SpellingSourceKind::Inferred,
|
||||
SpellingSourceKind::Propagated,
|
||||
SpellingSourceKind::Imported,
|
||||
SpellingSourceKind::UserChosen,
|
||||
]
|
||||
};
|
||||
epiphany_core::SpellingPrecedence::new(order)
|
||||
.expect("both listed orders are total over the five source kinds")
|
||||
}
|
||||
|
||||
/// A well-formed `numerator`/4 [`TimeSignature`](epiphany_core::TimeSignature)
|
||||
/// (Phase-3 tranche): `numerator` quarter-note beat groups summing exactly to
|
||||
/// the measure duration, so [`epiphany_core::TimeSignature::new`]'s beat-group
|
||||
|
|
|
|||
|
|
@ -298,6 +298,81 @@ pub fn decode_vectors() -> Vec<DecodeVector> {
|
|||
trailing,
|
||||
));
|
||||
|
||||
// --- OperationEnvelope carrying SetCanvasLayoutDefaults / SetSpellingPrecedence
|
||||
// (genesis tranche G2a) — same rationale as CreateInstrument above: nothing
|
||||
// else in this corpus exercises either payload's decode path, and a
|
||||
// round-trip check alone cannot see a self-consistent encoder/decoder
|
||||
// reorder (the 3b-i lesson).
|
||||
let layout_envelope = OperationEnvelope {
|
||||
id: OperationId::new(ReplicaId(1), 2),
|
||||
author: crate::support::AuthorId(0),
|
||||
stamp: crate::stamp::OperationStamp::new(
|
||||
crate::stamp::HybridLogicalClock::new(epiphany_core::WallClockTime(1), 1),
|
||||
OperationId::new(ReplicaId(1), 2),
|
||||
),
|
||||
causal_context: crate::causal::CausalContext::new(),
|
||||
transaction: None,
|
||||
payload: crate::payload::OperationPayload::Primitive(
|
||||
crate::payload::OperationKind::SetCanvasLayoutDefaults(
|
||||
crate::payload::SetCanvasLayoutDefaultsOp {
|
||||
layout_defaults: crate::valuegen::canvas_layout_defaults(1),
|
||||
},
|
||||
),
|
||||
),
|
||||
};
|
||||
let layout_envelope_bytes = layout_envelope.to_canonical_bytes();
|
||||
v.push(row(
|
||||
OE,
|
||||
"accept",
|
||||
"-",
|
||||
"set_canvas_layout_defaults",
|
||||
layout_envelope_bytes.clone(),
|
||||
));
|
||||
let mut layout_trailing = layout_envelope_bytes;
|
||||
layout_trailing.push(0);
|
||||
v.push(row(
|
||||
OE,
|
||||
"reject",
|
||||
"trailing-bytes",
|
||||
"set_canvas_layout_defaults_trailing",
|
||||
layout_trailing,
|
||||
));
|
||||
|
||||
let precedence_envelope = OperationEnvelope {
|
||||
id: OperationId::new(ReplicaId(1), 3),
|
||||
author: crate::support::AuthorId(0),
|
||||
stamp: crate::stamp::OperationStamp::new(
|
||||
crate::stamp::HybridLogicalClock::new(epiphany_core::WallClockTime(1), 1),
|
||||
OperationId::new(ReplicaId(1), 3),
|
||||
),
|
||||
causal_context: crate::causal::CausalContext::new(),
|
||||
transaction: None,
|
||||
payload: crate::payload::OperationPayload::Primitive(
|
||||
crate::payload::OperationKind::SetSpellingPrecedence(
|
||||
crate::payload::SetSpellingPrecedenceOp {
|
||||
precedence: crate::valuegen::spelling_precedence(1),
|
||||
},
|
||||
),
|
||||
),
|
||||
};
|
||||
let precedence_envelope_bytes = precedence_envelope.to_canonical_bytes();
|
||||
v.push(row(
|
||||
OE,
|
||||
"accept",
|
||||
"-",
|
||||
"set_spelling_precedence",
|
||||
precedence_envelope_bytes.clone(),
|
||||
));
|
||||
let mut precedence_trailing = precedence_envelope_bytes;
|
||||
precedence_trailing.push(0);
|
||||
v.push(row(
|
||||
OE,
|
||||
"reject",
|
||||
"trailing-bytes",
|
||||
"set_spelling_precedence_trailing",
|
||||
precedence_trailing,
|
||||
));
|
||||
|
||||
v
|
||||
}
|
||||
|
||||
|
|
@ -430,4 +505,54 @@ mod tests {
|
|||
"the committed literal bytes must decode and re-encode injectively"
|
||||
);
|
||||
}
|
||||
|
||||
/// (s8) Genesis tranche G2a (`spec/CONTRACT_GENESIS_G2A_SETTINGS.md`): the
|
||||
/// `SetCanvasLayoutDefaults` and `SetSpellingPrecedence` envelope decode
|
||||
/// vectors, pinned to literal byte arrays copied from the committed
|
||||
/// corpus — not derived by calling `.to_canonical_bytes()` here, for the
|
||||
/// same reason as `create_instrument_envelope_decode_vector_is_pinned_to_
|
||||
/// literal_bytes` above (the 3b-i lesson: round-trip locking alone cannot
|
||||
/// see a self-consistent encoder/decoder reorder). Each new payload
|
||||
/// carries exactly one field, so there are no adjacent fields to swap;
|
||||
/// the mutation this guards against is a swap of the two new
|
||||
/// **discriminants** (32 ↔ 33) in both the encoder and the decoder —
|
||||
/// self-consistent, so every round-trip test stays green, while these
|
||||
/// correctly-named literal vectors die.
|
||||
#[test]
|
||||
fn set_canvas_layout_defaults_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, 2, 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, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 72, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 128, 90, 64, 8, 0, 0, 0, 0, 0, 0, 0, 0, 144, 98, 64, 8, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 30, 64, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 64, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30,
|
||||
64, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 64,
|
||||
];
|
||||
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"
|
||||
);
|
||||
}
|
||||
|
||||
/// (s8) Same rationale as the sibling test above.
|
||||
#[test]
|
||||
fn set_spelling_precedence_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, 3, 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, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 9, 0, 0, 0, 5, 0, 0, 0, 4, 3, 2, 1, 0,
|
||||
];
|
||||
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"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ use epiphany_core::{
|
|||
LyricLineId, MarkerId, MeasureId, MusicalDuration, MusicalPosition, ObjectKindRegistryId,
|
||||
OperationId, PartDefinitionId, PitchId, RationalTime, RegionId, RepeatStructureId, ReplicaId,
|
||||
SlurId, SpannerId, StaffGroupId, StaffId, StaffInstanceId, TieId, TimeSignatureId,
|
||||
TransactionId, TupletId, TypedObjectId, ViewId, VoiceId, WallClockDuration, WallClockTime,
|
||||
TransactionId, TranspositionInterval, TupletId, TypedObjectId, ViewId, VoiceId,
|
||||
WallClockDuration, WallClockTime,
|
||||
};
|
||||
use epiphany_determinism::{
|
||||
CanonicalEncode, CanonicalF64, ChunkId, ContentHash, DomainTag, QuantizedCoord, Tolerance,
|
||||
|
|
@ -32,22 +33,23 @@ use epiphany_ops::valuegen;
|
|||
use epiphany_ops::{
|
||||
AnomalousReplicaSegment, AuthorId, CausalContext, ChangeRegionTimeModelOp, ConflictId,
|
||||
ConflictKind, ConflictKindRegistryId, ConflictRecord, ConflictRegistry,
|
||||
ConflictResolutionState, CreateCrossCuttingOp, 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, SetMetadataOp, SetMetricGridOp, SetStaffLayoutOp, SetTempoSegmentOp,
|
||||
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, SetUserPageBreakOp, SetUserSystemBreakOp, TransactionCategory,
|
||||
TransactionDescriptor, TransposeOp, TupletCompensation, TupletCompensationKind, UndoPolicy,
|
||||
UndoTransactionPayload,
|
||||
TransactionDescriptor, TransposeIntervalOp, TransposeOp, TupletCompensation,
|
||||
TupletCompensationKind, UndoPolicy, UndoTransactionPayload,
|
||||
};
|
||||
|
||||
use crate::rng::Rng;
|
||||
|
|
@ -644,7 +646,7 @@ pub fn operation_payload(rng: &mut Rng, events: u64, pitches: u64) -> OperationP
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
let kind = match rng.below(30) {
|
||||
let kind = match rng.below(34) {
|
||||
0 => {
|
||||
let pitches = if rng.boolean() {
|
||||
vec![obj_pitch(rng.below(pitches))]
|
||||
|
|
@ -846,6 +848,29 @@ pub fn operation_payload(rng: &mut Rng, events: u64, pitches: u64) -> OperationP
|
|||
28 => OperationKind::DeleteRepeatStructure(DeleteRepeatStructureOp {
|
||||
repeat: RepeatStructureId::new(OBJ_REPLICA, rng.below(2)),
|
||||
}),
|
||||
// Push 4a (previously absent from this corpus — see row 28's contract
|
||||
// note): the faithful transpose over the shared pitch-id space.
|
||||
29 => OperationKind::TransposeInterval(TransposeIntervalOp {
|
||||
targets: (0..1 + rng.below(2))
|
||||
.map(|_| obj_pitch(rng.below(pitches)))
|
||||
.collect(),
|
||||
interval: TranspositionInterval {
|
||||
diatonic_steps: rng.below(5) as i32 - 2,
|
||||
chromatic_steps: rng.below(9) as i32 - 4,
|
||||
},
|
||||
}),
|
||||
// Genesis tranche G1 (previously absent from this corpus — see row
|
||||
// 28's contract note): mint an instrument on the score root.
|
||||
30 => OperationKind::CreateInstrument(CreateInstrumentOp {
|
||||
instrument: valuegen::instrument(InstrumentId::new(OBJ_REPLICA, rng.below(2))),
|
||||
}),
|
||||
// Genesis tranche G2a: the two major-0 settings setters.
|
||||
31 => OperationKind::SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp {
|
||||
layout_defaults: valuegen::canvas_layout_defaults(rng.below(3) as u8),
|
||||
}),
|
||||
32 => OperationKind::SetSpellingPrecedence(SetSpellingPrecedenceOp {
|
||||
precedence: valuegen::spelling_precedence(rng.below(3) as u8),
|
||||
}),
|
||||
_ => OperationKind::Registered(
|
||||
OperationKindRegistryId(rng.next_u64() as u128),
|
||||
rng.byte_vec(0, 16),
|
||||
|
|
@ -1802,6 +1827,86 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
/// (s6, half) Genesis tranche G2a's boundary against G2b: both new
|
||||
/// setters are schema major 0 unconditionally, so a block carrying either
|
||||
/// stamps well within the `OperationEnvelopeBlock` accept-set no matter
|
||||
/// where that set's ceiling sits.
|
||||
///
|
||||
/// The other half of s6 — `max_supported_major(OperationEnvelopeBlock) ==
|
||||
/// 2` — is **not** assertable from this crate: `epiphany_bundle::
|
||||
/// max_supported_major` (`bundle.rs:67`) is defined in a private module
|
||||
/// (`mod bundle;`, not `pub mod`) and is not among `epiphany-bundle`'s
|
||||
/// `pub use` re-exports, so no outside crate can name it. Contract pin 4a
|
||||
/// forbids touching `epiphany-bundle` in this packet (not even to add a
|
||||
/// re-export), so that half of s6 is verified by reading
|
||||
/// `crates/epiphany-bundle/src/bundle.rs:69` directly (`ChunkKind::
|
||||
/// OperationEnvelopeBlock => 2`, unedited by this packet) rather than by
|
||||
/// a compiled assertion — a deviation from the contract's "assert it in
|
||||
/// code" phrasing, reported rather than worked around.
|
||||
///
|
||||
/// **Mutation:** stamp a payload carrying either new kind at a non-zero
|
||||
/// major (as if it had been wrongly placed in the `=> 2` arm alongside
|
||||
/// `SetMetadata`, exactly the bug pin 3 and test s5 both name) — this
|
||||
/// assertion fires.
|
||||
#[test]
|
||||
fn the_two_new_settings_kinds_stamp_within_the_accept_set() {
|
||||
for major in [
|
||||
OperationKind::SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp {
|
||||
layout_defaults: valuegen::canvas_layout_defaults(1),
|
||||
})
|
||||
.schema_major(),
|
||||
OperationKind::SetSpellingPrecedence(SetSpellingPrecedenceOp {
|
||||
precedence: valuegen::spelling_precedence(1),
|
||||
})
|
||||
.schema_major(),
|
||||
] {
|
||||
assert_eq!(major, 0, "both new kinds must stamp at major 0");
|
||||
}
|
||||
}
|
||||
|
||||
/// (s10, row 28) `operation_payload`'s bounded draw is a hand-maintained
|
||||
/// arm list over `rng.below(N)`, which nothing forces to move when the
|
||||
/// operation vocabulary grows — exactly how `TransposeInterval` (kind 30,
|
||||
/// 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..=33),
|
||||
/// not just that the function does not panic.
|
||||
#[test]
|
||||
fn operation_payload_emits_every_appended_kind() {
|
||||
let mut rng = Rng::new(17);
|
||||
let (mut saw_transpose_interval, mut saw_create_instrument) = (false, false);
|
||||
let (mut saw_canvas_layout_defaults, mut saw_spelling_precedence) = (false, false);
|
||||
for _ in 0..2000 {
|
||||
let OperationPayload::Primitive(kind) = operation_payload(&mut rng, 8, 8) else {
|
||||
continue;
|
||||
};
|
||||
match kind {
|
||||
OperationKind::TransposeInterval(_) => saw_transpose_interval = true,
|
||||
OperationKind::CreateInstrument(_) => saw_create_instrument = true,
|
||||
OperationKind::SetCanvasLayoutDefaults(_) => saw_canvas_layout_defaults = true,
|
||||
OperationKind::SetSpellingPrecedence(_) => saw_spelling_precedence = true,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
assert!(
|
||||
saw_transpose_interval,
|
||||
"TransposeInterval (kind 30) never drawn in 2000 samples"
|
||||
);
|
||||
assert!(
|
||||
saw_create_instrument,
|
||||
"CreateInstrument (kind 31) never drawn in 2000 samples"
|
||||
);
|
||||
assert!(
|
||||
saw_canvas_layout_defaults,
|
||||
"SetCanvasLayoutDefaults (kind 32) never drawn in 2000 samples"
|
||||
);
|
||||
assert!(
|
||||
saw_spelling_precedence,
|
||||
"SetSpellingPrecedence (kind 33) never drawn in 2000 samples"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn frontier_uses_the_real_dvv_encoding_and_preserves_gaps() {
|
||||
let mut rng = Rng::new(11);
|
||||
|
|
|
|||
|
|
@ -950,40 +950,25 @@ pub fn gen_vertical_band(rng: &mut Rng) -> VerticalBand {
|
|||
|
||||
/// An operation-kind tag (every variant Agent C's type provides, including the
|
||||
/// registered form).
|
||||
///
|
||||
/// Genesis tranche G2a (row 29): **derived**, not hand-maintained. The prior
|
||||
/// hand-written `match` had already gone stale twice — it stopped at 23 until
|
||||
/// the Phase-3 tranche and again omitted the repeat pair — because nothing
|
||||
/// forces a hand-written arm list to move when the vocabulary grows, even
|
||||
/// though this generator's own doc promises *every* variant. Built-ins are
|
||||
/// drawn uniformly from `OperationKindTag::PAYLOAD_FREE`
|
||||
/// (`operation_kind_tag_vocabulary!`'s single source of truth, `payload.rs`) —
|
||||
/// `Registered` is excluded from `PAYLOAD_FREE` by design (it carries a
|
||||
/// payload, `payload.rs:469`) and is appended here explicitly. Every future
|
||||
/// built-in append then follows structurally, with no edit to this function;
|
||||
/// see `OperationKind::discriminant()`'s in-crate precedent
|
||||
/// (`payload.rs:2052`, `all_tags`).
|
||||
pub fn gen_operation_kind_tag(rng: &mut Rng) -> OperationKindTag {
|
||||
match rng.below(30) {
|
||||
0 => OperationKindTag::InsertEvent,
|
||||
1 => OperationKindTag::DeleteEvent,
|
||||
2 => OperationKindTag::ModifyEvent,
|
||||
3 => OperationKindTag::RespellPitch,
|
||||
4 => OperationKindTag::Transpose,
|
||||
5 => OperationKindTag::CreateCrossCutting,
|
||||
6 => OperationKindTag::DeleteCrossCutting,
|
||||
7 => OperationKindTag::ModifyCrossCutting,
|
||||
8 => OperationKindTag::ChangeRegionTimeModel,
|
||||
9 => OperationKindTag::InsertRegion,
|
||||
10 => OperationKindTag::DeleteRegion,
|
||||
11 => OperationKindTag::InsertStaffInstance,
|
||||
12 => OperationKindTag::DeleteStaffInstance,
|
||||
13 => OperationKindTag::SetUserSystemBreak,
|
||||
14 => OperationKindTag::SetUserPageBreak,
|
||||
15 => OperationKindTag::DeclareTransaction,
|
||||
16 => OperationKindTag::InsertIdentifiedPitch,
|
||||
17 => OperationKindTag::DeleteIdentifiedPitch,
|
||||
18 => OperationKindTag::ModifyIdentifiedPitch,
|
||||
19 => OperationKindTag::CreateVoice,
|
||||
20 => OperationKindTag::DeleteVoice,
|
||||
21 => OperationKindTag::SetMetadata,
|
||||
22 => OperationKindTag::SetMetricGrid,
|
||||
// The appended vocabulary: the Phase-3 tranche (24..=27) — this
|
||||
// generator had gone stale at 23 — and the repeat pair (28/29).
|
||||
23 => OperationKindTag::InsertStaff,
|
||||
24 => OperationKindTag::SetTimeSignature,
|
||||
25 => OperationKindTag::SetTempoSegment,
|
||||
26 => OperationKindTag::SetStaffLayout,
|
||||
27 => OperationKindTag::CreateRepeatStructure,
|
||||
28 => OperationKindTag::DeleteRepeatStructure,
|
||||
_ => OperationKindTag::Registered(epiphany_ops::OperationKindRegistryId(
|
||||
// +1 slot for `Registered`, drawn last.
|
||||
let index = rng.below(OperationKindTag::PAYLOAD_FREE.len() as u64 + 1) as usize;
|
||||
match OperationKindTag::PAYLOAD_FREE.get(index) {
|
||||
Some(tag) => *tag,
|
||||
None => OperationKindTag::Registered(epiphany_ops::OperationKindRegistryId(
|
||||
rng.next_u64() as u128
|
||||
)),
|
||||
}
|
||||
|
|
@ -1385,6 +1370,34 @@ mod tests {
|
|||
use epiphany_core::TypedObjectId;
|
||||
use epiphany_determinism::CanonicalEncode;
|
||||
|
||||
/// (s10, row 29) `gen_operation_kind_tag`'s draw must cover exactly
|
||||
/// `PAYLOAD_FREE` ∪ `{Registered}` — **not** merely the appended
|
||||
/// discriminants 30..=33, 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.
|
||||
#[test]
|
||||
fn gen_operation_kind_tag_covers_payload_free_and_registered() {
|
||||
let mut rng = Rng::new(0x6E_57_A9);
|
||||
let mut saw_registered = false;
|
||||
let mut seen_builtins = std::collections::BTreeSet::new();
|
||||
for _ in 0..5000 {
|
||||
match gen_operation_kind_tag(&mut rng) {
|
||||
OperationKindTag::Registered(_) => saw_registered = true,
|
||||
other => {
|
||||
seen_builtins.insert(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert!(saw_registered, "Registered never drawn in 5000 samples");
|
||||
let expected: std::collections::BTreeSet<_> =
|
||||
OperationKindTag::PAYLOAD_FREE.iter().copied().collect();
|
||||
assert_eq!(
|
||||
seen_builtins, expected,
|
||||
"the draw's built-in coverage must be exactly PAYLOAD_FREE"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edit_barrier_blob_codec_round_trips_generated_barriers() {
|
||||
// Property gate for the provisional manifest-blob byte form
|
||||
|
|
|
|||
|
|
@ -304,13 +304,14 @@ fn the_kind_productions_are_the_operation_vocabulary() {
|
|||
// The count is still hand-maintained, which is the same shape the comment
|
||||
// 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`). 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.
|
||||
// `CreateInstrument`; genesis G2a takes it from 32 to 34 by adding
|
||||
// `SetCanvasLayoutDefaults` and `SetSpellingPrecedence`). 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(),
|
||||
32,
|
||||
"31 payload-free kinds plus `Registered`"
|
||||
34,
|
||||
"33 payload-free kinds plus `Registered`"
|
||||
);
|
||||
|
||||
let actual = alternatives("kind");
|
||||
|
|
|
|||
|
|
@ -26,7 +26,12 @@ use epiphany_ops::OperationEnvelope;
|
|||
/// without moving this constant would leave two incompatible grammars both
|
||||
/// claiming `(0 7 0)`. Cached projections do not migrate: a `TextProjection`
|
||||
/// chunk is a non-canonical accelerator, so a stale one is regenerated.
|
||||
pub const COMPANION_VERSION: (u32, u32, u32) = (0, 8, 0);
|
||||
///
|
||||
/// Bumped again 0.8.0 → 0.9.0 by the genesis tranche G2a, which appended
|
||||
/// `set-canvas-layout-defaults` and `set-spelling-precedence` to the `kind`
|
||||
/// production — the same reasoning: extending the grammar without moving this
|
||||
/// constant would leave two incompatible grammars both claiming `(0 8 0)`.
|
||||
pub const COMPANION_VERSION: (u32, u32, u32) = (0, 9, 0);
|
||||
|
||||
/// A parsed canonical Text Projection document.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -642,11 +642,12 @@ mod tests {
|
|||
out
|
||||
}
|
||||
|
||||
// Bumped with `COMPANION_VERSION` (0.7.0 → 0.8.0, genesis G1). 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 8 0))";
|
||||
// Bumped with `COMPANION_VERSION` (0.7.0 → 0.8.0, genesis G1; 0.8.0 →
|
||||
// 0.9.0, genesis G2a). 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 9 0))";
|
||||
const DOCUMENT: &str = "(document #x00000000000000000000000000000001)";
|
||||
|
||||
/// A minimal but complete valid projection: just the two mandatory lines.
|
||||
|
|
@ -851,6 +852,28 @@ mod tests {
|
|||
assert!(parse_document(&minimal_valid_document()).is_ok());
|
||||
}
|
||||
|
||||
/// (s9) Genesis tranche G2a (`spec/CONTRACT_GENESIS_G2A_SETTINGS.md`):
|
||||
/// `(0 8 0)` — the version this crate implemented *before* this
|
||||
/// packet's `kind` grammar extension — must now be rejected, not merely
|
||||
/// "some other version". This is the specific case
|
||||
/// `req:textproj:header-version`'s reject-all-others clause exists to
|
||||
/// guard, and it is the one a lenient "any `(0 x 0)`" parser would still
|
||||
/// pass.
|
||||
///
|
||||
/// **Mutation:** widen the parser's version check from an exact `!=
|
||||
/// COMPANION_VERSION` to accept any `(0 _ 0)` (e.g. `major == 0`) -> this
|
||||
/// test dies, since `(0 8 0)` would then parse.
|
||||
#[test]
|
||||
fn the_immediately_superseded_companion_version_is_rejected() {
|
||||
let text = projection(&["(text-projection (0 8 0))", DOCUMENT]);
|
||||
assert_eq!(
|
||||
parse_document(&text),
|
||||
Err(TextError::NotCanonical(
|
||||
"the header names a companion version other than the one this crate implements"
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_blob_line_is_always_rejected() {
|
||||
let blob_line = "(blob \"audio/wav\" () #x00)";
|
||||
|
|
|
|||
|
|
@ -323,16 +323,16 @@ pub fn document_vectors() -> Vec<TextVector> {
|
|||
.collect();
|
||||
|
||||
// The rejected version must be one this crate does NOT implement. Genesis
|
||||
// G1 moved `COMPANION_VERSION` to 0.8.0, which had been this vector's
|
||||
// G2a moved `COMPANION_VERSION` to 0.9.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.7.0, the
|
||||
// that the *correct* header is rejected. It now names 0.8.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 9 0))",
|
||||
"(text-projection (0 8 0))",
|
||||
"(text-projection (0 7 0))",
|
||||
);
|
||||
vectors.push((
|
||||
SURFACE,
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -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.11.0 --- The decode vector corpus extends to the core score wire}\\[4pt]
|
||||
{\normalsize\color{epiphanyink}Version 0.12.0 --- The genesis operation tranche reaches the wire (G1 + G2a)}\\[4pt]
|
||||
{\small\color{epiphanyslate}Normative for the byte layouts it defines}
|
||||
\vfill
|
||||
\end{titlepage}
|
||||
|
|
@ -1445,6 +1445,16 @@ and the reader disagree about the field's type.
|
|||
\texttt{diatonic\_steps} (\texttt{i32} LE, 4) \cat{}
|
||||
\texttt{chromatic\_steps} (\texttt{i32} LE, 4) &
|
||||
\sectionsc{TransposeInterval} \\
|
||||
\tablenums{31} & \texttt{CreateInstrument} &
|
||||
$\mathrm{lp}$(\texttt{Instrument}) --- the schema-major-2 layout,
|
||||
unconditionally (born at v2; Section~\ref{sec:evolution:major2}) &
|
||||
\sectionsc{CreateInstrument} \\
|
||||
\tablenums{32} & \texttt{SetCanvasLayoutDefaults} &
|
||||
$\mathrm{lp}$(\texttt{CanvasLayoutDefaults}) &
|
||||
\sectionsc{SetCanvasLayoutDefaults} \\
|
||||
\tablenums{33} & \texttt{SetSpellingPrecedence} &
|
||||
$\mathrm{lp}$(\texttt{SpellingPrecedence}) &
|
||||
\sectionsc{SetSpellingPrecedence} \\
|
||||
\bottomrule
|
||||
\end{longtable}
|
||||
\endgroup
|
||||
|
|
@ -1513,7 +1523,8 @@ discriminants and wrong lengths are decode errors. Append-only past
|
|||
\tablenums{24} & \texttt{InsertStaff} & \tablenums{25} & \texttt{SetTimeSignature} \\
|
||||
\tablenums{26} & \texttt{SetTempoSegment} & \tablenums{27} & \texttt{SetStaffLayout} \\
|
||||
\tablenums{28} & \texttt{CreateRepeatStructure} & \tablenums{29} & \texttt{DeleteRepeatStructure} \\
|
||||
\tablenums{30} & \texttt{TransposeInterval} & & \\
|
||||
\tablenums{30} & \texttt{TransposeInterval} & \tablenums{31} & \texttt{CreateInstrument} \\
|
||||
\tablenums{32} & \texttt{SetCanvasLayoutDefaults} & \tablenums{33} & \texttt{SetSpellingPrecedence} \\
|
||||
\bottomrule
|
||||
\end{longtable}
|
||||
\endgroup
|
||||
|
|
@ -2426,13 +2437,27 @@ The three added fields land in different chunk classes, and the major is
|
|||
assigned \textbf{per payload type}, not per chunk kind:
|
||||
|
||||
\begin{itemize}
|
||||
\item \texttt{Canvas.layout\_defaults} and \texttt{Instrument.range} appear
|
||||
\emph{only} in the acceleration-cache full-\texttt{Score} snapshot (a
|
||||
\texttt{ChunkKind::Snapshot}). No operation payload embeds a
|
||||
\texttt{Canvas} or an \texttt{Instrument} value (there is no
|
||||
\texttt{CreateCanvas}/\texttt{CreateInstrument}; canvas is the inline
|
||||
genesis singleton and instruments live in score genesis), so these two
|
||||
are confined to that one \textbf{non-canonical} chunk.
|
||||
\item \texttt{Canvas.layout\_defaults} and \texttt{Instrument.range} now
|
||||
also reach the \textbf{canonical operation layer}, each by a different
|
||||
genesis-tranche operation. \texttt{Instrument.range}: genesis tranche G1's
|
||||
\texttt{CreateInstrument} (\S\ref{sec:ops:kinds} discriminant
|
||||
\tablenums{31}) embeds the full \texttt{Instrument} value, whose
|
||||
schema-major-2 appends are mandatory --- so this payload always carries
|
||||
the complete (major-2) \texttt{Instrument} layout, \texttt{range}
|
||||
included, and a block carrying it is stamped \textbf{major~2}
|
||||
unconditionally, never merely major~1.
|
||||
\texttt{Canvas.layout\_defaults}: genesis tranche G2a's
|
||||
\texttt{SetCanvasLayoutDefaults} (discriminant \tablenums{32}) embeds the
|
||||
full \texttt{CanvasLayoutDefaults} value directly, rather than through the
|
||||
containing \texttt{Canvas} walk that carries the major-1 versioning ---
|
||||
\texttt{CanvasLayoutDefaults} has exactly one layout as a standalone
|
||||
value, so a block carrying this operation is stamped \textbf{major~0}.
|
||||
What remains confined to the \textbf{non-canonical} acceleration-cache
|
||||
full-\texttt{Score} snapshot (a \texttt{ChunkKind::Snapshot}) is the
|
||||
canvas \emph{object itself}: there is still no \texttt{CreateCanvas}, no
|
||||
\texttt{TypedObjectId} kind for it, and no operation mints, addresses, or
|
||||
deletes it --- the canvas is the inline genesis singleton, and that half
|
||||
of the earlier claim survives.
|
||||
\item \texttt{Region.permits\_spanning\_slurs} reaches the snapshot
|
||||
\emph{and} the \textbf{canonical operation layer}:
|
||||
\texttt{CreateRegion} embeds the full \texttt{Region} value
|
||||
|
|
@ -2596,19 +2621,29 @@ are defined in the same core revision; their wire layouts are below.
|
|||
The major is assigned per payload type, exactly as in major~1:
|
||||
|
||||
\begin{itemize}
|
||||
\item \textbf{Snapshot-only:} \texttt{Instrument} (no operation embeds
|
||||
one); it reaches only the acceleration full-\texttt{Score} snapshot.
|
||||
(\texttt{RepeatStructure} was snapshot-only when this section was
|
||||
first ratified; the repeat-authoring pair moved it to the canonical
|
||||
operation layer --- next bullet.)
|
||||
\item \textbf{Canonical operation layer:} eight operation
|
||||
payloads embed filled values. \texttt{CreateRepeatStructure} (this
|
||||
revision --- Operation Catalog \sectionsc{Repeat Structures},
|
||||
discriminant \tablenums{28}) embeds the v2 \texttt{RepeatStructure}
|
||||
layout unconditionally (\texttt{kind} and \texttt{voltas} are not
|
||||
optional fields) and is \emph{born at v2}: no lower-major layout for
|
||||
its payload exists, so every block carrying one stamps major~2 under
|
||||
minimal stamping. Its sibling \texttt{DeleteRepeatStructure}
|
||||
\item \textbf{Snapshot-only:} nothing, as of genesis tranche G1.
|
||||
\texttt{Instrument} was snapshot-only when this section was first
|
||||
ratified (no operation embedded one; it reached only the acceleration
|
||||
full-\texttt{Score} snapshot) and \texttt{RepeatStructure} likewise,
|
||||
until the repeat-authoring pair moved it to the canonical operation
|
||||
layer. \texttt{CreateInstrument} (genesis tranche G1, discriminant
|
||||
\tablenums{31}) moved \texttt{Instrument} the same way --- see the next
|
||||
bullet, which now names it.
|
||||
\item \textbf{Canonical operation layer:} nine operation
|
||||
payloads embed filled values. \texttt{CreateInstrument} (genesis
|
||||
tranche G1 --- Operation Catalog \sectionsc{CreateInstrument},
|
||||
discriminant \tablenums{31}) embeds the full \texttt{Instrument} value;
|
||||
its schema-major-2 appends (\texttt{sound\_config},
|
||||
\texttt{default\_clef}, \texttt{default\_staff\_lines}, and the rest)
|
||||
are mandatory fields, not \texttt{Option}-hidden, so it is
|
||||
\emph{born at v2} exactly as \texttt{CreateRepeatStructure} below is ---
|
||||
no lower-major layout for this payload exists, and every block
|
||||
carrying one stamps major~2 under minimal stamping.
|
||||
\texttt{CreateRepeatStructure} (Operation Catalog
|
||||
\sectionsc{Repeat Structures}, discriminant \tablenums{28}) embeds the
|
||||
v2 \texttt{RepeatStructure} layout unconditionally (\texttt{kind} and
|
||||
\texttt{voltas} are not optional fields) and is likewise \emph{born at
|
||||
v2}. Its sibling \texttt{DeleteRepeatStructure}
|
||||
(\tablenums{29}) carries a bare identifier --- a major-0 layout ---
|
||||
so minimal stamping gives its blocks major~0; the kind discriminant
|
||||
itself is an append-only schema-\emph{minor} vocabulary event (the
|
||||
|
|
@ -2617,8 +2652,8 @@ The major is assigned per payload type, exactly as in major~1:
|
|||
kind's blocks \emph{stamp} always follows minimal stamping over its
|
||||
payload, as discriminant \tablenums{24}'s always-major-2
|
||||
\texttt{CreateStaff} shows). Neither changes anything about
|
||||
lower-major layouts. The seven payloads of the first ratification
|
||||
embed filled values ---
|
||||
lower-major layouts. The seven remaining payloads of the first
|
||||
ratification embed filled values ---
|
||||
\texttt{CreateCrossCutting} and \texttt{ModifyCrossCutting} (a
|
||||
\texttt{CrossCuttingValue} embedding \texttt{Slur}, \texttt{Tie},
|
||||
\texttt{Beam}, or \texttt{Spanner}); \texttt{CreateStaff} (a
|
||||
|
|
@ -2634,7 +2669,9 @@ The major is assigned per payload type, exactly as in major~1:
|
|||
embedding the filled \texttt{StaffLineConfiguration}. (Reduction
|
||||
preconditions a \emph{carried} region to be empty of typed children,
|
||||
but the byte form is representable and preserved in the canonical
|
||||
set, so the wire must define it.)
|
||||
set, so the wire must define it.) That is
|
||||
$1~(\texttt{CreateInstrument}) + 1~(\texttt{CreateRepeatStructure}) +
|
||||
7 = 9$ payloads total.
|
||||
|
||||
\textbf{Minimal stamping.} A writer \MUST{} stamp each
|
||||
operation-envelope block with the \emph{lowest} schema major whose
|
||||
|
|
@ -3475,6 +3512,35 @@ only}: implementations need not agree on an error taxonomy.
|
|||
order, which previously passed round-trip locking and 8/8 conformance).
|
||||
No wire layout changed; no existing vector's bytes moved
|
||||
(\texttt{spec/CONTRACT\_CORE\_DECODE\_VECTORS.md}). \\
|
||||
\today & Operation wire forms & 0.12.0 --- Genesis tranche G2a
|
||||
(\texttt{spec/CONTRACT\_GENESIS\_G2A\_SETTINGS.md}), plus the repair of a
|
||||
G1 omission this document's own contract wrongly declared out of scope.
|
||||
Appends \texttt{OperationKind} wire discriminants \tablenums{31}
|
||||
(\texttt{CreateInstrument}, genesis tranche G1 --- landed at
|
||||
\texttt{3b09595} with no matching entry here), \tablenums{32}
|
||||
(\texttt{SetCanvasLayoutDefaults}), and \tablenums{33}
|
||||
(\texttt{SetSpellingPrecedence}), with their payload layouts, and the
|
||||
matching \texttt{OperationKindTag} discriminants \tablenums{31}--\tablenums{33}
|
||||
(name-verbatim projection, as the two most recent prior additions are) ---
|
||||
schema-\emph{minor} evolutions under this document's own append-only
|
||||
rules; no existing assignment changed. \texttt{CreateInstrument} embeds
|
||||
the full \texttt{Instrument} value and is \emph{born at v2}
|
||||
unconditionally (Section~\ref{sec:evolution:major2}), which the
|
||||
Section~\ref{sec:evolution:major1}/\ref{sec:evolution:major2}
|
||||
``Where the changed fields reach'' bullets are corrected to name: neither
|
||||
\texttt{Instrument} nor \texttt{Canvas.layout\_defaults} is
|
||||
snapshot-only any longer, and the \sectionsc{Schema Major 2} canonical
|
||||
operation-layer count moves from eight payloads to nine. Both new G2a
|
||||
payloads --- \texttt{SetCanvasLayoutDefaultsOp} and
|
||||
\texttt{SetSpellingPrecedenceOp} --- carry only major-0 layouts (neither
|
||||
carried type has ever been versioned as a standalone value), so no
|
||||
accept-set moves: \texttt{OperationEnvelopeBlock} stays at
|
||||
\tablenums{2}. The chunk schema \emph{minor} is knowingly still not
|
||||
stamped for any of \tablenums{24}--\tablenums{33} (filed as P13-S14, a
|
||||
retroactive sweep sequenced after this rung). Semantics: Operation
|
||||
Catalog \sectionsc{CreateInstrument} (retroactive),
|
||||
\sectionsc{SetCanvasLayoutDefaults}, \sectionsc{SetSpellingPrecedence},
|
||||
0.10.0. \\
|
||||
\bottomrule
|
||||
\end{longtable}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -5110,17 +5110,29 @@ pub struct CueEvent {
|
|||
|
||||
The canvas is the spatial root of the score. It contains regions.
|
||||
|
||||
The score root and the canvas are \emph{structural givens}, not
|
||||
operation products (ratified Pass~12): genesis is the creation of an
|
||||
empty score together with its bundle, outside the operation set, and
|
||||
neither object is ever minted, addressed, or deleted by an operation
|
||||
(there is no \texttt{TypedObjectId} kind for either). This is
|
||||
The score root and the canvas remain \emph{structural givens}, not
|
||||
operation products (ratified Pass~12; narrowed by
|
||||
\texttt{spec/RULING\_GENESIS\_PERSISTENCE.md}): neither object is ever
|
||||
minted, addressed, or deleted by an operation, and there is still no
|
||||
\texttt{TypedObjectId} kind for either. This is
|
||||
deliberate --- a document that could mint its own root would admit a
|
||||
genesis race under concurrent editing, and every operation would need
|
||||
a defined semantics against a not-yet-existing root. The decision may
|
||||
be revisited only if an addressable multi-canvas model is adopted at
|
||||
a future schema major.
|
||||
|
||||
What the genesis ruling reverses is the narrower claim this paragraph used
|
||||
to make alongside the above: that the score's \emph{contents} also arrive
|
||||
outside the operation set, as part of the same empty-score-plus-bundle
|
||||
genesis act. They do not. Every mutable field of \texttt{Score} becomes
|
||||
operation-authored under the genesis tranche
|
||||
(\texttt{spec/PLAN\_GENESIS\_OPS.md}): a document created empty
|
||||
(\texttt{Score::empty}) and given only operations can materialize a
|
||||
note-bearing score, reaching \texttt{Canvas.layout\_defaults}
|
||||
and \texttt{Score.spelling\_precedence} (genesis tranche G2a) among other
|
||||
surfaces. The root and the canvas themselves are the load-bearing
|
||||
exception that survives intact.
|
||||
|
||||
\begin{lstlisting}[language=Rust]
|
||||
pub struct Canvas {
|
||||
/// Regions in this canvas. Each region declares its time and
|
||||
|
|
@ -6911,6 +6923,8 @@ pub enum OperationKind {
|
|||
// Pitch and tuning operations
|
||||
RespellPitch(RespellPitchOp),
|
||||
Transpose(TransposeOp),
|
||||
// The faithful transposition (Push 4a); Transpose above is frozen.
|
||||
TransposeInterval(TransposeIntervalOp),
|
||||
InsertIdentifiedPitch(InsertIdentifiedPitchOp),
|
||||
DeleteIdentifiedPitch(DeleteIdentifiedPitchOp),
|
||||
ModifyIdentifiedPitch(ModifyIdentifiedPitchOp),
|
||||
|
|
@ -6934,6 +6948,10 @@ pub enum OperationKind {
|
|||
CreateVoice(CreateVoiceOp),
|
||||
DeleteVoice(DeleteVoiceOp),
|
||||
|
||||
// Genesis tranche G1: mints an abstract instrument on the score root ---
|
||||
// the single missing link between Score::empty and a note.
|
||||
CreateInstrument(CreateInstrumentOp),
|
||||
|
||||
// Metric-model operations
|
||||
SetTimeSignature(SetTimeSignatureOp),
|
||||
SetTempoSegment(SetTempoSegmentOp),
|
||||
|
|
@ -6941,6 +6959,10 @@ pub enum OperationKind {
|
|||
|
||||
// Score settings
|
||||
SetMetadata(SetMetadataOp),
|
||||
// Genesis tranche G2a: the two major-0 settings setters, on the
|
||||
// SetMetadata advisory-LWW pattern.
|
||||
SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp),
|
||||
SetSpellingPrecedence(SetSpellingPrecedenceOp),
|
||||
|
||||
// Layout-semantic operations
|
||||
SetUserSystemBreak(SetUserSystemBreakOp),
|
||||
|
|
@ -11900,6 +11922,15 @@ pub enum OperationKindTag {
|
|||
// its kind names verbatim, as the cross-cutting tags do.
|
||||
CreateRepeatStructure,
|
||||
DeleteRepeatStructure,
|
||||
// Push 4a: the faithful transpose. Transpose above is frozen.
|
||||
TransposeInterval,
|
||||
// Genesis tranche G1: name-verbatim, as the two most recent prior
|
||||
// additions are (the tag layer's older Create-to-Insert convention is
|
||||
// not followed here).
|
||||
CreateInstrument,
|
||||
// Genesis tranche G2a: the two major-0 settings setters.
|
||||
SetCanvasLayoutDefaults,
|
||||
SetSpellingPrecedence,
|
||||
}
|
||||
|
||||
pub enum BarrierScope {
|
||||
|
|
@ -12183,11 +12214,17 @@ non-canonical resolved-layout length-prefix width. Its wire form and the
|
|||
byte-for-byte migration from major~0 are defined in the Binary Format
|
||||
companion. The canonical-base \texttt{MaterializedState} embeds none of these
|
||||
values, so it is byte-identical across the bump and stays major~0.
|
||||
\texttt{Canvas.layout\_defaults} and \texttt{Instrument.range} reach only the
|
||||
non-canonical acceleration (full-\texttt{Score}) snapshot; but
|
||||
\texttt{Region.permits\_spanning\_slurs} also reaches the \emph{canonical}
|
||||
operation layer, because \texttt{CreateRegion} embeds a full \texttt{Region},
|
||||
so an operation-envelope block bearing a v1 \texttt{CreateRegion} is major~1.
|
||||
(As of the genesis operation tranche, \texttt{Canvas.layout\_defaults} and
|
||||
\texttt{Instrument.range} do too --- \texttt{SetCanvasLayoutDefaults}
|
||||
(G2a) and \texttt{CreateInstrument} (G1) embed the values directly --- but
|
||||
neither of those two payloads is itself major~1: the leaf value each embeds
|
||||
has exactly one layout, versioned only through the containing
|
||||
\texttt{Canvas}/\texttt{Instrument} walk, not through this schema-major-1
|
||||
bump. See the Binary Format companion \sectionsc{Schema Major 1} /
|
||||
\sectionsc{Schema Major 2} for the operation-by-operation accounting.)
|
||||
Consequently a major-0-only reader opens a major-1 bundle \emph{fully} only
|
||||
when the bundle carries no v1 \texttt{CreateRegion} operation; otherwise it
|
||||
reads the major-0 canonical base and manifest but opens read-only (it cannot
|
||||
|
|
@ -12204,7 +12241,7 @@ truncated bodies of the cross-cutting structures (\texttt{Slur},
|
|||
Chapter~5 definitions. The same per-payload-type rules apply: the
|
||||
canonical-base \texttt{MaterializedState} embeds none of these values and
|
||||
stays major~0; the filled values reach the acceleration snapshot
|
||||
\emph{and}, through the eight operation payloads that embed them
|
||||
\emph{and}, through the nine operation payloads that embed them
|
||||
(\texttt{CreateCrossCutting}, \texttt{ModifyCrossCutting},
|
||||
\texttt{InsertStaff} and \texttt{InsertStaffInstance} (the Operation
|
||||
Catalog's \texttt{CreateStaff} / \texttt{CreateStaffInstance}),
|
||||
|
|
@ -12213,11 +12250,17 @@ Catalog's \texttt{CreateStaff} / \texttt{CreateStaffInstance}),
|
|||
embeds the filled \texttt{RepeatStructure} unconditionally, so it is
|
||||
\emph{born at v2} and every block carrying one stamps major~2; its
|
||||
\texttt{DeleteRepeatStructure} sibling carries a bare identifier, a
|
||||
major-0 layout, and stamps major~0), and --- transitively,
|
||||
major-0 layout, and stamps major~0), \texttt{CreateInstrument} (genesis
|
||||
tranche G1 --- it embeds the filled \texttt{Instrument} unconditionally, so
|
||||
it too is \emph{born at v2}), and --- transitively,
|
||||
because an embedded \texttt{Region} may carry a \texttt{StaffInstance}
|
||||
whose \texttt{staff\_lines\_override} embeds the filled
|
||||
\texttt{StaffLineConfiguration} --- \texttt{InsertRegion}
|
||||
(\texttt{CreateRegion})), the canonical operation layer. A block is
|
||||
(\texttt{CreateRegion})), the canonical operation layer. That is nine:
|
||||
\texttt{CreateCrossCutting}, \texttt{ModifyCrossCutting},
|
||||
\texttt{InsertStaff}, \texttt{InsertStaffInstance}, \texttt{SetStaffLayout},
|
||||
\texttt{SetMetadata}, \texttt{CreateRepeatStructure}, \texttt{CreateInstrument},
|
||||
and \texttt{InsertRegion}. A block is
|
||||
stamped with the \emph{lowest} schema major whose layouts decode its
|
||||
bytes (the companion's minimal-stamping rule --- deterministic, so
|
||||
identical content hashes identically): any v2-dependent bytes make it
|
||||
|
|
@ -16426,7 +16469,11 @@ layouts they own versus inherit:
|
|||
the corresponding wire discriminants. This document's
|
||||
\texttt{OperationKind} listing gains the four kinds. The create
|
||||
score/canvas slots remain deliberately unavailable pending an
|
||||
addressable root model (P12-K8).
|
||||
addressable root model (P12-K8). (Reversed in part by
|
||||
\texttt{spec/RULING\_GENESIS\_PERSISTENCE.md}, ratified with the genesis
|
||||
operation tranche: the root/canvas \emph{objects} stay unavailable as
|
||||
ratified here, but the score's \emph{contents} are no longer outside the
|
||||
operation set --- see \sectionsc{The Canvas}, \S\ref{sec:graph:canvas}.)
|
||||
\\
|
||||
\today & Schema major 1 (data-model expansion) &
|
||||
Defines the two referenced-but-undefined types
|
||||
|
|
@ -16473,7 +16520,10 @@ layouts they own versus inherit:
|
|||
inference-ineligible targets surface
|
||||
(Requirement~\ref{req:pitch:authored-uninferred}, P12-H7). Identity:
|
||||
system-derived intrinsic content immutable under reduction (P12-K3). Genesis
|
||||
ratified outside the operation set (P12-K8). Cross-region slur permission =
|
||||
ratified outside the operation set (P12-K8 --- reversed in part by
|
||||
\texttt{spec/RULING\_GENESIS\_PERSISTENCE.md}, as annotated above: the
|
||||
root/canvas objects stay unavailable, the score's contents no longer do).
|
||||
Cross-region slur permission =
|
||||
AND (P12-K12). Re-anchoring: cue cascade-on-any-source, Range truncate
|
||||
defined, annotation orphaning sanctioned, \texttt{ReanchorReason::
|
||||
SameCanvasNearer} appended (P12-C1/C2/C3/C4). Barriers: target-free and
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -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.9.0 --- Space-relative CMN transposition}\\[4pt]
|
||||
{\normalsize\color{epiphanyink}Version 0.10.0 --- The genesis operation tranche (G1 + G2a)}\\[4pt]
|
||||
{\small\color{epiphanyslate}Normative for the operation kinds it defines}
|
||||
\vfill
|
||||
\end{titlepage}
|
||||
|
|
@ -343,6 +343,45 @@ resolution in Push~4b. No payload bytes change and no
|
|||
\texttt{PreconditionFailureReason} is appended; assignments 10 through 15
|
||||
remain exactly as ratified.
|
||||
|
||||
\medskip
|
||||
|
||||
\noindent\textbf{Version 0.10.0, first half (genesis tranche G1,
|
||||
retroactively recorded).} \texttt{CreateInstrument}
|
||||
(Section~\ref{sec:k0:create-instrument}) landed at commit \texttt{3b09595}
|
||||
without a version bump or a changelog paragraph, against this document's own
|
||||
convention above --- an omission genesis tranche G2a repairs here rather than
|
||||
silently. Adds one operation kind, \texttt{CreateInstrument}, mint-only
|
||||
(set-union creation, no delete in this catalogue revision) on the score root,
|
||||
carrying the full \texttt{Instrument} value. It is the single missing link
|
||||
between an empty score (\texttt{Score::empty}) and a note: \texttt{CreateStaff}
|
||||
already demands a live \texttt{Instrument}, and nothing else could mint one.
|
||||
Schema major~2 unconditionally (\texttt{Instrument}'s major-2 appends are
|
||||
mandatory fields, not \texttt{Option}-hidden).
|
||||
|
||||
\medskip
|
||||
|
||||
\noindent\textbf{Version 0.10.0, second half (genesis tranche G2a).} Adds two
|
||||
operation kinds, \texttt{SetCanvasLayoutDefaults}
|
||||
(Section~\ref{sec:k0:set-canvas-layout-defaults}) and
|
||||
\texttt{SetSpellingPrecedence} (Section~\ref{sec:k0:set-spelling-precedence}),
|
||||
on exactly the \texttt{SetMetadata} advisory-LWW pattern
|
||||
(Section~\ref{sec:k0:score-settings}): the canvas's default layout advisories
|
||||
and the score's spelling-precedence configuration join the operation-authored
|
||||
surfaces. Both are schema major~0 unconditionally --- neither carried type's
|
||||
canonical encoding, taken as a standalone payload, has ever been versioned.
|
||||
No accept-set change: the third genesis-ladder setter,
|
||||
\texttt{SetTuningContext}, is schema major~3 and is deliberately deferred to
|
||||
its own rung (G2b) rather than anticipated here.
|
||||
|
||||
The \emph{Value restoration} passage
|
||||
(Section~\ref{sec:k0:undo}) and the \emph{Retired slots} closing note both
|
||||
gain a repair alongside this addition: the former's LWW-family enumeration
|
||||
now names both new setters, and the latter's ``outside the operation set''
|
||||
clause is narrowed to the canvas object itself, per
|
||||
\texttt{spec/RULING\_GENESIS\_PERSISTENCE.md} --- the score's \emph{contents}
|
||||
are no longer outside the operation set; the canvas is still never
|
||||
op-minted.
|
||||
|
||||
% ===========================================================================
|
||||
\chapter{The Catalog Framework}
|
||||
\label{ch:framework}
|
||||
|
|
@ -1138,6 +1177,76 @@ There is no \texttt{DeleteInstrument} in this catalogue revision ---
|
|||
full delete/modify coverage of the genesis-authored fields is later
|
||||
tranche work (\texttt{spec/PLAN\_GENESIS\_OPS.md} G3).
|
||||
|
||||
\section{SetCanvasLayoutDefaults}
|
||||
\label{sec:k0:set-canvas-layout-defaults}
|
||||
|
||||
Ratified with the genesis operation tranche's G2a rung (\texttt{spec/CONTRACT\_
|
||||
GENESIS\_G2A\_SETTINGS.md}, executing \texttt{spec/RULING\_GENESIS\_
|
||||
PERSISTENCE.md}): the canvas's default layout advisories
|
||||
(\texttt{Canvas.layout\_defaults}) join the operation-authored surfaces, on
|
||||
exactly the \texttt{SetMetadata} pattern (Section~\ref{sec:k0:score-settings}).
|
||||
|
||||
\textbf{Payload schema.} \texttt{SetCanvasLayoutDefaultsOp \{ layout\_defaults:
|
||||
CanvasLayoutDefaults \}} --- the full page-size-and-margins value.
|
||||
|
||||
\textbf{Canonical encoding.} The length-framed canonical bytes of
|
||||
\texttt{layout\_defaults}. \texttt{CanvasLayoutDefaults} carries no
|
||||
schema-major-1-or-higher appends of its own --- the versioning that labels the
|
||||
type ``schema major 1'' lives in the \emph{containing} \texttt{Canvas} walk,
|
||||
not in this leaf --- so, as a standalone payload, it has exactly one layout
|
||||
and this operation is schema major~0 unconditionally.
|
||||
|
||||
\textbf{Reduction rule.} An advisory last-writer-wins field overwrite,
|
||||
identical in discipline to \texttt{SetMetadata}: the latest write in canonical
|
||||
order silently wins and the operation always applies --- no working state, no
|
||||
conflict, and no idempotence short-circuit (a re-write of an identical value
|
||||
is a legitimate new write, not a no-op). Graph-aware reduction overwrites
|
||||
\texttt{Canvas.layout\_defaults}.
|
||||
|
||||
\textbf{Conflict cases.} None (advisory LWW).
|
||||
|
||||
\textbf{Undo semantics.} A value-restoring field overwrite
|
||||
(Section~\ref{sec:k0:undo}): the write chain is seeded from the base value at
|
||||
ingest, so undoing the first operational write restores the pre-operational
|
||||
state rather than absence.
|
||||
|
||||
\textbf{Re-anchoring.} Not applicable: the field is a score singleton with no
|
||||
tombstonable anchor.
|
||||
|
||||
\section{SetSpellingPrecedence}
|
||||
\label{sec:k0:set-spelling-precedence}
|
||||
|
||||
Ratified with the genesis operation tranche's G2a rung, alongside
|
||||
\texttt{SetCanvasLayoutDefaults} above: the score's spelling-precedence
|
||||
configuration (\texttt{Score.spelling\_precedence}) joins the
|
||||
operation-authored surfaces, on the same \texttt{SetMetadata} pattern.
|
||||
|
||||
\textbf{Payload schema.} \texttt{SetSpellingPrecedenceOp \{ precedence:
|
||||
SpellingPrecedence \}} --- the full total-ordering value over the five
|
||||
spelling-source kinds.
|
||||
|
||||
\textbf{Canonical encoding.} The length-framed canonical bytes of
|
||||
\texttt{precedence}. \texttt{SpellingPrecedence} has never been versioned ---
|
||||
every codec walk that reads it, frozen and live alike, reads it through the
|
||||
plain unversioned codec --- so this operation is schema major~0
|
||||
unconditionally, exactly as \texttt{SetCanvasLayoutDefaults} is.
|
||||
|
||||
\textbf{Reduction rule.} An advisory last-writer-wins field overwrite,
|
||||
identical in discipline to \texttt{SetMetadata} and
|
||||
\texttt{SetCanvasLayoutDefaults}: no working state, no conflict, no
|
||||
idempotence short-circuit. Graph-aware reduction overwrites
|
||||
\texttt{Score.spelling\_precedence}.
|
||||
|
||||
\textbf{Conflict cases.} None (advisory LWW).
|
||||
|
||||
\textbf{Undo semantics.} A value-restoring field overwrite
|
||||
(Section~\ref{sec:k0:undo}): the write chain is seeded from the base value at
|
||||
ingest, so undoing the first operational write restores the pre-operational
|
||||
state rather than absence.
|
||||
|
||||
\textbf{Re-anchoring.} Not applicable: the field is a score singleton with no
|
||||
tombstonable anchor.
|
||||
|
||||
\section{Repeat Structures}
|
||||
\label{sec:k0:repeat-structures}
|
||||
|
||||
|
|
@ -1494,8 +1603,9 @@ transaction minted is tombstoned. \texttt{StrictInverse} conflicts
|
|||
|
||||
\emph{Value restoration} (this revision): for every last-writer-wins overwrite
|
||||
the target transaction performed --- event and identified-pitch modification,
|
||||
respelling, cross-cutting modification, metadata, metric grid, meter change,
|
||||
tempo segment, staff layout, and the user break advisories --- the reducer
|
||||
respelling, cross-cutting modification, metadata, canvas layout defaults,
|
||||
spelling precedence, metric grid, meter change, tempo segment, staff layout,
|
||||
and the user break advisories --- the reducer
|
||||
maintains, per overwritten key, the \emph{canonical-order write chain} of
|
||||
(writer, value) pairs. Undoing the transaction restores each written key to
|
||||
its chain-predecessor value (or its absence, where the transaction introduced
|
||||
|
|
@ -1633,15 +1743,23 @@ a fresh design.
|
|||
\section*{Retired slots (ratified Pass~12: outside the operation set)}
|
||||
|
||||
\begin{description}
|
||||
\item[Create score / canvas --- retired, closing P12-K8]
|
||||
The document root and the canvas are \emph{structural givens}, not
|
||||
operation products: \texttt{TypedObjectId} has no Canvas kind, the root is
|
||||
never op-minted, and genesis is normatively the empty-document constructor
|
||||
plus bundle creation, outside the operation set (core specification,
|
||||
Chapter~5 \sectionsc{The Canvas}). These are not ``unavailable slots''
|
||||
awaiting a design --- no operation kind will be assigned to them. The
|
||||
decision is revisited only if an addressable multi-canvas model is adopted
|
||||
at a future schema major.
|
||||
\item[Create score / canvas --- retired, closing P12-K8; narrowed by
|
||||
\texttt{spec/RULING\_GENESIS\_PERSISTENCE.md}]
|
||||
The document root and the canvas remain \emph{structural givens}, not
|
||||
operation products: \texttt{TypedObjectId} has no Canvas kind, and the
|
||||
root is never op-minted (core specification, Chapter~5
|
||||
\sectionsc{The Canvas}). \texttt{RULING\_GENESIS\_PERSISTENCE} reverses
|
||||
only the wider claim this slot's description used to carry --- that the
|
||||
score's \emph{contents} arrive outside the operation set. They do not:
|
||||
the genesis tranche makes every mutable \texttt{Score} field
|
||||
operation-authored, \texttt{Canvas.layout\_defaults} among them
|
||||
(Section~\ref{sec:k0:set-canvas-layout-defaults}). What survives, and is
|
||||
load-bearing, is the narrower claim above --- the canvas \emph{itself} is
|
||||
still never minted, addressed, or deleted by any operation, and no
|
||||
\texttt{TypedObjectId} kind exists for it. These are not ``unavailable
|
||||
slots'' awaiting a design --- no operation kind will be assigned to them.
|
||||
The decision is revisited only if an addressable multi-canvas model is
|
||||
adopted at a future schema major.
|
||||
\end{description}
|
||||
|
||||
\begin{nongoal}
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -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.8.0 --- The genesis operation vocabulary reaches the grammar}\\[4pt]
|
||||
{\normalsize\color{epiphanyink}Version 0.9.0 --- The genesis settings setters reach the grammar}\\[4pt]
|
||||
{\small\color{epiphanyslate}Normative for the text form it defines}
|
||||
\vfill
|
||||
\end{titlepage}
|
||||
|
|
@ -467,7 +467,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 8 0)}, the version of the companion it implements. It
|
||||
version: \texttt{(0 9 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
|
||||
|
|
@ -518,7 +518,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.8.0, neither a canonical operation nor canonical reduced state can
|
||||
version~0.9.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}
|
||||
|
|
@ -1042,6 +1042,8 @@ kind ::= "(insert-event " bytes " " value ")"
|
|||
| "(delete-repeat-structure " bytes ")"
|
||||
| "(transpose-interval (" bytes* ") " value ")"
|
||||
| "(create-instrument " value ")"
|
||||
| "(set-canvas-layout-defaults " value ")"
|
||||
| "(set-spelling-precedence " value ")"
|
||||
|
||||
tuplet-comp ::= "not-in-tuplet" | "(replace-with-rest " value ")"
|
||||
| "(rewrite-tuplets (" bytes* "))"
|
||||
|
|
@ -1118,7 +1120,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 8 0))
|
||||
(text-projection (0 9 0))
|
||||
(document #x05050505050505050505050505050505)
|
||||
(profile full (0 1 0) (constraints 67108864 (retention 1 () true)))
|
||||
(canonical-base #x1f8b0000000000000000000000000000 #x 1 full (schema 0 1) #x0000)
|
||||
|
|
@ -1325,6 +1327,18 @@ absorb it, exactly as the binary decoder does.
|
|||
may discard, so a stale projection is regenerated from the canonical
|
||||
document rather than converted. Multi-version acceptance and text
|
||||
migrate-on-read remain deferred, unchanged. \\
|
||||
\today & Chapter 5 & 0.9.0 --- The genesis settings setters reach the
|
||||
grammar. The \texttt{kind} production gains
|
||||
\texttt{"(set-canvas-layout-defaults " value ")"} and
|
||||
\texttt{"(set-spelling-precedence " value ")"}
|
||||
(\texttt{req:textproj:operation-vocabulary}), the second appended pair since
|
||||
the header was gated to a single version at 0.7.0.
|
||||
|
||||
Same forcing reason as the 0.8.0 bump above: holding the version while
|
||||
extending the grammar would leave two mutually incompatible grammars both
|
||||
claiming \texttt{(0 8 0)}. Cached projections at \texttt{(0 8 0)} do not
|
||||
migrate; a stale \texttt{TextProjection} chunk is regenerated, not
|
||||
converted. \\
|
||||
\bottomrule
|
||||
\end{longtable}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,8 +69,10 @@ ops.operation_kind_tag accept - tag_28 1c
|
|||
ops.operation_kind_tag accept - tag_29 1d
|
||||
ops.operation_kind_tag accept - tag_30 1e
|
||||
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 - registered 1000000000000000000123456789abcdef
|
||||
ops.operation_kind_tag reject unknown-discriminant tag_32_one_past_the_vocabulary 20
|
||||
ops.operation_kind_tag reject unknown-discriminant tag_34_one_past_the_vocabulary 22
|
||||
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
|
||||
|
|
@ -79,6 +81,10 @@ ops.operation_kind_tag reject truncated registered_one_byte_short 10000000000000
|
|||
# ops.operation_envelope
|
||||
ops.operation_envelope accept - create_instrument 000000000000000100000000000000010000000000000000000000000000000001000000000000000100000000000000000000010000000000000001000000000000000000001f4100000010000000000000000000000100000000000000010c000000696e737472756d656e742d31000000000000000002000508000000000000000000f03f000000000000
|
||||
ops.operation_envelope reject trailing-bytes create_instrument_trailing 000000000000000100000000000000010000000000000000000000000000000001000000000000000100000000000000000000010000000000000001000000000000000000001f4100000010000000000000000000000100000000000000010c000000696e737472756d656e742d31000000000000000002000508000000000000000000f03f00000000000000
|
||||
ops.operation_envelope accept - set_canvas_layout_defaults 000000000000000100000000000000020000000000000000000000000000000001000000000000000100000000000000000000010000000000000002000000000000000000002048000000080000000000000000805a40080000000000000000906240080000000000000000001e40080000000000000000001e40080000000000000000001e40080000000000000000001e40
|
||||
ops.operation_envelope reject trailing-bytes set_canvas_layout_defaults_trailing 000000000000000100000000000000020000000000000000000000000000000001000000000000000100000000000000000000010000000000000002000000000000000000002048000000080000000000000000805a40080000000000000000906240080000000000000000001e40080000000000000000001e40080000000000000000001e40080000000000000000001e4000
|
||||
ops.operation_envelope accept - set_spelling_precedence 000000000000000100000000000000030000000000000000000000000000000001000000000000000100000000000000000000010000000000000003000000000000000000002109000000050000000403020100
|
||||
ops.operation_envelope reject trailing-bytes set_spelling_precedence_trailing 00000000000000010000000000000003000000000000000000000000000000000100000000000000010000000000000000000001000000000000000300000000000000000000210900000005000000040302010000
|
||||
|
||||
# bundle.manifest
|
||||
bundle.manifest accept - empty_manifest 6f9e7d11689ab113c4a1f05faf60fe60050505050505050505050505050505050000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000001000000000000000000000400000000010000000001000000000000
|
||||
|
|
|
|||
|
|
@ -22,16 +22,16 @@
|
|||
# document bytes are normative. `<utf8-hex>` is lowercase with no separators.
|
||||
|
||||
# textproj.document
|
||||
textproj.document accept - minimal 28746578742d70726f6a656374696f6e2028302038203029290a28646f63756d656e742023783031303130313031303130313031303130313031303130313031303130313031290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a
|
||||
textproj.document accept - lineage_custom_profile 28746578742d70726f6a656374696f6e2028302038203029290a28646f63756d656e742023783032303230323032303230323032303230323032303230323032303230323032290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a
|
||||
textproj.document accept - extension_base_two_envelopes 28746578742d70726f6a656374696f6e2028302038203029290a28646f63756d656e742023783033303330333033303330333033303330333033303330333033303330333033290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a
|
||||
textproj.document accept - rich_document 28746578742d70726f6a656374696f6e2028302038203029290a28646f63756d656e742023783034303430343034303430343034303430343034303430343034303430343034290a286c696e656167652023783134313431343134313431343134313431343134313431343134313431343134290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a28657874656e73696f6e202378303230323032303230323032303230323032303230323032303230323032303220283120302032292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830332929202378303220237830323033290a2863616e6f6e6963616c2d62617365202378303430343034303430343034303430343034303430343034303430343034303420237830313032303420312066756c6c2028736368656d61203020312920237861303034290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303034202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203430302030202378303030303030303030303030303030313030303030303030303030303030303429202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030342929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303035202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203530302030202378303030303030303030303030303030313030303030303030303030303030303529202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030352929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303036202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203630302030202378303030303030303030303030303030313030303030303030303030303030303629202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030362929290a
|
||||
textproj.document reject wrong-header-version superseded_companion_version 28746578742d70726f6a656374696f6e2028302037203029290a28646f63756d656e742023783031303130313031303130313031303130313031303130313031303130313031290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a
|
||||
textproj.document reject blob-line unreferenced_blob 28746578742d70726f6a656374696f6e2028302038203029290a28646f63756d656e742023783031303130313031303130313031303130313031303130313031303130313031290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28626c6f6220226170706c69636174696f6e2f6f637465742d73747265616d222028292023783031290a
|
||||
textproj.document reject out-of-order-sections canonical_base_before_extension 28746578742d70726f6a656374696f6e2028302038203029290a28646f63756d656e742023783033303330333033303330333033303330333033303330333033303330333033290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a
|
||||
textproj.document reject repeated-singular-section lineage_repeated 28746578742d70726f6a656374696f6e2028302038203029290a28646f63756d656e742023783032303230323032303230323032303230323032303230323032303230323032290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a
|
||||
textproj.document reject operation-envelope-order envelopes_reversed 28746578742d70726f6a656374696f6e2028302038203029290a28646f63756d656e742023783033303330333033303330333033303330333033303330333033303330333033290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a
|
||||
textproj.document reject profile-declaration-order profiles_reversed 28746578742d70726f6a656374696f6e2028302038203029290a28646f63756d656e742023783032303230323032303230323032303230323032303230323032303230323032290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a
|
||||
textproj.document reject extension-declaration-order extensions_reversed 28746578742d70726f6a656374696f6e2028302038203029290a28646f63756d656e742023783034303430343034303430343034303430343034303430343034303430343034290a286c696e656167652023783134313431343134313431343134313431343134313431343134313431343134290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303230323032303230323032303230323032303230323032303230323032303220283120302032292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830332929202378303220237830323033290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303430343034303430343034303430343034303430343034303430343034303420237830313032303420312066756c6c2028736368656d61203020312920237861303034290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303034202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203430302030202378303030303030303030303030303030313030303030303030303030303030303429202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030342929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303035202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203530302030202378303030303030303030303030303030313030303030303030303030303030303529202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030352929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303036202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203630302030202378303030303030303030303030303030313030303030303030303030303030303629202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030362929290a
|
||||
textproj.document reject extension-chunk-order extension_chunks_reversed 28746578742d70726f6a656374696f6e2028302038203029290a28646f63756d656e742023783033303330333033303330333033303330333033303330333033303330333033290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a
|
||||
textproj.document reject missing-trailing-lf final_lf_missing 28746578742d70726f6a656374696f6e2028302038203029290a28646f63756d656e742023783031303130313031303130313031303130313031303130313031303130313031290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e20312028292074727565292929
|
||||
textproj.document accept - minimal 28746578742d70726f6a656374696f6e2028302039203029290a28646f63756d656e742023783031303130313031303130313031303130313031303130313031303130313031290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a
|
||||
textproj.document accept - lineage_custom_profile 28746578742d70726f6a656374696f6e2028302039203029290a28646f63756d656e742023783032303230323032303230323032303230323032303230323032303230323032290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a
|
||||
textproj.document accept - extension_base_two_envelopes 28746578742d70726f6a656374696f6e2028302039203029290a28646f63756d656e742023783033303330333033303330333033303330333033303330333033303330333033290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a
|
||||
textproj.document accept - rich_document 28746578742d70726f6a656374696f6e2028302039203029290a28646f63756d656e742023783034303430343034303430343034303430343034303430343034303430343034290a286c696e656167652023783134313431343134313431343134313431343134313431343134313431343134290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a28657874656e73696f6e202378303230323032303230323032303230323032303230323032303230323032303220283120302032292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830332929202378303220237830323033290a2863616e6f6e6963616c2d62617365202378303430343034303430343034303430343034303430343034303430343034303420237830313032303420312066756c6c2028736368656d61203020312920237861303034290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303034202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203430302030202378303030303030303030303030303030313030303030303030303030303030303429202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030342929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303035202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203530302030202378303030303030303030303030303030313030303030303030303030303030303529202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030352929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303036202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203630302030202378303030303030303030303030303030313030303030303030303030303030303629202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030362929290a
|
||||
textproj.document reject wrong-header-version superseded_companion_version 28746578742d70726f6a656374696f6e2028302038203029290a28646f63756d656e742023783031303130313031303130313031303130313031303130313031303130313031290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a
|
||||
textproj.document reject blob-line unreferenced_blob 28746578742d70726f6a656374696f6e2028302039203029290a28646f63756d656e742023783031303130313031303130313031303130313031303130313031303130313031290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28626c6f6220226170706c69636174696f6e2f6f637465742d73747265616d222028292023783031290a
|
||||
textproj.document reject out-of-order-sections canonical_base_before_extension 28746578742d70726f6a656374696f6e2028302039203029290a28646f63756d656e742023783033303330333033303330333033303330333033303330333033303330333033290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a
|
||||
textproj.document reject repeated-singular-section lineage_repeated 28746578742d70726f6a656374696f6e2028302039203029290a28646f63756d656e742023783032303230323032303230323032303230323032303230323032303230323032290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a
|
||||
textproj.document reject operation-envelope-order envelopes_reversed 28746578742d70726f6a656374696f6e2028302039203029290a28646f63756d656e742023783033303330333033303330333033303330333033303330333033303330333033290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a
|
||||
textproj.document reject profile-declaration-order profiles_reversed 28746578742d70726f6a656374696f6e2028302039203029290a28646f63756d656e742023783032303230323032303230323032303230323032303230323032303230323032290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a
|
||||
textproj.document reject extension-declaration-order extensions_reversed 28746578742d70726f6a656374696f6e2028302039203029290a28646f63756d656e742023783034303430343034303430343034303430343034303430343034303430343034290a286c696e656167652023783134313431343134313431343134313431343134313431343134313431343134290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303230323032303230323032303230323032303230323032303230323032303220283120302032292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830332929202378303220237830323033290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303430343034303430343034303430343034303430343034303430343034303420237830313032303420312066756c6c2028736368656d61203020312920237861303034290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303034202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203430302030202378303030303030303030303030303030313030303030303030303030303030303429202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030342929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303035202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203530302030202378303030303030303030303030303030313030303030303030303030303030303529202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030352929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303036202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203630302030202378303030303030303030303030303030313030303030303030303030303030303629202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030362929290a
|
||||
textproj.document reject extension-chunk-order extension_chunks_reversed 28746578742d70726f6a656374696f6e2028302039203029290a28646f63756d656e742023783033303330333033303330333033303330333033303330333033303330333033290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a
|
||||
textproj.document reject missing-trailing-lf final_lf_missing 28746578742d70726f6a656374696f6e2028302039203029290a28646f63756d656e742023783031303130313031303130313031303130313031303130313031303130313031290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e20312028292074727565292929
|
||||
|
|
|
|||
Loading…
Reference in New Issue