Genesis G2b: SetTuningContext, and the accept-set raise it pays for
Kind and tag 34, schema major 3, minor epoch 10. The last rung before G3, and the one that closes P13-S13: the tuning context becomes operation-authored, so it finally has a canonical carrier. The closure argument is the metadata precedent, not the canonical base - the base embeds no graph values for any field, and metadata has been durable purely through its operations since M2d. The payload carries epiphany_core::TuningContextSettings, a five-field subset of ScoreTuningContext, not the full graph type. ScoreTuningContext's codec deliberately drops accidental_extensions, so a full-value payload would have diverged between a live session, where accept stores the envelope as a value, and the same document reloaded, where the field decodes empty. canonical_value! could not have caught that: it compares bytes and never the originating value, so a field that never reached the bytes is structurally invisible to it. The subset makes the divergence unrepresentable instead of relying on a normalization step nothing can enforce, and it costs no wire design - the encoding is byte-identical to the existing five-field walk, which tuning_context_settings_canonical_bytes_match_score_tuning_context asserts directly. Reduction leaves accidental_extensions untouched. SetTuningContext is the sole genesis payload born at major 3, because minimal stamping is a function of each payload's value, so the accept-set raise is charged to this one surface: OperationEnvelopeBlock 2 to 3. The doc comment above it did not merely record the cap, it asserted that no operation payload embeds the tuning context - a sentence this rung falsifies - so it is rewritten rather than left beside a corrected constant. Undo restores the seeded base settings, default or not, and the never-authored versus authored-to-default distinction stays unobservable. An earlier draft of the contract had that backwards; PLAN_GENESIS_OPS section 5 trap 5 withdrew it, and SetMetadata is the disproof. Fixes two undefined references the interrupted run had not yet reached: operation_catalog.tex referenced sec:evolution:major3, a label defined in binary_format.tex, which LaTeX cannot resolve across documents. Replaced with the sectionsc convention already used for every other cross-companion citation in that file. Gate: 1409 tests, clippy 0, fmt clean, conformance 8/8 including [7f], both vector corpora regenerated, all four PDFs at 0 undefined references. The t5 and t7 mutations were re-run independently and observed to fail as specified; the remaining eight are not signed off, because the implementing run was stopped before it reported them. 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
039a8ddec8
commit
13c3d2fd46
|
|
@ -644,3 +644,45 @@ declaration order (`core_spec` §"Extension Declarations"), which had chunks bef
|
||||||
kinds and barriers.
|
kinds and barriers.
|
||||||
|
|
||||||
Still no implementation. The companion is now complete enough to implement against.
|
Still no implementation. The companion is now complete enough to implement against.
|
||||||
|
|
||||||
|
## Genesis tranche G2b: op-block accept-set raised to [0, 3] (2026-07-28)
|
||||||
|
|
||||||
|
`spec/CONTRACT_GENESIS_G2B_TUNING.md` charges this crate alone with the raise:
|
||||||
|
`max_supported_major(OperationEnvelopeBlock)` → 3. `SetTuningContext`
|
||||||
|
(`epiphany-ops`) is the sole genesis-tranche payload born at schema major 3 —
|
||||||
|
its carried `epiphany_core::TuningContextSettings` has mandatory (not
|
||||||
|
`Option`-hidden) appends past major 2, so a block carrying one is now born at
|
||||||
|
v3. This is the one-way door the governing plan (`PLAN_GENESIS_OPS.md` §4)
|
||||||
|
warned against burying inside routine work: G2 was split into G2a/G2b
|
||||||
|
precisely so the two major-0 setters (G2a) would not carry this raise, and it
|
||||||
|
lands alone here instead.
|
||||||
|
|
||||||
|
**The doc comment above `max_supported_major` asserted a rationale this rung
|
||||||
|
falsifies, and it had to move with the number, not just the number itself.**
|
||||||
|
The prior text ("Schema major 3 ... does not raise this role: no operation
|
||||||
|
payload embeds the tuning context, so no op block is ever born at v3") is now
|
||||||
|
false. Rewritten, and mutation-verified (`accept_set_doc_no_longer_claims_
|
||||||
|
no_payload_embeds_the_tuning_context`, `bundle.rs`) that the exact stale
|
||||||
|
sentence is absent from the source — not merely superseded by newer prose
|
||||||
|
elsewhere in the file, which a reader skimming only the doc comment could
|
||||||
|
still miss. This is the `binary_format.tex:2373` lesson applied to Rust doc
|
||||||
|
comments, not just the LaTeX companion.
|
||||||
|
|
||||||
|
**One existing test needed a value bump as a direct consequence, not a
|
||||||
|
touch-table item.** `committing_an_unsupported_major_op_root_makes_the_live_
|
||||||
|
bundle_read_only` staged a block at major 3 to exercise the "beyond the
|
||||||
|
accept-set" read-only path; major 3 is now *inside* the accept-set, so the
|
||||||
|
test silently stopped testing what its name claims (it would still pass,
|
||||||
|
vacuously, for the wrong reason) — caught by running the full bundle suite
|
||||||
|
after the raise, not by the touch table, which did not name this test.
|
||||||
|
Moved to major 4, with a comment explaining why 3 no longer works. This is
|
||||||
|
exactly the kind of collateral fix the touch table's "floor, not ceiling"
|
||||||
|
framing anticipates: a file not listed can still need an edit when a change
|
||||||
|
elsewhere makes its assumption stale.
|
||||||
|
|
||||||
|
**No `epiphany-bundle` participation in the never-authored/authored-to-default
|
||||||
|
question (pin 5).** This crate has no visibility into operation semantics —
|
||||||
|
`edit_barriers` and the op-block bytes are opaque to it — so pin 5's
|
||||||
|
seeded-undo discipline is entirely `epiphany-ops`'s concern. This crate's
|
||||||
|
only stake is that the raise is now paid for real, once, by the value that
|
||||||
|
actually needs it.
|
||||||
|
|
|
||||||
|
|
@ -50,23 +50,26 @@ pub const SUPPORTED_SCHEMA_MAJOR: u16 = 0;
|
||||||
/// bound of its per-role accept-set `[0, max]` (Binary Format companion
|
/// bound of its per-role accept-set `[0, max]` (Binary Format companion
|
||||||
/// §"Schema Major 1", "The accept-set gate").
|
/// §"Schema Major 1", "The accept-set gate").
|
||||||
///
|
///
|
||||||
/// `OperationEnvelopeBlock` admits major 2 (schema major 2 fills the
|
/// `OperationEnvelopeBlock` admits major 3 (schema major 2 fills the
|
||||||
/// cross-cutting/staff/metadata bodies its payloads embed; major 1 embedded a
|
/// cross-cutting/staff/metadata bodies its payloads embed; major 1 embedded a
|
||||||
/// v1 `CreateRegion`; the reader treats the block bytes opaquely, so it
|
/// v1 `CreateRegion`; the reader treats the block bytes opaquely, so it
|
||||||
/// parses a higher-major block without decoding the payload). Schema major 3
|
/// parses a higher-major block without decoding the payload). **Schema major
|
||||||
/// (Push 4b tranche 3b-i) does **not** raise this role: no operation payload
|
/// 3 is raised by genesis tranche G2b** (`spec/CONTRACT_GENESIS_G2B_TUNING.md`):
|
||||||
/// embeds the tuning context, so no op block is ever born at v3. `Snapshot`
|
/// `SetTuningContext` is the sole operation payload that embeds the tuning
|
||||||
/// admits major 3 for the acceleration full-`Score` form (decoded through
|
/// context (`epiphany_core::TuningContextSettings`, born at major 3
|
||||||
/// the core versioned seam); the canonical BASE carried under the same kind
|
/// unconditionally), so an op block carrying one is now born at v3 — this
|
||||||
/// must stay major 0, enforced per role. Every other role stays at
|
/// superseded the earlier Push 4b tranche 3b-i note claiming no payload ever
|
||||||
/// [`SUPPORTED_SCHEMA_MAJOR`] until its own versioned path lands — the
|
/// would. `Snapshot` admits major 3 for the acceleration full-`Score` form
|
||||||
/// layout cache, the operation index, and the manifest (carried opaquely,
|
/// (decoded through the core versioned seam); the canonical BASE carried
|
||||||
|
/// under the same kind must stay major 0, enforced per role. Every other role
|
||||||
|
/// stays at [`SUPPORTED_SCHEMA_MAJOR`] until its own versioned path lands —
|
||||||
|
/// the layout cache, the operation index, and the manifest (carried opaquely,
|
||||||
/// never grows a versioned layout). A chunk above its role's max is not
|
/// never grows a versioned layout). A chunk above its role's max is not
|
||||||
/// admitted; for a **canonical** role that means the bundle opens read-only
|
/// admitted; for a **canonical** role that means the bundle opens read-only
|
||||||
/// (a lower-major-only reader meeting a newer op block), not a hard reject.
|
/// (a lower-major-only reader meeting a newer op block), not a hard reject.
|
||||||
pub fn max_supported_major(kind: ChunkKind) -> u16 {
|
pub fn max_supported_major(kind: ChunkKind) -> u16 {
|
||||||
match kind {
|
match kind {
|
||||||
ChunkKind::OperationEnvelopeBlock => 2,
|
ChunkKind::OperationEnvelopeBlock => 3,
|
||||||
// The payload-polymorphic Snapshot role: the acceleration
|
// The payload-polymorphic Snapshot role: the acceleration
|
||||||
// full-`Score` form is decoded through the core versioned seam
|
// full-`Score` form is decoded through the core versioned seam
|
||||||
// (`Score::decode_canonical_versioned`, majors {0,1,2,3}). The
|
// (`Score::decode_canonical_versioned`, majors {0,1,2,3}). The
|
||||||
|
|
@ -1380,14 +1383,17 @@ mod tests {
|
||||||
// CreateRegion), and schema major 2 to major 2 (a block bearing a v2
|
// CreateRegion), and schema major 2 to major 2 (a block bearing a v2
|
||||||
// cross-cutting/staff/metadata value); every other role stays exact-0
|
// cross-cutting/staff/metadata value); every other role stays exact-0
|
||||||
// until its own versioned path lands, and the manifest stays major 0
|
// until its own versioned path lands, and the manifest stays major 0
|
||||||
// forever. Schema major 3 (Push 4b tranche 3b-i, §"Schema Major 3")
|
// forever. Genesis tranche G2b (`spec/CONTRACT_GENESIS_G2B_TUNING.md`)
|
||||||
// raises only the snapshot role — no operation payload embeds the
|
// raises the op-block role to major 3: `SetTuningContext` is the sole
|
||||||
// tuning context, so the op-block role's admission is untouched.
|
// operation payload that embeds the tuning context, born at major 3
|
||||||
|
// unconditionally, so a block carrying one is now born at v3 — this
|
||||||
|
// supersedes the earlier Push 4b tranche 3b-i note claiming no
|
||||||
|
// payload ever would.
|
||||||
assert_eq!(SchemaVersion::V1.major, 1);
|
assert_eq!(SchemaVersion::V1.major, 1);
|
||||||
assert_eq!(SchemaVersion::V2.major, 2);
|
assert_eq!(SchemaVersion::V2.major, 2);
|
||||||
assert_eq!(SchemaVersion::V3.major, 3);
|
assert_eq!(SchemaVersion::V3.major, 3);
|
||||||
// The op-block role admits [0, 2] — unchanged by schema major 3.
|
// (t4) The op-block role admits [0, 3] as of genesis tranche G2b.
|
||||||
assert_eq!(max_supported_major(ChunkKind::OperationEnvelopeBlock), 2);
|
assert_eq!(max_supported_major(ChunkKind::OperationEnvelopeBlock), 3);
|
||||||
// The snapshot role admits the major-3 acceleration form (decoded
|
// The snapshot role admits the major-3 acceleration form (decoded
|
||||||
// through the core versioned seam); the canonical BASE stays major 0
|
// through the core versioned seam); the canonical BASE stays major 0
|
||||||
// per role (`mis_stamped_canonical_base`). The remaining roles stay
|
// per role (`mis_stamped_canonical_base`). The remaining roles stay
|
||||||
|
|
@ -1401,16 +1407,45 @@ mod tests {
|
||||||
assert_eq!(Manifest::SCHEMA.major, 0);
|
assert_eq!(Manifest::SCHEMA.major, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// (t10) `CONTRACT_GENESIS_G2B_TUNING.md` pin 3: the doc comment above
|
||||||
|
/// `max_supported_major` used to assert a rationale G2b falsifies (no
|
||||||
|
/// operation payload reaches the tuning context, so no op block would
|
||||||
|
/// ever reach schema major 3). That claim must be gone from the source,
|
||||||
|
/// not merely superseded in prose elsewhere; a stale rationale beside a
|
||||||
|
/// corrected constant is exactly how `binary_format.tex:2373` decayed.
|
||||||
|
///
|
||||||
|
/// **Mutation:** restore the stale sentence into the doc comment; must
|
||||||
|
/// fail.
|
||||||
|
#[test]
|
||||||
|
fn accept_set_doc_no_longer_claims_no_payload_embeds_the_tuning_context() {
|
||||||
|
let source = include_str!("bundle.rs");
|
||||||
|
let stale_claim: String = ["no operation payload ", "embeds the tuning context"].concat();
|
||||||
|
let stale_consequence: String = ["no op block is ever ", "born at v3"].concat();
|
||||||
|
assert!(
|
||||||
|
!source.contains(&stale_claim),
|
||||||
|
"the doc comment above max_supported_major must not assert the falsified claim anymore"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!source.contains(&stale_consequence),
|
||||||
|
"the doc comment above max_supported_major must not assert the falsified consequence anymore"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn committing_an_unsupported_major_op_root_makes_the_live_bundle_read_only() {
|
fn committing_an_unsupported_major_op_root_makes_the_live_bundle_read_only() {
|
||||||
// A commit publishes an op block beyond this reader's accept-set (a
|
// A commit publishes an op block beyond this reader's accept-set (a
|
||||||
// forward-compat write): structural validation lets it through, but the
|
// forward-compat write): structural validation lets it through, but the
|
||||||
// LIVE bundle must go read-only at once — not only on the next reopen —
|
// LIVE bundle must go read-only at once — not only on the next reopen —
|
||||||
// so no further commit runs against canonical history it cannot parse.
|
// so no further commit runs against canonical history it cannot parse.
|
||||||
|
//
|
||||||
|
// Major 4, not 3: genesis tranche G2b raised the op-block accept-set
|
||||||
|
// to [0, 3] (`SetTuningContext` is born at major 3), so major 3 is now
|
||||||
|
// admitted and this test's "future major" must move past it to stay
|
||||||
|
// an actual test of the read-only-on-overflow path.
|
||||||
let mut bundle = fresh_bundle();
|
let mut bundle = fresh_bundle();
|
||||||
let block = StagedChunk::operation_block_versioned(
|
let block = StagedChunk::operation_block_versioned(
|
||||||
crate::block::encode_block(&[vec![1u8, 2, 3]]),
|
crate::block::encode_block(&[vec![1u8, 2, 3]]),
|
||||||
SchemaVersion::new(3, 0),
|
SchemaVersion::new(4, 0),
|
||||||
);
|
);
|
||||||
bundle
|
bundle
|
||||||
.commit(&[block], |ctx| {
|
.commit(&[block], |ctx| {
|
||||||
|
|
@ -1426,7 +1461,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert!(bundle.anomalies().iter().any(|a| matches!(
|
assert!(bundle.anomalies().iter().any(|a| matches!(
|
||||||
a,
|
a,
|
||||||
IntegrityAnomaly::UnsupportedCanonicalChunkMajor { schema_major: 3 }
|
IntegrityAnomaly::UnsupportedCanonicalChunkMajor { schema_major: 4 }
|
||||||
)));
|
)));
|
||||||
// A further commit against the now-read-only bundle is refused.
|
// A further commit against the now-read-only bundle is refused.
|
||||||
let more = StagedChunk::operation_block_versioned(
|
let more = StagedChunk::operation_block_versioned(
|
||||||
|
|
|
||||||
|
|
@ -1441,3 +1441,53 @@ in the *containing* `Canvas` walk (`dec_canvas_v0` default-fills the field;
|
||||||
itself. So neither op gains a `schema_major()` arm — both fall into the
|
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
|
existing `_ => 0` catch-all in `epiphany-ops`. This is unlike G1's
|
||||||
`CreateInstrument`, whose carried `Instrument` has mandatory major-2 appends.
|
`CreateInstrument`, whose carried `Instrument` has mandatory major-2 appends.
|
||||||
|
|
||||||
|
## Genesis tranche G2b — `TuningContextSettings`, the subset type
|
||||||
|
## (2026-07-28)
|
||||||
|
|
||||||
|
`spec/CONTRACT_GENESIS_G2B_TUNING.md` §1 (RATIFIED, resolving
|
||||||
|
`spec/PLAN_GENESIS_OPS.md` §3's open pin) adds `SetTuningContext` to
|
||||||
|
`epiphany-ops`, the G2b rung of the genesis ladder. Unlike G1 and G2a, its
|
||||||
|
carried payload is **not** the full `ScoreTuningContext` — it is a new type,
|
||||||
|
`epiphany_core::TuningContextSettings`, holding exactly the five fields
|
||||||
|
`ScoreTuningContext`'s `Codec` actually walks onto the wire
|
||||||
|
(`default_pitch_space`, `default_tuning_system`, `reference`, `smufl`,
|
||||||
|
`overrides`), in that same order.
|
||||||
|
|
||||||
|
**Why a new type, not the full value or a normalizing construction check.**
|
||||||
|
`ScoreTuningContext`'s `Codec` deliberately drops `accidental_extensions` on
|
||||||
|
encode and default-fills it to `Vec::new()` on decode (the field is staged out
|
||||||
|
of schema major 3). `OperationSet::accept` stores the authored envelope as a
|
||||||
|
**value**, so a `SetTuningContext` carrying the full `ScoreTuningContext`
|
||||||
|
would reduce with `accidental_extensions` intact on the authoring replica and
|
||||||
|
empty on any replica that received the document through serialization — the
|
||||||
|
same document in two graph states, depending only on whether you just
|
||||||
|
authored it. `canonical_value!`'s generated `decode_canonical` cannot catch
|
||||||
|
this: it compares decode → `finish()` → re-encode bytes, never the
|
||||||
|
originating value, so a field that never reaches the bytes is invisible to
|
||||||
|
it.
|
||||||
|
|
||||||
|
Normalization (clearing the field at construction) and reject-on-non-empty
|
||||||
|
were both rejected: normalization makes correctness depend on remembering to
|
||||||
|
clear a field at every construction site, enforced by nothing the compiler or
|
||||||
|
codec can see — a shape this track has been burned by twice already (four
|
||||||
|
stale literal sites at Push 4a, six found during G2a); reject-on-non-empty
|
||||||
|
turns an in-memory-only field into an authoring error for callers who never
|
||||||
|
opted into persistence. The subset type makes the divergence
|
||||||
|
**unrepresentable**: a field that does not exist cannot be set wrongly.
|
||||||
|
|
||||||
|
**No new byte layout.** `TuningContextSettings`'s `Codec` is byte-identical to
|
||||||
|
`ScoreTuningContext`'s existing five-field walk by construction — same five
|
||||||
|
fields, same order, same per-field codecs — asserted directly by
|
||||||
|
`tuning_context_settings_canonical_bytes_match_score_tuning_context`
|
||||||
|
(`codec.rs`). This is a type-level narrowing, not a new wire form, so
|
||||||
|
`canonical_value!` still applies and the G1/G2a payload template is
|
||||||
|
unchanged. One more `canonical_value!` line makes it reachable per-value.
|
||||||
|
|
||||||
|
`SetTuningContext` **does** gain a real `schema_major()` arm returning 3,
|
||||||
|
unconditionally — the opposite of G2a. `ScoreTuningContext`'s wire form is
|
||||||
|
born at schema major 3 and its appends (`smufl`, `overrides`) are mandatory,
|
||||||
|
not `Option`-hidden, so there is no lower-major layout for this payload to
|
||||||
|
fall back to. This is the sole surface among the nine genesis-tranche
|
||||||
|
settings/creates that drags `OperationEnvelopeBlock`'s accept-set from 2 to 3
|
||||||
|
(`epiphany-bundle`'s `DECISIONS.md`).
|
||||||
|
|
|
||||||
|
|
@ -61,8 +61,8 @@ use crate::graph::{
|
||||||
SpannerKind, Staff, StaffBasedContent, StaffBracketKind, StaffExtent, StaffGroup,
|
SpannerKind, Staff, StaffBasedContent, StaffBracketKind, StaffExtent, StaffGroup,
|
||||||
StaffGroupKind, StaffInstance, StaffLineConfiguration, StemDirection, SubBeam,
|
StaffGroupKind, StaffInstance, StaffLineConfiguration, StemDirection, SubBeam,
|
||||||
TempoMapReference, TextLineDefinition, Tie, TieClass, TimeExtent, TimeSignature,
|
TempoMapReference, TextLineDefinition, Tie, TieClass, TimeExtent, TimeSignature,
|
||||||
TimeSignatureDisplay, Timestamp, Tuplet, TupletRatio, UnpitchedMember, ViewDefinition, Voice,
|
TimeSignatureDisplay, Timestamp, TuningContextSettings, Tuplet, TupletRatio, UnpitchedMember,
|
||||||
VoiceOrigin, Volta,
|
ViewDefinition, Voice, VoiceOrigin, Volta,
|
||||||
};
|
};
|
||||||
use crate::ids::{
|
use crate::ids::{
|
||||||
AnalysisLayerId, AnalyticalAnnotationId, BarlineAlignmentGroupId, BeamId, ChordSymbolId,
|
AnalysisLayerId, AnalyticalAnnotationId, BarlineAlignmentGroupId, BeamId, ChordSymbolId,
|
||||||
|
|
@ -1984,6 +1984,40 @@ impl Codec for ScoreTuningContext {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `TuningContextSettings` (genesis tranche G2b,
|
||||||
|
// `spec/CONTRACT_GENESIS_G2B_TUNING.md` §1): the authored subset of
|
||||||
|
// `ScoreTuningContext` that `SetTuningContext` carries — exactly its five
|
||||||
|
// wire-bearing fields, in the codec's existing order. This walk is
|
||||||
|
// **byte-identical** to `ScoreTuningContext`'s `enc`/`dec` above by
|
||||||
|
// construction (same five fields, same order, same per-field codecs) — a
|
||||||
|
// type-level narrowing, not a new wire form. The identity is asserted by a
|
||||||
|
// round-trip test just below
|
||||||
|
// (`tuning_context_settings_canonical_bytes_match_score_tuning_context`).
|
||||||
|
impl Codec for TuningContextSettings {
|
||||||
|
fn enc(&self, out: &mut Vec<u8>) {
|
||||||
|
self.default_pitch_space.enc(out);
|
||||||
|
self.default_tuning_system.enc(out);
|
||||||
|
self.reference.enc(out);
|
||||||
|
self.smufl.enc(out);
|
||||||
|
self.overrides.enc(out);
|
||||||
|
}
|
||||||
|
fn dec(r: &mut Reader<'_>) -> Result<Self> {
|
||||||
|
let default_pitch_space = Codec::dec(r)?;
|
||||||
|
let default_tuning_system = Codec::dec(r)?;
|
||||||
|
let reference = Codec::dec(r)?;
|
||||||
|
let smufl = Codec::dec(r)?;
|
||||||
|
let overrides = Codec::dec(r)?;
|
||||||
|
Ok(TuningContextSettings {
|
||||||
|
default_pitch_space,
|
||||||
|
default_tuning_system,
|
||||||
|
reference,
|
||||||
|
smufl,
|
||||||
|
overrides,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Schema major 2: the cross-cutting bodies filled (appended fields); the
|
// Schema major 2: the cross-cutting bodies filled (appended fields); the
|
||||||
// frozen prior layouts are read by the `dec_*_v1` sub-decoders.
|
// frozen prior layouts are read by the `dec_*_v1` sub-decoders.
|
||||||
struct_codec!(Slur {
|
struct_codec!(Slur {
|
||||||
|
|
@ -3545,6 +3579,12 @@ canonical_value! {
|
||||||
// own — see the contract's "Why these two" table.
|
// own — see the contract's "Why these two" table.
|
||||||
CanvasLayoutDefaults,
|
CanvasLayoutDefaults,
|
||||||
SpellingPrecedence,
|
SpellingPrecedence,
|
||||||
|
// Genesis tranche G2b (`CONTRACT_GENESIS_G2B_TUNING.md` §1) —
|
||||||
|
// SetTuningContext embeds this authored subset, not the full
|
||||||
|
// `ScoreTuningContext`. Its `Codec` above is byte-identical to
|
||||||
|
// `ScoreTuningContext`'s five-field walk; this makes that layout
|
||||||
|
// reachable per-value, exactly as `ScoreTuningContext` above is.
|
||||||
|
TuningContextSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
@ -3873,6 +3913,65 @@ mod tests {
|
||||||
assert!(back.accidental_extensions.is_empty());
|
assert!(back.accidental_extensions.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Genesis tranche G2b (`CONTRACT_GENESIS_G2B_TUNING.md` §1, pin/touch-row
|
||||||
|
/// 3): `TuningContextSettings`'s canonical encoding is **byte-identical**
|
||||||
|
/// to `ScoreTuningContext`'s existing five-field walk — a type-level
|
||||||
|
/// narrowing, not a new wire form. Proven directly against non-default
|
||||||
|
/// values in all five fields, not just the default.
|
||||||
|
///
|
||||||
|
/// **Mutation:** reorder two fields in `TuningContextSettings::enc` (e.g.
|
||||||
|
/// swap `smufl` and `overrides`) without making the matching change in
|
||||||
|
/// `ScoreTuningContext::enc`; must fail.
|
||||||
|
#[test]
|
||||||
|
fn tuning_context_settings_canonical_bytes_match_score_tuning_context() {
|
||||||
|
use crate::accidental::{SmuflVersion, SmuflVersionRequirement};
|
||||||
|
use crate::graph::{ScoreTuningContext, TuningContextSettings};
|
||||||
|
use crate::ids::{ReplicaId, VoiceId};
|
||||||
|
use crate::pitch::TuningSystemId;
|
||||||
|
use crate::tuning::{TuningOverride, TuningScope};
|
||||||
|
|
||||||
|
let full = ScoreTuningContext {
|
||||||
|
smufl: SmuflVersionRequirement {
|
||||||
|
minimum: SmuflVersion::from_decimal(1, "12").unwrap(),
|
||||||
|
authored_against: SmuflVersion::from_decimal(1, "18").unwrap(),
|
||||||
|
},
|
||||||
|
overrides: vec![TuningOverride {
|
||||||
|
scope: TuningScope::Voice(VoiceId::new(ReplicaId(1), 7)),
|
||||||
|
pitch_space: None,
|
||||||
|
tuning_system: Some(TuningSystemId::new("tet-19")),
|
||||||
|
reference: None,
|
||||||
|
}],
|
||||||
|
..ScoreTuningContext::default()
|
||||||
|
};
|
||||||
|
let settings = TuningContextSettings {
|
||||||
|
default_pitch_space: full.default_pitch_space.clone(),
|
||||||
|
default_tuning_system: full.default_tuning_system.clone(),
|
||||||
|
reference: full.reference.clone(),
|
||||||
|
smufl: full.smufl,
|
||||||
|
overrides: full.overrides.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut full_bytes = Vec::new();
|
||||||
|
full.enc(&mut full_bytes);
|
||||||
|
let mut settings_bytes = Vec::new();
|
||||||
|
settings.enc(&mut settings_bytes);
|
||||||
|
assert_eq!(
|
||||||
|
settings_bytes, full_bytes,
|
||||||
|
"TuningContextSettings must encode byte-identically to ScoreTuningContext's five-field walk"
|
||||||
|
);
|
||||||
|
|
||||||
|
let decoded =
|
||||||
|
TuningContextSettings::dec(&mut Reader::new(&settings_bytes)).expect("decodes");
|
||||||
|
assert_eq!(decoded.default_pitch_space, settings.default_pitch_space);
|
||||||
|
assert_eq!(
|
||||||
|
decoded.default_tuning_system,
|
||||||
|
settings.default_tuning_system
|
||||||
|
);
|
||||||
|
assert_eq!(decoded.reference, settings.reference);
|
||||||
|
assert_eq!(decoded.smufl, settings.smufl);
|
||||||
|
assert_eq!(decoded.overrides, settings.overrides);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn generator_scores_round_trip() {
|
fn generator_scores_round_trip() {
|
||||||
for seed in 0..200u64 {
|
for seed in 0..200u64 {
|
||||||
|
|
|
||||||
|
|
@ -1705,6 +1705,49 @@ impl Default for ScoreTuningContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The **authored subset** of [`ScoreTuningContext`] that `SetTuningContext`
|
||||||
|
/// (genesis tranche G2b, `spec/CONTRACT_GENESIS_G2B_TUNING.md` §1) carries:
|
||||||
|
/// exactly the five fields `ScoreTuningContext`'s `Codec` actually walks onto
|
||||||
|
/// the wire (`codec.rs`'s hand-written `impl Codec for ScoreTuningContext`),
|
||||||
|
/// in that same order. `accidental_extensions` is **not** a field of this
|
||||||
|
/// type — it is deliberately absent, not cleared or normalized.
|
||||||
|
///
|
||||||
|
/// **Why a new type rather than reusing `ScoreTuningContext` directly.**
|
||||||
|
/// `ScoreTuningContext`'s `Codec` drops `accidental_extensions` on encode and
|
||||||
|
/// default-fills it to `Vec::new()` on decode: the field is staged out of
|
||||||
|
/// schema major 3 and stays in-memory-only. If an operation carried the full
|
||||||
|
/// `ScoreTuningContext`, `OperationSet::accept` would store the authored
|
||||||
|
/// envelope as a **value** (with `accidental_extensions` intact), while a
|
||||||
|
/// document reloaded from bytes would decode the same envelope with that
|
||||||
|
/// field reconstructed as empty — two divergent graph states from one
|
||||||
|
/// document, observable only by whether you just authored it or reloaded it.
|
||||||
|
/// A field that never reaches the wire cannot be caught by
|
||||||
|
/// `canonical_value!`'s decode → `finish()` → re-encode byte comparison,
|
||||||
|
/// because that comparison never touches the originating value.
|
||||||
|
///
|
||||||
|
/// This type makes the divergence **unrepresentable**: it has no
|
||||||
|
/// `accidental_extensions` field to diverge on. `SetTuningContext`'s
|
||||||
|
/// reduction writes exactly these five fields onto `score.tuning_context` and
|
||||||
|
/// leaves `accidental_extensions` untouched, preserving whatever the graph
|
||||||
|
/// already held. This is a **type-level narrowing, not a new wire form** —
|
||||||
|
/// `TuningContextSettings`'s canonical encoding is byte-for-byte identical to
|
||||||
|
/// `ScoreTuningContext`'s existing five-field walk (asserted in
|
||||||
|
/// `codec.rs`), so the packet designs no new layout.
|
||||||
|
///
|
||||||
|
/// When a later schema major lands `accidental_extensions` on the wire, this
|
||||||
|
/// type gains the field like any other major payload change — the same cost
|
||||||
|
/// normalization would have paid, but without making the never-authored /
|
||||||
|
/// authored-to-default distinction depend on a clearing discipline enforced
|
||||||
|
/// by nothing the compiler can see.
|
||||||
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub struct TuningContextSettings {
|
||||||
|
pub default_pitch_space: PitchSpaceId,
|
||||||
|
pub default_tuning_system: TuningSystemId,
|
||||||
|
pub reference: ReferencePitch,
|
||||||
|
pub smufl: crate::accidental::SmuflVersionRequirement,
|
||||||
|
pub overrides: Vec<crate::tuning::TuningOverride>,
|
||||||
|
}
|
||||||
|
|
||||||
/// The root object of a score (Chapter 5 §"Top-Level Score Structure").
|
/// The root object of a score (Chapter 5 §"Top-Level Score Structure").
|
||||||
///
|
///
|
||||||
/// This carries the full Chapter 5 top-level shape. The invariant-bearing
|
/// This carries the full Chapter 5 top-level shape. The invariant-bearing
|
||||||
|
|
|
||||||
|
|
@ -160,8 +160,8 @@ pub use graph::{
|
||||||
SoundConfiguration, SpaceUnit, SpanStyle, Spanner, SpannerKind, Staff, StaffBasedContent,
|
SoundConfiguration, SpaceUnit, SpanStyle, Spanner, SpannerKind, Staff, StaffBasedContent,
|
||||||
StaffBracketKind, StaffExtent, StaffGroup, StaffGroupKind, StaffInstance,
|
StaffBracketKind, StaffExtent, StaffGroup, StaffGroupKind, StaffInstance,
|
||||||
StaffLineConfiguration, StemDirection, SubBeam, TempoMapReference, TextLineDefinition, Tie,
|
StaffLineConfiguration, StemDirection, SubBeam, TempoMapReference, TextLineDefinition, Tie,
|
||||||
TieClass, TimeExtent, TimeSignature, TimeSignatureDisplay, Timestamp, Tuplet, TupletRatio,
|
TieClass, TimeExtent, TimeSignature, TimeSignatureDisplay, Timestamp, TuningContextSettings,
|
||||||
UnpitchedMember, ViewDefinition, Voice, VoiceOrigin, Volta,
|
Tuplet, TupletRatio, UnpitchedMember, ViewDefinition, Voice, VoiceOrigin, Volta,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use tempo::{
|
pub use tempo::{
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ use crate::graph::{
|
||||||
AnnotationAnchor, DecompositionSource, EventOrderingDAG, GestureAnchoring, KeySignature,
|
AnnotationAnchor, DecompositionSource, EventOrderingDAG, GestureAnchoring, KeySignature,
|
||||||
MetadataValue, RegionContent, RegionTimeModel, RepeatKind, ScoreTuningContext,
|
MetadataValue, RegionContent, RegionTimeModel, RepeatKind, ScoreTuningContext,
|
||||||
SoundConfiguration, SpaceUnit, SpannerKind, StaffGroupKind, TieClass, TimeSignature,
|
SoundConfiguration, SpaceUnit, SpannerKind, StaffGroupKind, TieClass, TimeSignature,
|
||||||
TimeSignatureDisplay, Timestamp, TupletRatio, VoiceOrigin,
|
TimeSignatureDisplay, Timestamp, TuningContextSettings, TupletRatio, VoiceOrigin,
|
||||||
};
|
};
|
||||||
use crate::textvalue::{kebab, Sexp, TextError, TextValue};
|
use crate::textvalue::{kebab, Sexp, TextError, TextValue};
|
||||||
use crate::textvalue_impls::class_of;
|
use crate::textvalue_impls::class_of;
|
||||||
|
|
@ -447,6 +447,38 @@ impl TextValue for ScoreTuningContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The **authored subset** of `ScoreTuningContext` that `SetTuningContext`
|
||||||
|
/// carries (genesis tranche G2b, `spec/CONTRACT_GENESIS_G2B_TUNING.md` §1) —
|
||||||
|
/// the same five fields, in the same order, as `ScoreTuningContext`'s
|
||||||
|
/// projection above; `accidental_extensions` has no field here to project.
|
||||||
|
impl TextValue for TuningContextSettings {
|
||||||
|
fn project(&self) -> Sexp {
|
||||||
|
Sexp::List(vec![
|
||||||
|
Sexp::Symbol(kebab("TuningContextSettings")),
|
||||||
|
self.default_pitch_space.project(),
|
||||||
|
self.default_tuning_system.project(),
|
||||||
|
self.reference.project(),
|
||||||
|
self.smufl.project(),
|
||||||
|
self.overrides.project(),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
fn parse(s: &Sexp) -> Result<Self, TextError> {
|
||||||
|
let fields = s.expect_struct(&kebab("TuningContextSettings"), 5)?;
|
||||||
|
let default_pitch_space = TextValue::parse(&fields[0])?;
|
||||||
|
let default_tuning_system = TextValue::parse(&fields[1])?;
|
||||||
|
let reference = TextValue::parse(&fields[2])?;
|
||||||
|
let smufl = TextValue::parse(&fields[3])?;
|
||||||
|
let overrides = TextValue::parse(&fields[4])?;
|
||||||
|
Ok(TuningContextSettings {
|
||||||
|
default_pitch_space,
|
||||||
|
default_tuning_system,
|
||||||
|
reference,
|
||||||
|
smufl,
|
||||||
|
overrides,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
// Tagged unions.
|
// Tagged unions.
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@
|
||||||
//! container is what the barrier's **scope** is for, and scope is matched
|
//! container is what the barrier's **scope** is for, and scope is matched
|
||||||
//! against the target's real containment, precisely.
|
//! against the target's real containment, precisely.
|
||||||
//! * **Score-level operations** (`SetMetadata`, the transaction descriptor,
|
//! * **Score-level operations** (`SetMetadata`, the transaction descriptor,
|
||||||
//! `SetCanvasLayoutDefaults`, `SetSpellingPrecedence`) name no graph object:
|
//! `SetCanvasLayoutDefaults`, `SetSpellingPrecedence`, `SetTuningContext`)
|
||||||
//! only a score-wide barrier (empty
|
//! name no graph object: only a score-wide barrier (empty
|
||||||
//! `affected_object_kinds`, `WholeScore`/`TuningContext`/`Registered` scope)
|
//! `affected_object_kinds`, `WholeScore`/`TuningContext`/`Registered` scope)
|
||||||
//! can match them.
|
//! can match them.
|
||||||
//! * **Extension-defined operations** (`OperationKind::Registered`) carry a
|
//! * **Extension-defined operations** (`OperationKind::Registered`) carry a
|
||||||
|
|
@ -469,7 +469,11 @@ pub(crate) fn subjects_of(kind: &OperationKind, score: &Score) -> BarrierSubject
|
||||||
OperationKind::SetMetadata(_)
|
OperationKind::SetMetadata(_)
|
||||||
| OperationKind::DeclareTransaction(_)
|
| OperationKind::DeclareTransaction(_)
|
||||||
| OperationKind::SetCanvasLayoutDefaults(_)
|
| OperationKind::SetCanvasLayoutDefaults(_)
|
||||||
| OperationKind::SetSpellingPrecedence(_) => BarrierSubjects::ScoreWide,
|
| OperationKind::SetSpellingPrecedence(_)
|
||||||
|
// Genesis tranche G2b (`CONTRACT_GENESIS_G2B_TUNING.md`, one-time
|
||||||
|
// authorization): another score-singleton field overwrite naming no
|
||||||
|
// resolvable region or object, exactly like `SetMetadata`.
|
||||||
|
| OperationKind::SetTuningContext(_) => BarrierSubjects::ScoreWide,
|
||||||
OperationKind::CreateRepeatStructure(op) => one(
|
OperationKind::CreateRepeatStructure(op) => one(
|
||||||
TypedObjectId::RepeatStructure(op.repeat_structure_id()),
|
TypedObjectId::RepeatStructure(op.repeat_structure_id()),
|
||||||
repeat_context(score, &op.repeat),
|
repeat_context(score, &op.repeat),
|
||||||
|
|
|
||||||
|
|
@ -1153,28 +1153,28 @@ mod tests {
|
||||||
tag: 7
|
tag: 7
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
// Operation-kind tag 34 is one past the vocabulary (the Phase-3 ops
|
// Operation-kind tag 35 is one past the vocabulary (the Phase-3 ops
|
||||||
// tranche appended 24..=27, the repeat pair 28/29, `TransposeInterval`
|
// tranche appended 24..=27, the repeat pair 28/29, `TransposeInterval`
|
||||||
// 30, genesis G1's `CreateInstrument` 31, genesis G2a's
|
// 30, genesis G1's `CreateInstrument` 31, genesis G2a's
|
||||||
// `SetCanvasLayoutDefaults` 32 and `SetSpellingPrecedence` 33;
|
// `SetCanvasLayoutDefaults` 32 and `SetSpellingPrecedence` 33,
|
||||||
// encodings are append-only).
|
// genesis G2b's `SetTuningContext` 34; encodings are append-only).
|
||||||
//
|
//
|
||||||
// This assertion named 30 until Push 5 / P4, 31 until genesis G1, and
|
// This assertion named 30 until Push 5 / P4, 31 until genesis G1, 32
|
||||||
// 32 until genesis G2a — each time, by then, the number had become a
|
// until genesis G2a, and 34 until genesis G2b — each time, by then,
|
||||||
// real kind, so the test was pinning a bug: a barrier that prohibited
|
// the number had become a real kind, so the test was pinning a bug: a
|
||||||
// the new operation encoded fine and would not read back. It must be
|
// barrier that prohibited the new operation encoded fine and would
|
||||||
// bumped by every tranche that appends a tag, and it is deliberately a
|
// not read back. It must be bumped by every tranche that appends a
|
||||||
// literal rather than `PAYLOAD_FREE.len()` so the bump is a conscious
|
// tag, and it is deliberately a literal rather than
|
||||||
// act.
|
// `PAYLOAD_FREE.len()` so the bump is a conscious act.
|
||||||
let mut bytes = vec![0u8];
|
let mut bytes = vec![0u8];
|
||||||
bytes.extend(set_blob(&[]));
|
bytes.extend(set_blob(&[]));
|
||||||
bytes.extend(set_blob(&[vec![34u8]]));
|
bytes.extend(set_blob(&[vec![35u8]]));
|
||||||
bytes.push(0);
|
bytes.push(0);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
EditBarrier::decode_canonical_bytes(&bytes),
|
EditBarrier::decode_canonical_bytes(&bytes),
|
||||||
Err(BarrierDecodeError::InvalidTag {
|
Err(BarrierDecodeError::InvalidTag {
|
||||||
kind: "OperationKindTag",
|
kind: "OperationKindTag",
|
||||||
tag: 34
|
tag: 35
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1888,3 +1888,72 @@ surface for a leak to appear on even before checking the hash. `gen_payload`
|
||||||
arms appended, reshuffling the seeded RNG stream exactly as at Phase D, Push
|
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
|
4a, and G1; the digest moved and was re-pinned with that reasoning recorded
|
||||||
in the test's own comment.
|
in the test's own comment.
|
||||||
|
|
||||||
|
## Genesis tranche G2b — `SetTuningContext`, kind/tag 34, the accept-set raise
|
||||||
|
## (2026-07-28)
|
||||||
|
|
||||||
|
`spec/CONTRACT_GENESIS_G2B_TUNING.md` lands the third rung: the sole genesis
|
||||||
|
payload born at schema major 3, and the one surface among the nine
|
||||||
|
settings/creates that drags `OperationEnvelopeBlock`'s accept-set from 2 to 3.
|
||||||
|
Its carried type is **not** the full `ScoreTuningContext` but the new
|
||||||
|
`epiphany_core::TuningContextSettings` — the authored subset of exactly the
|
||||||
|
five wire-bearing fields; see that crate's `DECISIONS.md` for why (the
|
||||||
|
never-authored / authored-to-default divergence a full-value payload would
|
||||||
|
have introduced).
|
||||||
|
|
||||||
|
`set_tuning_context` copies `set_metadata` structurally — advisory LWW, no
|
||||||
|
conflict, no idempotence short-circuit — but writes onto `score.tuning_context`
|
||||||
|
**field by field** rather than by whole-struct assignment, because the payload
|
||||||
|
carries a different (narrower) type than the field it targets:
|
||||||
|
`accidental_extensions` is left untouched in both the ordinary apply path and
|
||||||
|
undo's restoration-apply path. This is the one place in this rung's reduction
|
||||||
|
code that could not be a literal copy-paste of `set_metadata`/
|
||||||
|
`set_canvas_layout_defaults`/`set_spelling_precedence` — those three write
|
||||||
|
`score.<field> = op.<value>.clone()` in one line because the carried type
|
||||||
|
*is* the field's type; here it is a strict subset, so the assignment is five
|
||||||
|
lines, one per subset field, deliberately omitting `accidental_extensions`.
|
||||||
|
|
||||||
|
**Pin 5, verified rather than assumed.** An earlier draft of the governing
|
||||||
|
contract required undo to distinguish "never authored" from
|
||||||
|
"authored-to-default" — `spec/PLAN_GENESIS_OPS.md` §5 trap 5, withdrawn
|
||||||
|
2026-07-28 before this packet started. `tuning_context_chain` is seeded from
|
||||||
|
`Score::empty`'s default in `seed_from_graph`, exactly as `metadata_chain` is,
|
||||||
|
so the first undo of a `SetTuningContext` write yields
|
||||||
|
`Restore(Some(Predecessor::Base(seeded)))` regardless of whether the seed (or
|
||||||
|
the write) happened to equal the type default. Test t7 asserts the two cases
|
||||||
|
(default seed, non-default seed) restore identically — proving the
|
||||||
|
distinction unobservable, not merely failing to test for it.
|
||||||
|
|
||||||
|
`schema_major()` gains a real, unconditional arm returning 3 — the opposite of
|
||||||
|
G2a's "no arm" pin, because `ScoreTuningContext`'s `smufl`/`overrides` appends
|
||||||
|
are mandatory (not `Option`-hidden), so no lower-major layout for this payload
|
||||||
|
exists (a `CreateInstrument`-shaped arm, not a `CreateRegion`-shaped one).
|
||||||
|
|
||||||
|
**The accept-set raise is entirely `epiphany-bundle`'s change** (see that
|
||||||
|
crate's `DECISIONS.md`); this crate's contribution is making `SetTuningContext`
|
||||||
|
the value that requires it.
|
||||||
|
|
||||||
|
**Boundary crossings, budgeted as the contract's one-time authorization.**
|
||||||
|
`editor-core/src/barriers.rs::subjects_of` gains kind 34 in the same
|
||||||
|
score-wide `SetMetadata(_) | DeclareTransaction(_) | ...` arm G2a's two kinds
|
||||||
|
joined — a score-level field overwrite with no resolvable region or object.
|
||||||
|
`layout-ir/src/barrier.rs`'s "one past the vocabulary" literal moves 34→35.
|
||||||
|
`testkit/src/generators.rs`'s `rng.below` bound and
|
||||||
|
`testkit/tests/text_projection_grammar.rs`'s kind count both move by one.
|
||||||
|
`testkit/src/layout_stub.rs`'s derived `PAYLOAD_FREE`-based draw needed no
|
||||||
|
edit — confirmed, not assumed, per the contract's explicit ask (touch row 21)
|
||||||
|
— because it derives from the vocabulary macro rather than being hand-extended.
|
||||||
|
|
||||||
|
**Decode vector pinned to literal bytes** (`vectors.rs`,
|
||||||
|
`set_tuning_context_envelope_decode_vector_is_pinned_to_literal_bytes`), not
|
||||||
|
merely round-tripped — the plan's trap 4 (a self-consistent discriminant
|
||||||
|
reorder once passed 1283 tests and 8/8 conformance). Mutation-verified: a
|
||||||
|
one-byte corruption of the pinned discriminant produces
|
||||||
|
`InvalidTag { kind: "OperationKind", tag: 99 }`, observed directly rather than
|
||||||
|
inferred.
|
||||||
|
|
||||||
|
**No pruning or compaction is implemented, enabled, or prepared here** — pin
|
||||||
|
9's explicit non-goal. The op log is now the sole canonical carrier of the
|
||||||
|
tuning context (the canonical base embeds no graph value for any `Score`
|
||||||
|
field), which is exactly why a future prune must stay blocked on disposition
|
||||||
|
C; this packet adds no `fn prune` and no scaffolding toward one.
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,8 @@ use epiphany_core::{
|
||||||
CanvasLayoutDefaults, EventId, Instrument, InstrumentId, MetricGrid, MusicalPosition,
|
CanvasLayoutDefaults, EventId, Instrument, InstrumentId, MetricGrid, MusicalPosition,
|
||||||
OperationId, PitchId, PitchSpelling, RegionId, RegionTimeModel, RepeatStructureId, ReplicaId,
|
OperationId, PitchId, PitchSpelling, RegionId, RegionTimeModel, RepeatStructureId, ReplicaId,
|
||||||
ScoreMetadata, SpellingPrecedence, Staff, StaffInstance, StaffInstanceId,
|
ScoreMetadata, SpellingPrecedence, Staff, StaffInstance, StaffInstanceId,
|
||||||
StaffLineConfiguration, TimeAnchor, TimeSignature, TranspositionInterval, TupletId,
|
StaffLineConfiguration, TimeAnchor, TimeSignature, TranspositionInterval,
|
||||||
TypedObjectId, Voice, VoiceId, WallClockTime,
|
TuningContextSettings, TupletId, TypedObjectId, Voice, VoiceId, WallClockTime,
|
||||||
};
|
};
|
||||||
use epiphany_determinism::{CanonicalDecode, CanonicalEncode};
|
use epiphany_determinism::{CanonicalDecode, CanonicalEncode};
|
||||||
|
|
||||||
|
|
@ -596,6 +596,9 @@ fn operation_kind(r: &mut Reader<'_>) -> Result<OperationKind> {
|
||||||
33 => OperationKind::SetSpellingPrecedence(SetSpellingPrecedenceOp {
|
33 => OperationKind::SetSpellingPrecedence(SetSpellingPrecedenceOp {
|
||||||
precedence: value::<SpellingPrecedence>(r, "SpellingPrecedence")?,
|
precedence: value::<SpellingPrecedence>(r, "SpellingPrecedence")?,
|
||||||
}),
|
}),
|
||||||
|
34 => OperationKind::SetTuningContext(SetTuningContextOp {
|
||||||
|
settings: value::<TuningContextSettings>(r, "TuningContextSettings")?,
|
||||||
|
}),
|
||||||
tag => {
|
tag => {
|
||||||
return Err(EnvelopeDecodeError::InvalidTag {
|
return Err(EnvelopeDecodeError::InvalidTag {
|
||||||
kind: "OperationKind",
|
kind: "OperationKind",
|
||||||
|
|
@ -895,6 +898,11 @@ pub(crate) mod tests {
|
||||||
precedence: valuegen::spelling_precedence(1),
|
precedence: valuegen::spelling_precedence(1),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
OperationKindTag::SetTuningContext => {
|
||||||
|
OperationKind::SetTuningContext(SetTuningContextOp {
|
||||||
|
settings: valuegen::tuning_context_settings(1),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ fn pitch(n: u64) -> PitchId {
|
||||||
|
|
||||||
/// Generates a random payload over the shared id space.
|
/// Generates a random payload over the shared id space.
|
||||||
fn gen_payload(rng: &mut SplitMix64) -> OperationPayload {
|
fn gen_payload(rng: &mut SplitMix64) -> OperationPayload {
|
||||||
let kind = match rng.below(31) {
|
let kind = match rng.below(32) {
|
||||||
0 => {
|
0 => {
|
||||||
let voice = VoiceId::new(ReplicaId(7), rng.below(3));
|
let voice = VoiceId::new(ReplicaId(7), rng.below(3));
|
||||||
let position = MusicalPosition(RationalTime::from_int(rng.below(4) as i32));
|
let position = MusicalPosition(RationalTime::from_int(rng.below(4) as i32));
|
||||||
|
|
@ -300,6 +300,10 @@ fn gen_payload(rng: &mut SplitMix64) -> OperationPayload {
|
||||||
30 => OperationKind::SetSpellingPrecedence(crate::payload::SetSpellingPrecedenceOp {
|
30 => OperationKind::SetSpellingPrecedence(crate::payload::SetSpellingPrecedenceOp {
|
||||||
precedence: valuegen::spelling_precedence(rng.below(3) as u8),
|
precedence: valuegen::spelling_precedence(rng.below(3) as u8),
|
||||||
}),
|
}),
|
||||||
|
// Genesis tranche G2b: the sole genesis payload born at schema major 3.
|
||||||
|
31 => OperationKind::SetTuningContext(crate::payload::SetTuningContextOp {
|
||||||
|
settings: valuegen::tuning_context_settings(rng.below(3) as u8),
|
||||||
|
}),
|
||||||
_ => OperationKind::SetStaffLayout(SetStaffLayoutOp {
|
_ => OperationKind::SetStaffLayout(SetStaffLayoutOp {
|
||||||
staff_instance: StaffInstanceId::new(ReplicaId(7), rng.below(3)),
|
staff_instance: StaffInstanceId::new(ReplicaId(7), rng.below(3)),
|
||||||
instrument_override: None,
|
instrument_override: None,
|
||||||
|
|
|
||||||
|
|
@ -132,8 +132,9 @@ pub use payload::{
|
||||||
ModifyIdentifiedPitchOp, OperationKind, OperationKindTag, OperationPayload, PositionRemapping,
|
ModifyIdentifiedPitchOp, OperationKind, OperationKindTag, OperationPayload, PositionRemapping,
|
||||||
ResolveConflictPayload, ResolveEquivocationPayload, RespellPitchOp, SetCanvasLayoutDefaultsOp,
|
ResolveConflictPayload, ResolveEquivocationPayload, RespellPitchOp, SetCanvasLayoutDefaultsOp,
|
||||||
SetMetadataOp, SetMetricGridOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp,
|
SetMetadataOp, SetMetricGridOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp,
|
||||||
SetTimeSignatureOp, SetUserPageBreakOp, SetUserSystemBreakOp, TransactionCategory,
|
SetTimeSignatureOp, SetTuningContextOp, SetUserPageBreakOp, SetUserSystemBreakOp,
|
||||||
TransactionDescriptor, TransposeIntervalOp, TransposeOp, TupletCompensation,
|
TransactionCategory, TransactionDescriptor, TransposeIntervalOp, TransposeOp,
|
||||||
|
TupletCompensation,
|
||||||
};
|
};
|
||||||
pub use reduce::{
|
pub use reduce::{
|
||||||
canonical_reduction_order, GraphMaterialization, MaterializedState, ObjectState, PendingReason,
|
canonical_reduction_order, GraphMaterialization, MaterializedState, ObjectState, PendingReason,
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,8 @@ fn project_kind(kind: &OperationKind) -> V0OperationKind {
|
||||||
OperationKind::SetSpellingPrecedence(op) => {
|
OperationKind::SetSpellingPrecedence(op) => {
|
||||||
V0OperationKind::SetSpellingPrecedence(op.clone())
|
V0OperationKind::SetSpellingPrecedence(op.clone())
|
||||||
}
|
}
|
||||||
|
// Genesis tranche G2b: born past v0; projected verbatim.
|
||||||
|
OperationKind::SetTuningContext(op) => V0OperationKind::SetTuningContext(op.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -350,6 +352,8 @@ fn migrate_kind(kind: &V0OperationKind, context: &Score) -> Result<OperationKind
|
||||||
V0OperationKind::SetSpellingPrecedence(op) => {
|
V0OperationKind::SetSpellingPrecedence(op) => {
|
||||||
OperationKind::SetSpellingPrecedence(op.clone())
|
OperationKind::SetSpellingPrecedence(op.clone())
|
||||||
}
|
}
|
||||||
|
// Genesis tranche G2b: identity round-trip (no lossy v0 form).
|
||||||
|
V0OperationKind::SetTuningContext(op) => OperationKind::SetTuningContext(op.clone()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,8 @@ use epiphany_core::{
|
||||||
OperationId, Pitch, PitchId, PitchSpelling, Region, RegionId, RegionTimeModel, RepeatStructure,
|
OperationId, Pitch, PitchId, PitchSpelling, Region, RegionId, RegionTimeModel, RepeatStructure,
|
||||||
RepeatStructureId, Rest, ScoreMetadata, Slur, Spanner, SpellingPrecedence, Staff, StaffId,
|
RepeatStructureId, Rest, ScoreMetadata, Slur, Spanner, SpellingPrecedence, Staff, StaffId,
|
||||||
StaffInstance, StaffInstanceId, StaffLineConfiguration, TempoSegment, Tie, TimeAnchor,
|
StaffInstance, StaffInstanceId, StaffLineConfiguration, TempoSegment, Tie, TimeAnchor,
|
||||||
TimeSignature, TransactionId, TranspositionInterval, TupletId, TypedObjectId, Voice, VoiceId,
|
TimeSignature, TransactionId, TranspositionInterval, TuningContextSettings, TupletId,
|
||||||
|
TypedObjectId, Voice, VoiceId,
|
||||||
};
|
};
|
||||||
use epiphany_determinism::{
|
use epiphany_determinism::{
|
||||||
sorted_canonical, CanonicalDecode, CanonicalEncode, CanonicalSet, DecodeError,
|
sorted_canonical, CanonicalDecode, CanonicalEncode, CanonicalSet, DecodeError,
|
||||||
|
|
@ -263,6 +264,15 @@ pub enum OperationKind {
|
||||||
/// Overwrite the score's spelling precedence (later-in-canonical-order
|
/// Overwrite the score's spelling precedence (later-in-canonical-order
|
||||||
/// wins).
|
/// wins).
|
||||||
SetSpellingPrecedence(SetSpellingPrecedenceOp),
|
SetSpellingPrecedence(SetSpellingPrecedenceOp),
|
||||||
|
// --- Genesis tranche G2b (`spec/CONTRACT_GENESIS_G2B_TUNING.md`): the
|
||||||
|
// sole genesis payload born at schema major 3. Discriminant extends
|
||||||
|
// additively past 33.
|
||||||
|
// ---
|
||||||
|
/// Overwrite the score's tuning context settings (later-in-canonical-
|
||||||
|
/// order wins). Carries [`TuningContextSettings`], the authored subset of
|
||||||
|
/// `ScoreTuningContext` — `accidental_extensions` is not on the wire and
|
||||||
|
/// is left untouched by reduction (contract §1).
|
||||||
|
SetTuningContext(SetTuningContextOp),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OperationKind {
|
impl OperationKind {
|
||||||
|
|
@ -291,6 +301,13 @@ impl OperationKind {
|
||||||
| OperationKind::CreateStaff(_)
|
| OperationKind::CreateStaff(_)
|
||||||
| OperationKind::SetMetadata(_)
|
| OperationKind::SetMetadata(_)
|
||||||
| OperationKind::CreateInstrument(_) => 2,
|
| OperationKind::CreateInstrument(_) => 2,
|
||||||
|
// Genesis tranche G2b (contract pin 2): unconditionally 3.
|
||||||
|
// `ScoreTuningContext`'s `smufl`/`overrides` appends are
|
||||||
|
// mandatory, not `Option`-hidden, so there is no lower-major
|
||||||
|
// layout for this payload — a `CreateInstrument`-shaped arm, not
|
||||||
|
// a `CreateRegion`-shaped one. The sole surface among the nine
|
||||||
|
// genesis settings/creates that raises the op-block accept-set.
|
||||||
|
OperationKind::SetTuningContext(_) => 3,
|
||||||
// Value-dependent: the embedded StaffLineConfiguration rides an
|
// Value-dependent: the embedded StaffLineConfiguration rides an
|
||||||
// Option; None encodes byte-identically to the prior major.
|
// Option; None encodes byte-identically to the prior major.
|
||||||
OperationKind::CreateRegion(op) => {
|
OperationKind::CreateRegion(op) => {
|
||||||
|
|
@ -368,6 +385,9 @@ impl OperationKind {
|
||||||
// by the same accident as above, not by rule.
|
// by the same accident as above, not by rule.
|
||||||
OperationKind::SetCanvasLayoutDefaults(_) => 32,
|
OperationKind::SetCanvasLayoutDefaults(_) => 32,
|
||||||
OperationKind::SetSpellingPrecedence(_) => 33,
|
OperationKind::SetSpellingPrecedence(_) => 33,
|
||||||
|
// Genesis tranche G2b; appended past 33. Coincides with tag 34 by
|
||||||
|
// the same accident as G1/G2a, not by rule.
|
||||||
|
OperationKind::SetTuningContext(_) => 34,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -424,6 +444,9 @@ impl OperationKind {
|
||||||
OperationKind::SetCanvasLayoutDefaults(_) | OperationKind::SetSpellingPrecedence(_) => {
|
OperationKind::SetCanvasLayoutDefaults(_) | OperationKind::SetSpellingPrecedence(_) => {
|
||||||
Some(9)
|
Some(9)
|
||||||
}
|
}
|
||||||
|
// Minor 10 (Genesis tranche G2b), ratified
|
||||||
|
// `spec/PLAN_GMINOR_SCHEMA_MINOR.md` §4.
|
||||||
|
OperationKind::SetTuningContext(_) => Some(10),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -471,6 +494,7 @@ impl OperationKind {
|
||||||
OperationKind::CreateInstrument(_) => OperationKindTag::CreateInstrument,
|
OperationKind::CreateInstrument(_) => OperationKindTag::CreateInstrument,
|
||||||
OperationKind::SetCanvasLayoutDefaults(_) => OperationKindTag::SetCanvasLayoutDefaults,
|
OperationKind::SetCanvasLayoutDefaults(_) => OperationKindTag::SetCanvasLayoutDefaults,
|
||||||
OperationKind::SetSpellingPrecedence(_) => OperationKindTag::SetSpellingPrecedence,
|
OperationKind::SetSpellingPrecedence(_) => OperationKindTag::SetSpellingPrecedence,
|
||||||
|
OperationKind::SetTuningContext(_) => OperationKindTag::SetTuningContext,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -516,6 +540,7 @@ impl CanonicalEncode for OperationKind {
|
||||||
OperationKind::CreateInstrument(op) => op.encode_canonical(out),
|
OperationKind::CreateInstrument(op) => op.encode_canonical(out),
|
||||||
OperationKind::SetCanvasLayoutDefaults(op) => op.encode_canonical(out),
|
OperationKind::SetCanvasLayoutDefaults(op) => op.encode_canonical(out),
|
||||||
OperationKind::SetSpellingPrecedence(op) => op.encode_canonical(out),
|
OperationKind::SetSpellingPrecedence(op) => op.encode_canonical(out),
|
||||||
|
OperationKind::SetTuningContext(op) => op.encode_canonical(out),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -570,6 +595,8 @@ pub enum OperationKindTag {
|
||||||
SetCanvasLayoutDefaults,
|
SetCanvasLayoutDefaults,
|
||||||
/// Genesis tranche G2a.
|
/// Genesis tranche G2a.
|
||||||
SetSpellingPrecedence,
|
SetSpellingPrecedence,
|
||||||
|
/// Genesis tranche G2b.
|
||||||
|
SetTuningContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The discriminant of [`OperationKindTag::Registered`], the one tag that
|
/// The discriminant of [`OperationKindTag::Registered`], the one tag that
|
||||||
|
|
@ -684,6 +711,7 @@ operation_kind_tag_vocabulary! {
|
||||||
CreateInstrument = 31 => "create-instrument" @ Some(8),
|
CreateInstrument = 31 => "create-instrument" @ Some(8),
|
||||||
SetCanvasLayoutDefaults = 32 => "set-canvas-layout-defaults" @ Some(9),
|
SetCanvasLayoutDefaults = 32 => "set-canvas-layout-defaults" @ Some(9),
|
||||||
SetSpellingPrecedence = 33 => "set-spelling-precedence" @ Some(9),
|
SetSpellingPrecedence = 33 => "set-spelling-precedence" @ Some(9),
|
||||||
|
SetTuningContext = 34 => "set-tuning-context" @ Some(10),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CanonicalEncode for OperationKindTag {
|
impl CanonicalEncode for OperationKindTag {
|
||||||
|
|
@ -1650,6 +1678,30 @@ impl CanonicalEncode for SetSpellingPrecedenceOp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Genesis tranche G2b (`spec/CONTRACT_GENESIS_G2B_TUNING.md`): the sole
|
||||||
|
// genesis payload born at schema major 3. LWW field-overwrite, the same
|
||||||
|
// `SetMetadata` discipline. ---
|
||||||
|
|
||||||
|
/// Overwrite the score's tuning context settings (operation_catalog
|
||||||
|
/// §SetTuningContext). Carries [`TuningContextSettings`] — the **authored
|
||||||
|
/// subset** of `ScoreTuningContext` (contract §1): exactly the five
|
||||||
|
/// wire-bearing fields, in the codec's existing order.
|
||||||
|
/// `accidental_extensions` is not a field of the carried type and is never
|
||||||
|
/// touched by reduction, which writes only these five fields onto
|
||||||
|
/// `score.tuning_context`. 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 SetTuningContextOp {
|
||||||
|
pub settings: TuningContextSettings,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CanonicalEncode for SetTuningContextOp {
|
||||||
|
fn encode_canonical(&self, out: &mut Vec<u8>) {
|
||||||
|
push_lp_bytes(out, &self.settings.canonical_bytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Set, replace, or (`None`) remove the single meter change at the anchor's
|
/// Set, replace, or (`None`) remove the single meter change at the anchor's
|
||||||
/// resolved musical position in a region's default metric grid
|
/// resolved musical position in a region's default metric grid
|
||||||
/// (operation_catalog §"Meter and Tempo Overwrites"). Carries the full
|
/// (operation_catalog §"Meter and Tempo Overwrites"). Carries the full
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ use epiphany_core::{
|
||||||
SpellingDirective, SpellingPrecedence, SpellingScope, SpellingSource, Staff, StaffId,
|
SpellingDirective, SpellingPrecedence, SpellingScope, SpellingSource, Staff, StaffId,
|
||||||
StaffInstance, StaffInstanceId, StaffLineConfiguration, TempoMap, TempoSegment, TempoShape,
|
StaffInstance, StaffInstanceId, StaffLineConfiguration, TempoMap, TempoSegment, TempoShape,
|
||||||
TimeAnchor, TimeSignature, TimeSignatureId, TransactionId, TransposeRefusal,
|
TimeAnchor, TimeSignature, TimeSignatureId, TransactionId, TransposeRefusal,
|
||||||
TranspositionInterval, TypedObjectId, Voice, VoiceId, VoiceOrigin,
|
TranspositionInterval, TuningContextSettings, TypedObjectId, Voice, VoiceId, VoiceOrigin,
|
||||||
};
|
};
|
||||||
use epiphany_determinism::CanonicalEncode;
|
use epiphany_determinism::CanonicalEncode;
|
||||||
|
|
||||||
|
|
@ -63,7 +63,8 @@ use crate::payload::{
|
||||||
InsertIdentifiedPitchOp, ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp,
|
InsertIdentifiedPitchOp, ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp,
|
||||||
OperationKind, OperationPayload, RespellPitchOp, SetCanvasLayoutDefaultsOp, SetMetadataOp,
|
OperationKind, OperationPayload, RespellPitchOp, SetCanvasLayoutDefaultsOp, SetMetadataOp,
|
||||||
SetMetricGridOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp,
|
SetMetricGridOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp,
|
||||||
SetTimeSignatureOp, SetUserPageBreakOp, TransposeIntervalOp, TransposeOp, TupletCompensation,
|
SetTimeSignatureOp, SetTuningContextOp, SetUserPageBreakOp, TransposeIntervalOp, TransposeOp,
|
||||||
|
TupletCompensation,
|
||||||
};
|
};
|
||||||
use crate::stamp::StampTuple;
|
use crate::stamp::StampTuple;
|
||||||
use crate::support::{ObjectKind, SerializedCanonicalInputs};
|
use crate::support::{ObjectKind, SerializedCanonicalInputs};
|
||||||
|
|
@ -851,6 +852,11 @@ enum ValueRestoration {
|
||||||
SpellingPrecedence {
|
SpellingPrecedence {
|
||||||
value: Option<SpellingPrecedence>,
|
value: Option<SpellingPrecedence>,
|
||||||
},
|
},
|
||||||
|
/// Genesis tranche G2b. The subset type — `accidental_extensions` is not
|
||||||
|
/// part of it and is never touched by restoration.
|
||||||
|
TuningContext {
|
||||||
|
value: Option<TuningContextSettings>,
|
||||||
|
},
|
||||||
MetricGrid {
|
MetricGrid {
|
||||||
region: RegionId,
|
region: RegionId,
|
||||||
value: Option<MetricGrid>,
|
value: Option<MetricGrid>,
|
||||||
|
|
@ -972,6 +978,11 @@ struct Reducer<'a> {
|
||||||
// the pre-operational value.
|
// the pre-operational value.
|
||||||
canvas_layout_defaults_chain: WriteChain<CanvasLayoutDefaults>,
|
canvas_layout_defaults_chain: WriteChain<CanvasLayoutDefaults>,
|
||||||
spelling_precedence_chain: WriteChain<SpellingPrecedence>,
|
spelling_precedence_chain: WriteChain<SpellingPrecedence>,
|
||||||
|
// Genesis tranche G2b (`CONTRACT_GENESIS_G2B_TUNING.md` pin 5): same
|
||||||
|
// discipline, carrying the **subset** type — `accidental_extensions`
|
||||||
|
// never participates in undo, because no operation ever writes it and
|
||||||
|
// undo must leave it exactly as it found it.
|
||||||
|
tuning_context_chain: WriteChain<TuningContextSettings>,
|
||||||
break_chain: BTreeMap<(RegionId, MusicalPosition), WriteChain<(TimeAnchor, bool)>>,
|
break_chain: BTreeMap<(RegionId, MusicalPosition), WriteChain<(TimeAnchor, bool)>>,
|
||||||
page_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
|
// Meter/tempo overwrite chains (Phase-3 tranche): `Some` = a set/replace at
|
||||||
|
|
@ -1085,6 +1096,7 @@ struct WorkingSnapshot {
|
||||||
metadata_chain: WriteChain<ScoreMetadata>,
|
metadata_chain: WriteChain<ScoreMetadata>,
|
||||||
canvas_layout_defaults_chain: WriteChain<CanvasLayoutDefaults>,
|
canvas_layout_defaults_chain: WriteChain<CanvasLayoutDefaults>,
|
||||||
spelling_precedence_chain: WriteChain<SpellingPrecedence>,
|
spelling_precedence_chain: WriteChain<SpellingPrecedence>,
|
||||||
|
tuning_context_chain: WriteChain<TuningContextSettings>,
|
||||||
break_chain: BTreeMap<(RegionId, MusicalPosition), WriteChain<(TimeAnchor, bool)>>,
|
break_chain: BTreeMap<(RegionId, MusicalPosition), WriteChain<(TimeAnchor, bool)>>,
|
||||||
page_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>>>,
|
meter_change_chain: BTreeMap<(RegionId, MusicalPosition), WriteChain<Option<MeterChange>>>,
|
||||||
|
|
@ -1367,6 +1379,7 @@ impl<'a> Reducer<'a> {
|
||||||
metadata_chain: WriteChain::new(),
|
metadata_chain: WriteChain::new(),
|
||||||
canvas_layout_defaults_chain: WriteChain::new(),
|
canvas_layout_defaults_chain: WriteChain::new(),
|
||||||
spelling_precedence_chain: WriteChain::new(),
|
spelling_precedence_chain: WriteChain::new(),
|
||||||
|
tuning_context_chain: WriteChain::new(),
|
||||||
break_chain: BTreeMap::new(),
|
break_chain: BTreeMap::new(),
|
||||||
page_break_chain: BTreeMap::new(),
|
page_break_chain: BTreeMap::new(),
|
||||||
meter_change_chain: BTreeMap::new(),
|
meter_change_chain: BTreeMap::new(),
|
||||||
|
|
@ -1469,6 +1482,17 @@ impl<'a> Reducer<'a> {
|
||||||
.seed(score.canvas.layout_defaults);
|
.seed(score.canvas.layout_defaults);
|
||||||
self.spelling_precedence_chain
|
self.spelling_precedence_chain
|
||||||
.seed(score.spelling_precedence.clone());
|
.seed(score.spelling_precedence.clone());
|
||||||
|
// Genesis tranche G2b (contract pin 5): same discipline, seeded with
|
||||||
|
// only the five wire-bearing fields — the subset the chain's value
|
||||||
|
// type carries. `accidental_extensions` is not part of the seed and
|
||||||
|
// is never touched by undo.
|
||||||
|
self.tuning_context_chain.seed(TuningContextSettings {
|
||||||
|
default_pitch_space: score.tuning_context.default_pitch_space.clone(),
|
||||||
|
default_tuning_system: score.tuning_context.default_tuning_system.clone(),
|
||||||
|
reference: score.tuning_context.reference.clone(),
|
||||||
|
smufl: score.tuning_context.smufl,
|
||||||
|
overrides: score.tuning_context.overrides.clone(),
|
||||||
|
});
|
||||||
for segment in &score.tempo_map.segments {
|
for segment in &score.tempo_map.segments {
|
||||||
self.tempo_segment_chain
|
self.tempo_segment_chain
|
||||||
.entry((None, resolved_anchor_position(&segment.start)))
|
.entry((None, resolved_anchor_position(&segment.start)))
|
||||||
|
|
@ -2833,6 +2857,7 @@ impl<'a> Reducer<'a> {
|
||||||
self.set_canvas_layout_defaults(env, op)
|
self.set_canvas_layout_defaults(env, op)
|
||||||
}
|
}
|
||||||
OperationKind::SetSpellingPrecedence(op) => self.set_spelling_precedence(env, op),
|
OperationKind::SetSpellingPrecedence(op) => self.set_spelling_precedence(env, op),
|
||||||
|
OperationKind::SetTuningContext(op) => self.set_tuning_context(env, op),
|
||||||
},
|
},
|
||||||
OperationPayload::ResolveConflict(op) => self.resolve_conflict(env, op),
|
OperationPayload::ResolveConflict(op) => self.resolve_conflict(env, op),
|
||||||
OperationPayload::UndoTransaction(op) => self.undo_transaction(env, op),
|
OperationPayload::UndoTransaction(op) => self.undo_transaction(env, op),
|
||||||
|
|
@ -2947,6 +2972,30 @@ impl<'a> Reducer<'a> {
|
||||||
OperationEffect::Applied
|
OperationEffect::Applied
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Genesis tranche G2b (`CONTRACT_GENESIS_G2B_TUNING.md` pin 5): copies
|
||||||
|
/// `set_metadata` structurally — advisory LWW, no conflict, no
|
||||||
|
/// idempotence short-circuit. Writes exactly the five subset fields onto
|
||||||
|
/// `score.tuning_context` and **leaves `accidental_extensions`
|
||||||
|
/// untouched** — the carried payload has no such field, and preserving
|
||||||
|
/// whatever the graph already held is the ruling (contract §1).
|
||||||
|
fn set_tuning_context(
|
||||||
|
&mut self,
|
||||||
|
env: &OperationEnvelope,
|
||||||
|
op: &SetTuningContextOp,
|
||||||
|
) -> OperationEffect {
|
||||||
|
self.tuning_context_chain
|
||||||
|
.record(env.id, env.transaction, op.settings.clone());
|
||||||
|
if let Some(score) = self.graph.as_mut() {
|
||||||
|
score.tuning_context.default_pitch_space = op.settings.default_pitch_space.clone();
|
||||||
|
score.tuning_context.default_tuning_system = op.settings.default_tuning_system.clone();
|
||||||
|
score.tuning_context.reference = op.settings.reference.clone();
|
||||||
|
score.tuning_context.smufl = op.settings.smufl;
|
||||||
|
score.tuning_context.overrides = op.settings.overrides.clone();
|
||||||
|
// accidental_extensions is intentionally not touched here.
|
||||||
|
}
|
||||||
|
OperationEffect::Applied
|
||||||
|
}
|
||||||
|
|
||||||
fn set_metric_grid(
|
fn set_metric_grid(
|
||||||
&mut self,
|
&mut self,
|
||||||
env: &OperationEnvelope,
|
env: &OperationEnvelope,
|
||||||
|
|
@ -5334,6 +5383,16 @@ impl<'a> Reducer<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Genesis tranche G2b (contract pin 5): mirror the same shape.
|
||||||
|
match self.tuning_context_chain.undo_verdict(tx) {
|
||||||
|
ChainUndoVerdict::NotWritten => {}
|
||||||
|
ChainUndoVerdict::Superseded { by } => superseded.push(by),
|
||||||
|
ChainUndoVerdict::Restore(predecessor) => {
|
||||||
|
restorations.push(ValueRestoration::TuningContext {
|
||||||
|
value: predecessor.map(Predecessor::into_value),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
for (region, chain) in &self.metric_grid_chain {
|
for (region, chain) in &self.metric_grid_chain {
|
||||||
if !slot_live(TypedObjectId::Region(*region)) {
|
if !slot_live(TypedObjectId::Region(*region)) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -5574,6 +5633,24 @@ impl<'a> Reducer<'a> {
|
||||||
.record(env.id, env.transaction, value);
|
.record(env.id, env.transaction, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Genesis tranche G2b (contract pin 5): mirror `Metadata`'s
|
||||||
|
// restoration-apply shape; writes only the five subset
|
||||||
|
// fields, leaving `accidental_extensions` untouched.
|
||||||
|
ValueRestoration::TuningContext { value } => {
|
||||||
|
if let Some(value) = value {
|
||||||
|
if let Some(score) = self.graph.as_mut() {
|
||||||
|
score.tuning_context.default_pitch_space =
|
||||||
|
value.default_pitch_space.clone();
|
||||||
|
score.tuning_context.default_tuning_system =
|
||||||
|
value.default_tuning_system.clone();
|
||||||
|
score.tuning_context.reference = value.reference.clone();
|
||||||
|
score.tuning_context.smufl = value.smufl;
|
||||||
|
score.tuning_context.overrides = value.overrides.clone();
|
||||||
|
}
|
||||||
|
self.tuning_context_chain
|
||||||
|
.record(env.id, env.transaction, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
ValueRestoration::MetricGrid { region, value } => {
|
ValueRestoration::MetricGrid { region, value } => {
|
||||||
self.metric_grid_chain
|
self.metric_grid_chain
|
||||||
.entry(region)
|
.entry(region)
|
||||||
|
|
@ -7551,6 +7628,7 @@ impl<'a> Reducer<'a> {
|
||||||
metadata_chain: self.metadata_chain.clone(),
|
metadata_chain: self.metadata_chain.clone(),
|
||||||
canvas_layout_defaults_chain: self.canvas_layout_defaults_chain.clone(),
|
canvas_layout_defaults_chain: self.canvas_layout_defaults_chain.clone(),
|
||||||
spelling_precedence_chain: self.spelling_precedence_chain.clone(),
|
spelling_precedence_chain: self.spelling_precedence_chain.clone(),
|
||||||
|
tuning_context_chain: self.tuning_context_chain.clone(),
|
||||||
break_chain: self.break_chain.clone(),
|
break_chain: self.break_chain.clone(),
|
||||||
page_break_chain: self.page_break_chain.clone(),
|
page_break_chain: self.page_break_chain.clone(),
|
||||||
meter_change_chain: self.meter_change_chain.clone(),
|
meter_change_chain: self.meter_change_chain.clone(),
|
||||||
|
|
@ -7590,6 +7668,7 @@ impl<'a> Reducer<'a> {
|
||||||
self.metadata_chain = s.metadata_chain;
|
self.metadata_chain = s.metadata_chain;
|
||||||
self.canvas_layout_defaults_chain = s.canvas_layout_defaults_chain;
|
self.canvas_layout_defaults_chain = s.canvas_layout_defaults_chain;
|
||||||
self.spelling_precedence_chain = s.spelling_precedence_chain;
|
self.spelling_precedence_chain = s.spelling_precedence_chain;
|
||||||
|
self.tuning_context_chain = s.tuning_context_chain;
|
||||||
self.break_chain = s.break_chain;
|
self.break_chain = s.break_chain;
|
||||||
self.page_break_chain = s.page_break_chain;
|
self.page_break_chain = s.page_break_chain;
|
||||||
self.meter_change_chain = s.meter_change_chain;
|
self.meter_change_chain = s.meter_change_chain;
|
||||||
|
|
@ -10914,6 +10993,92 @@ mod tests {
|
||||||
0,
|
0,
|
||||||
"SetSpellingPrecedence stays in the major-0 catch-all"
|
"SetSpellingPrecedence stays in the major-0 catch-all"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// (t2) Genesis tranche G2b: the opposite of G2a's pin — SetTuningContext
|
||||||
|
// is *unconditionally* 3, the same "no lower-major layout exists" shape
|
||||||
|
// as CreateInstrument above (not a value-dependent Option-hidden
|
||||||
|
// embedding). Asserted on the minimal (default) settings specifically,
|
||||||
|
// so an arm that becomes value-dependent is caught immediately.
|
||||||
|
assert_eq!(
|
||||||
|
OperationKind::SetTuningContext(crate::payload::SetTuningContextOp {
|
||||||
|
settings: crate::valuegen::tuning_context_settings(0),
|
||||||
|
})
|
||||||
|
.schema_major(),
|
||||||
|
3,
|
||||||
|
"SetTuningContext is unconditionally v3, even for the minimal settings"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// (t1) Genesis tranche G2b: kind and tag are both 34, and the
|
||||||
|
/// discriminant byte leads the canonical encoding of the op payload.
|
||||||
|
///
|
||||||
|
/// **Mutation:** move either `OperationKind::SetTuningContext`'s
|
||||||
|
/// discriminant or `OperationKindTag::SetTuningContext`'s tag to 35;
|
||||||
|
/// must fail.
|
||||||
|
#[test]
|
||||||
|
fn t1_set_tuning_context_kind_and_tag_are_both_34() {
|
||||||
|
use crate::payload::{OperationKindTag, SetTuningContextOp};
|
||||||
|
let op = OperationKind::SetTuningContext(SetTuningContextOp {
|
||||||
|
settings: crate::valuegen::tuning_context_settings(1),
|
||||||
|
});
|
||||||
|
assert_eq!(op.tag(), OperationKindTag::SetTuningContext);
|
||||||
|
assert_eq!(op.tag().discriminant(), 34);
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
op.encode_canonical(&mut bytes);
|
||||||
|
assert_eq!(
|
||||||
|
bytes[0], 34,
|
||||||
|
"the discriminant byte must lead the canonical encoding"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// (t3) Genesis tranche G2b: a block containing exactly one
|
||||||
|
/// `SetTuningContext` stamps schema major 3.
|
||||||
|
///
|
||||||
|
/// **Mutation:** make `schema_major` ignore the `SetTuningContext` arm
|
||||||
|
/// (fold it into the catch-all `_ => 0`); must fail.
|
||||||
|
#[test]
|
||||||
|
fn t3_a_block_with_one_set_tuning_context_stamps_major_3() {
|
||||||
|
let op = OperationKind::SetTuningContext(crate::payload::SetTuningContextOp {
|
||||||
|
settings: crate::valuegen::tuning_context_settings(1),
|
||||||
|
});
|
||||||
|
let envelopes = [op.clone()];
|
||||||
|
let major = envelopes.iter().map(|k| k.schema_major()).max().unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
major, 3,
|
||||||
|
"a block carrying only SetTuningContext stamps major 3"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// (t8) Genesis tranche G2b: kind 34 carries epoch 10
|
||||||
|
/// (`spec/PLAN_GMINOR_SCHEMA_MINOR.md` §4), and a block containing it
|
||||||
|
/// stamps schema minor 10.
|
||||||
|
///
|
||||||
|
/// **Mutation:** assign epoch 9 instead of 10 in `introduced_minor`'s
|
||||||
|
/// `SetTuningContext` arm; must fail.
|
||||||
|
#[test]
|
||||||
|
fn t8_set_tuning_context_carries_epoch_10() {
|
||||||
|
let op = OperationKind::SetTuningContext(crate::payload::SetTuningContextOp {
|
||||||
|
settings: crate::valuegen::tuning_context_settings(1),
|
||||||
|
});
|
||||||
|
assert_eq!(op.introduced_minor(), Some(10));
|
||||||
|
assert_eq!(op.tag().introduced_minor(), Some(10));
|
||||||
|
|
||||||
|
let env = OperationEnvelope {
|
||||||
|
id: OperationId::new(ReplicaId(1), 1),
|
||||||
|
author: crate::support::AuthorId(0),
|
||||||
|
stamp: crate::stamp::OperationStamp::new(
|
||||||
|
crate::stamp::HybridLogicalClock::new(epiphany_core::WallClockTime(1), 1),
|
||||||
|
OperationId::new(ReplicaId(1), 1),
|
||||||
|
),
|
||||||
|
causal_context: crate::causal::CausalContext::new(),
|
||||||
|
transaction: None,
|
||||||
|
payload: OperationPayload::Primitive(op),
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
crate::payload::operation_block_introduced_minor(&[env]),
|
||||||
|
Some(10),
|
||||||
|
"a block containing kind 34 stamps minor 10"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -11007,6 +11172,16 @@ mod tests {
|
||||||
// leak to appear on even if the base did stamp one (it does not —
|
// leak to appear on even if the base did stamp one (it does not —
|
||||||
// that is `OperationEnvelopeBlock`'s concern in `epiphany-bundle`,
|
// that is `OperationEnvelopeBlock`'s concern in `epiphany-bundle`,
|
||||||
// untouched by this packet).
|
// untouched by this packet).
|
||||||
|
//
|
||||||
|
// Re-pinned again at genesis tranche G2b
|
||||||
|
// (`spec/CONTRACT_GENESIS_G2B_TUNING.md`): `gen_payload` gained
|
||||||
|
// `SetTuningContext` (arm 31), and `rng.below(31)` became
|
||||||
|
// `below(32)` — the same reshuffle, same reasoning. `SetTuningContext`
|
||||||
|
// is schema major **3**, unlike its siblings, but that is
|
||||||
|
// `OperationEnvelopeBlock`'s concern (`epiphany-bundle`), not
|
||||||
|
// `MaterializedState`'s: the canonical base still embeds no `Score`
|
||||||
|
// field value for any setting, so there remains no schema-major
|
||||||
|
// surface on this type for a leak to appear on.
|
||||||
let mut rng = epiphany_determinism::fuzz::SplitMix64::new(0xBA5E);
|
let mut rng = epiphany_determinism::fuzz::SplitMix64::new(0xBA5E);
|
||||||
let envelopes = crate::fuzz::gen_envelope_set(&mut rng, 200);
|
let envelopes = crate::fuzz::gen_envelope_set(&mut rng, 200);
|
||||||
let mut set = OperationSet::new();
|
let mut set = OperationSet::new();
|
||||||
|
|
@ -11016,7 +11191,7 @@ mod tests {
|
||||||
let hex: String = digest.iter().map(|b| format!("{b:02x}")).collect();
|
let hex: String = digest.iter().map(|b| format!("{b:02x}")).collect();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
hex,
|
hex,
|
||||||
"7fd6455a6ae304101774ba981d01702ad37c567575707b1e814dad6e153ab07d"
|
"116e88b4013a18864dcd1b09489ab297aa332e14800cf4ca00be9dfa100b4a08"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -12952,6 +13127,55 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// (t9) Regression guard: the from-empty spine still reaches a note, now
|
||||||
|
/// with a `SetTuningContext` authored alongside it — genesis tranche G2b
|
||||||
|
/// does not disturb the spine G1 established. Mutation is t2's (the
|
||||||
|
/// `schema_major` arm), which this test does not re-verify on its own;
|
||||||
|
/// its job is to prove the spine and the new op coexist cleanly.
|
||||||
|
#[test]
|
||||||
|
fn from_empty_spine_reaches_a_note_with_a_tuning_context_authored() {
|
||||||
|
let spine = genesis_spine_envelopes();
|
||||||
|
let settings = crate::valuegen::tuning_context_settings(1);
|
||||||
|
let set_tuning = prim_env(
|
||||||
|
1,
|
||||||
|
12,
|
||||||
|
70,
|
||||||
|
CausalContext::new(),
|
||||||
|
OperationKind::SetTuningContext(crate::payload::SetTuningContextOp {
|
||||||
|
settings: settings.clone(),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
let mut envelopes = spine.envelopes;
|
||||||
|
envelopes.push(set_tuning);
|
||||||
|
let mut set = OperationSet::new();
|
||||||
|
set.accept_all(envelopes);
|
||||||
|
let identity = IdentityContext::new(ReplicaId(1));
|
||||||
|
let out = reduce_operation_set_onto(&set, &Score::empty(identity));
|
||||||
|
|
||||||
|
for counter in [0, 2, 4, 6, 8, 10, 12] {
|
||||||
|
assert_eq!(
|
||||||
|
effect_at(&out.state, counter),
|
||||||
|
Some(&OperationEffect::Applied),
|
||||||
|
"spine operation at counter {counter} must apply"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
assert!(
|
||||||
|
out.score.events.contains(spine.event_id),
|
||||||
|
"the spine still reaches a note"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
out.score.tuning_context.default_pitch_space,
|
||||||
|
settings.default_pitch_space
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
out.score.tuning_context.default_tuning_system,
|
||||||
|
settings.default_tuning_system
|
||||||
|
);
|
||||||
|
assert_eq!(out.score.tuning_context.reference, settings.reference);
|
||||||
|
assert_eq!(out.score.tuning_context.smufl, settings.smufl);
|
||||||
|
assert_eq!(out.score.tuning_context.overrides, settings.overrides);
|
||||||
|
}
|
||||||
|
|
||||||
/// (i2) Re-carry idempotence: the same `CreateInstrument` twice ->
|
/// (i2) Re-carry idempotence: the same `CreateInstrument` twice ->
|
||||||
/// `AlreadyApplied`, and a differing second carry under the same live id
|
/// `AlreadyApplied`, and a differing second carry under the same live id
|
||||||
/// -> `RecreateContentMismatch` — exactly `create_staff`'s discipline
|
/// -> `RecreateContentMismatch` — exactly `create_staff`'s discipline
|
||||||
|
|
@ -13511,6 +13735,245 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Genesis tranche G2b (`spec/CONTRACT_GENESIS_G2B_TUNING.md`): the sole
|
||||||
|
// genesis payload born at schema major 3, `SetTuningContext`.
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/// (t5) **The pin's whole reason for existing** (contract §1): an op
|
||||||
|
/// authored **live** and the same op reloaded **from bytes** must
|
||||||
|
/// reduce to identical graph states, with a pre-existing non-empty
|
||||||
|
/// `accidental_extensions` preserved across both. This is what the
|
||||||
|
/// subset type (pin 1) makes structurally impossible to get wrong — a
|
||||||
|
/// full-value `SetTuningContext(ScoreTuningContext)` would diverge here,
|
||||||
|
/// because `OperationSet::accept` stores the authored envelope as a
|
||||||
|
/// **value** (live path keeps whatever `accidental_extensions` the
|
||||||
|
/// constructor set) while a decoded envelope always reconstructs it as
|
||||||
|
/// empty (the wire drops it).
|
||||||
|
///
|
||||||
|
/// **Mutation:** make the payload carry the full `ScoreTuningContext`
|
||||||
|
/// instead of the subset `TuningContextSettings`; must fail. Performed
|
||||||
|
/// and reversed live for this rung (see the report) rather than left in
|
||||||
|
/// the tree, since it requires the type-level change pin 1 forbids.
|
||||||
|
#[test]
|
||||||
|
fn t5_live_authored_and_reloaded_from_bytes_agree_with_extensions_preserved() {
|
||||||
|
use epiphany_core::{AccidentalRegistryId, ScoreAccidentalExtensions};
|
||||||
|
|
||||||
|
// A base graph with a pre-existing, non-empty accidental_extensions —
|
||||||
|
// the field the op never carries and reduction must leave untouched.
|
||||||
|
let mut base = Score::empty(IdentityContext::new(ReplicaId(1)));
|
||||||
|
let pre_existing = vec![ScoreAccidentalExtensions {
|
||||||
|
base: AccidentalRegistryId::new("heji"),
|
||||||
|
additions: Vec::new(),
|
||||||
|
overrides: Vec::new(),
|
||||||
|
}];
|
||||||
|
base.tuning_context.accidental_extensions = pre_existing.clone();
|
||||||
|
|
||||||
|
let settings = crate::valuegen::tuning_context_settings(3);
|
||||||
|
let live_env = prim_env(
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
10,
|
||||||
|
CausalContext::new(),
|
||||||
|
OperationKind::SetTuningContext(crate::payload::SetTuningContextOp {
|
||||||
|
settings: settings.clone(),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Path A: authored live — the envelope object itself, never touching
|
||||||
|
// bytes.
|
||||||
|
let mut live_set = OperationSet::new();
|
||||||
|
live_set.accept_all(vec![live_env.clone()]);
|
||||||
|
let live_out = reduce_operation_set_onto(&live_set, &base);
|
||||||
|
|
||||||
|
// Path B: the identical envelope, round-tripped through canonical
|
||||||
|
// bytes and decoded back before reduction.
|
||||||
|
let bytes = live_env.to_canonical_bytes();
|
||||||
|
let reloaded_env = crate::envdecode::decode_envelope(&bytes).expect("the envelope decodes");
|
||||||
|
let mut reloaded_set = OperationSet::new();
|
||||||
|
reloaded_set.accept_all(vec![reloaded_env]);
|
||||||
|
let reloaded_out = reduce_operation_set_onto(&reloaded_set, &base);
|
||||||
|
|
||||||
|
// The two graph states are identical.
|
||||||
|
assert_eq!(
|
||||||
|
live_out.score.tuning_context, reloaded_out.score.tuning_context,
|
||||||
|
"an op authored live and the same op reloaded from bytes must reduce identically"
|
||||||
|
);
|
||||||
|
// Both apply the authored five-field settings...
|
||||||
|
assert_eq!(
|
||||||
|
live_out.score.tuning_context.default_pitch_space,
|
||||||
|
settings.default_pitch_space
|
||||||
|
);
|
||||||
|
assert_eq!(live_out.score.tuning_context.reference, settings.reference);
|
||||||
|
// ...and both preserve the base's pre-existing accidental_extensions,
|
||||||
|
// untouched — the field the payload cannot carry.
|
||||||
|
assert_eq!(
|
||||||
|
live_out.score.tuning_context.accidental_extensions, pre_existing,
|
||||||
|
"live path: accidental_extensions preserved"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
reloaded_out.score.tuning_context.accidental_extensions, pre_existing,
|
||||||
|
"reloaded path: accidental_extensions preserved"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// (t6) Undo restores the previous (chain-predecessor) five-field value —
|
||||||
|
/// not the seeded base, and not the type default. Two `SetTuningContext`
|
||||||
|
/// writes in two separate transactions; undoing the *second* must restore
|
||||||
|
/// the *first*'s authored value.
|
||||||
|
///
|
||||||
|
/// **Mutation:** in the `TuningContext` restoration-apply arm, restore
|
||||||
|
/// the default `TuningContextSettings` instead of the chain predecessor
|
||||||
|
/// (or drop the field writes entirely); must fail.
|
||||||
|
#[test]
|
||||||
|
fn t6_undo_restores_the_chain_predecessor_tuning_settings() {
|
||||||
|
let identity = IdentityContext::new(ReplicaId(1));
|
||||||
|
let first = crate::valuegen::tuning_context_settings(1);
|
||||||
|
let second = crate::valuegen::tuning_context_settings(2);
|
||||||
|
assert_ne!(first, second);
|
||||||
|
|
||||||
|
let tx2 = TransactionId::from_raw(2);
|
||||||
|
let envelopes = vec![
|
||||||
|
prim_env(
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
10,
|
||||||
|
CausalContext::new(),
|
||||||
|
OperationKind::SetTuningContext(crate::payload::SetTuningContextOp {
|
||||||
|
settings: first.clone(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
declare_transaction(1, 1, 20, seen_r1(0), tx2),
|
||||||
|
tx_member(
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
21,
|
||||||
|
seen_r1(1),
|
||||||
|
tx2,
|
||||||
|
OperationKind::SetTuningContext(crate::payload::SetTuningContextOp {
|
||||||
|
settings: second,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
undo_env(1, 3, 22, seen_r1(2), tx2, UndoPolicy::StrictInverse),
|
||||||
|
];
|
||||||
|
let mut set = OperationSet::new();
|
||||||
|
set.accept_all(envelopes);
|
||||||
|
let out = reduce_operation_set_onto(&set, &Score::empty(identity));
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
out.score.tuning_context.default_pitch_space,
|
||||||
|
first.default_pitch_space
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
out.score.tuning_context.default_tuning_system,
|
||||||
|
first.default_tuning_system
|
||||||
|
);
|
||||||
|
assert_eq!(out.score.tuning_context.reference, first.reference);
|
||||||
|
assert_eq!(out.score.tuning_context.smufl, first.smufl);
|
||||||
|
assert_eq!(
|
||||||
|
out.score.tuning_context.overrides, first.overrides,
|
||||||
|
"undo of the second write restores the first write's value"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// (t7) Undo of the **first** authoring restores the **seeded base**
|
||||||
|
/// settings, identically whether the seed was the type default or a
|
||||||
|
/// non-default value — the never-authored / authored-to-default
|
||||||
|
/// distinction stays unobservable (contract pin 5, and plan trap 5's
|
||||||
|
/// withdrawal). `accidental_extensions` is untouched throughout: it is
|
||||||
|
/// not part of the carried subset type, so undo cannot move it, and this
|
||||||
|
/// test proves the base's own extensions survive both the write and the
|
||||||
|
/// undo unchanged.
|
||||||
|
///
|
||||||
|
/// **Mutation:** skip `tuning_context_chain.seed(...)` in
|
||||||
|
/// `seed_from_graph` -> the first undo sees `NotWritten` (no predecessor
|
||||||
|
/// recorded) instead of `Restore(Base(seeded))`, and the field is left at
|
||||||
|
/// the authored value instead of reverting; must fail.
|
||||||
|
#[test]
|
||||||
|
fn t7_undo_of_first_authoring_restores_the_seeded_base_default_or_not() {
|
||||||
|
// Both cases run through the exact same assertion shape below — no
|
||||||
|
// branch distinguishes "the seed happened to be the type default"
|
||||||
|
// from "the seed was a genuine non-default value". That uniformity is
|
||||||
|
// itself the proof the distinction is unobservable, per pin 5's
|
||||||
|
// explicit instruction not to write code that tells them apart.
|
||||||
|
// A pre-existing, non-empty `accidental_extensions` fixture, built
|
||||||
|
// directly (its constructor is `pub(crate)` in `epiphany-core`, so
|
||||||
|
// this crate cannot reuse the core fixture helper).
|
||||||
|
let default_extensions = || {
|
||||||
|
vec![epiphany_core::ScoreAccidentalExtensions {
|
||||||
|
base: epiphany_core::AccidentalRegistryId::new("heji"),
|
||||||
|
additions: Vec::new(),
|
||||||
|
overrides: Vec::new(),
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
for (case, base) in [
|
||||||
|
("case A: from-empty, default seed", {
|
||||||
|
let mut b = Score::empty(IdentityContext::new(ReplicaId(1)));
|
||||||
|
b.tuning_context.accidental_extensions = default_extensions();
|
||||||
|
b
|
||||||
|
}),
|
||||||
|
("case B: loaded base, non-default seed", {
|
||||||
|
let mut b = Score::empty(IdentityContext::new(ReplicaId(1)));
|
||||||
|
let non_default = crate::valuegen::tuning_context_settings(9);
|
||||||
|
b.tuning_context.default_pitch_space = non_default.default_pitch_space;
|
||||||
|
b.tuning_context.default_tuning_system = non_default.default_tuning_system;
|
||||||
|
b.tuning_context.reference = non_default.reference;
|
||||||
|
b.tuning_context.smufl = non_default.smufl;
|
||||||
|
b.tuning_context.overrides = non_default.overrides;
|
||||||
|
b.tuning_context.accidental_extensions = default_extensions();
|
||||||
|
b
|
||||||
|
}),
|
||||||
|
] {
|
||||||
|
let seeded = base.tuning_context.clone();
|
||||||
|
let tx = TransactionId::from_raw(3);
|
||||||
|
let authored = crate::valuegen::tuning_context_settings(20);
|
||||||
|
let envelopes = vec![
|
||||||
|
declare_transaction(1, 0, 10, CausalContext::new(), tx),
|
||||||
|
tx_member(
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
11,
|
||||||
|
seen_r1(0),
|
||||||
|
tx,
|
||||||
|
OperationKind::SetTuningContext(crate::payload::SetTuningContextOp {
|
||||||
|
settings: authored,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
undo_env(1, 2, 12, seen_r1(1), tx, UndoPolicy::StrictInverse),
|
||||||
|
];
|
||||||
|
let mut set = OperationSet::new();
|
||||||
|
set.accept_all(envelopes);
|
||||||
|
let out = reduce_operation_set_onto(&set, &base);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
out.score.tuning_context.default_pitch_space, seeded.default_pitch_space,
|
||||||
|
"{case}: undo restores the seeded default_pitch_space"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
out.score.tuning_context.default_tuning_system, seeded.default_tuning_system,
|
||||||
|
"{case}: undo restores the seeded default_tuning_system"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
out.score.tuning_context.reference, seeded.reference,
|
||||||
|
"{case}: undo restores the seeded reference"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
out.score.tuning_context.smufl, seeded.smufl,
|
||||||
|
"{case}: undo restores the seeded smufl"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
out.score.tuning_context.overrides, seeded.overrides,
|
||||||
|
"{case}: undo restores the seeded overrides"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
out.score.tuning_context.accidental_extensions, seeded.accidental_extensions,
|
||||||
|
"{case}: accidental_extensions is untouched throughout — it is not part \
|
||||||
|
of the carried subset type, so undo cannot move it"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// (s7) Transaction rollback discards the write — and the assertion must
|
/// (s7) Transaction rollback discards the write — and the assertion must
|
||||||
/// not be on the field. `WorkingSnapshot` (`:7480`) is the transaction
|
/// not be on the field. `WorkingSnapshot` (`:7480`) is the transaction
|
||||||
/// **rollback** mechanism: snapshot before, restore on failure. But
|
/// **rollback** mechanism: snapshot before, restore on failure. But
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@ use crate::payload::{
|
||||||
InsertIdentifiedPitchOp, ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp,
|
InsertIdentifiedPitchOp, ModifyCrossCuttingOp, ModifyEventOp, ModifyIdentifiedPitchOp,
|
||||||
OperationKind, OperationKindTag, RespellPitchOp, SetCanvasLayoutDefaultsOp, SetMetadataOp,
|
OperationKind, OperationKindTag, RespellPitchOp, SetCanvasLayoutDefaultsOp, SetMetadataOp,
|
||||||
SetMetricGridOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp,
|
SetMetricGridOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp,
|
||||||
SetTimeSignatureOp, SetUserPageBreakOp, SetUserSystemBreakOp, TransactionDescriptor,
|
SetTimeSignatureOp, SetTuningContextOp, SetUserPageBreakOp, SetUserSystemBreakOp,
|
||||||
TransposeIntervalOp, TransposeOp,
|
TransactionDescriptor, TransposeIntervalOp, TransposeOp,
|
||||||
};
|
};
|
||||||
use crate::support::OperationKindRegistryId;
|
use crate::support::OperationKindRegistryId;
|
||||||
|
|
||||||
|
|
@ -229,6 +229,9 @@ impl TextValue for OperationKind {
|
||||||
OperationKind::SetSpellingPrecedence(op) => {
|
OperationKind::SetSpellingPrecedence(op) => {
|
||||||
production(self.tag(), vec![op.precedence.project()])
|
production(self.tag(), vec![op.precedence.project()])
|
||||||
}
|
}
|
||||||
|
OperationKind::SetTuningContext(op) => {
|
||||||
|
production(self.tag(), vec![op.settings.project()])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -566,6 +569,14 @@ impl TextValue for OperationKind {
|
||||||
precedence: TextValue::parse(precedence)?,
|
precedence: TextValue::parse(precedence)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
OperationKindTag::SetTuningContext => {
|
||||||
|
let [settings] = fields(s, tag, 1)? else {
|
||||||
|
unreachable!("the arity-1 check returned one field")
|
||||||
|
};
|
||||||
|
OperationKind::SetTuningContext(SetTuningContextOp {
|
||||||
|
settings: TextValue::parse(settings)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -619,7 +630,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn every_operation_kind_round_trips_with_canonical_text() {
|
fn every_operation_kind_round_trips_with_canonical_text() {
|
||||||
let tags: Vec<_> = all_tags().collect();
|
let tags: Vec<_> = all_tags().collect();
|
||||||
assert_eq!(tags.len(), 34, "the grammar has 34 kind productions");
|
assert_eq!(tags.len(), 35, "the grammar has 35 kind productions");
|
||||||
for tag in tags {
|
for tag in tags {
|
||||||
round_trip(&sample_kind(tag));
|
round_trip(&sample_kind(tag));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,10 @@ pub enum V0OperationKind {
|
||||||
// every other v1-native kind above.
|
// every other v1-native kind above.
|
||||||
SetCanvasLayoutDefaults(crate::payload::SetCanvasLayoutDefaultsOp),
|
SetCanvasLayoutDefaults(crate::payload::SetCanvasLayoutDefaultsOp),
|
||||||
SetSpellingPrecedence(crate::payload::SetSpellingPrecedenceOp),
|
SetSpellingPrecedence(crate::payload::SetSpellingPrecedenceOp),
|
||||||
|
// Genesis tranche G2b — born at wire-disc 34; no lossy v0 form (v0
|
||||||
|
// predates the catalog entirely), so it round-trips by identity like
|
||||||
|
// every other v1-native kind above.
|
||||||
|
SetTuningContext(crate::payload::SetTuningContextOp),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// v0 `InsertEvent`: the event was a bare [`EventId`] plus the reduction-relevant
|
/// v0 `InsertEvent`: the event was a bare [`EventId`] plus the reduction-relevant
|
||||||
|
|
|
||||||
|
|
@ -409,6 +409,30 @@ pub fn spelling_precedence(nth: u8) -> epiphany_core::SpellingPrecedence {
|
||||||
.expect("both listed orders are total over the five source kinds")
|
.expect("both listed orders are total over the five source kinds")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tuning context settings with an `nth`-distinct reference frequency
|
||||||
|
/// (genesis tranche G2b) — the carried [`epiphany_core::TuningContextSettings`]
|
||||||
|
/// of `SetTuningContext`. Distinct `nth` give distinct values so a harness can
|
||||||
|
/// drive concurrent `SetTuningContext`s, an advisory LWW field that resolves
|
||||||
|
/// by canonical order with no conflict.
|
||||||
|
pub fn tuning_context_settings(nth: u8) -> epiphany_core::TuningContextSettings {
|
||||||
|
use epiphany_core::{CmnNominal, PitchSpacePosition, ReferencePitch};
|
||||||
|
epiphany_core::TuningContextSettings {
|
||||||
|
default_pitch_space: epiphany_core::PitchSpaceId::new("cmn-12"),
|
||||||
|
default_tuning_system: epiphany_core::TuningSystemId::new("tet-12"),
|
||||||
|
reference: ReferencePitch::new(
|
||||||
|
PitchSpacePosition::Cmn {
|
||||||
|
nominal: CmnNominal::A,
|
||||||
|
alteration: 0,
|
||||||
|
octave: 4,
|
||||||
|
},
|
||||||
|
440.0 + f64::from(nth),
|
||||||
|
)
|
||||||
|
.expect("a small positive offset from A440 stays finite and positive"),
|
||||||
|
smufl: epiphany_core::SmuflVersionRequirement::default(),
|
||||||
|
overrides: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A well-formed `numerator`/4 [`TimeSignature`](epiphany_core::TimeSignature)
|
/// A well-formed `numerator`/4 [`TimeSignature`](epiphany_core::TimeSignature)
|
||||||
/// (Phase-3 tranche): `numerator` quarter-note beat groups summing exactly to
|
/// (Phase-3 tranche): `numerator` quarter-note beat groups summing exactly to
|
||||||
/// the measure duration, so [`epiphany_core::TimeSignature::new`]'s beat-group
|
/// the measure duration, so [`epiphany_core::TimeSignature::new`]'s beat-group
|
||||||
|
|
|
||||||
|
|
@ -373,6 +373,44 @@ pub fn decode_vectors() -> Vec<DecodeVector> {
|
||||||
precedence_trailing,
|
precedence_trailing,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// --- OperationEnvelope carrying SetTuningContext (genesis tranche G2b) —
|
||||||
|
// the sole genesis payload born at schema major 3. Same rationale as the
|
||||||
|
// siblings above: nothing else in this corpus exercises this payload's
|
||||||
|
// decode path, and a round-trip check alone cannot see a self-consistent
|
||||||
|
// encoder/decoder reorder (the 3b-i lesson).
|
||||||
|
let tuning_envelope = OperationEnvelope {
|
||||||
|
id: OperationId::new(ReplicaId(1), 4),
|
||||||
|
author: crate::support::AuthorId(0),
|
||||||
|
stamp: crate::stamp::OperationStamp::new(
|
||||||
|
crate::stamp::HybridLogicalClock::new(epiphany_core::WallClockTime(1), 1),
|
||||||
|
OperationId::new(ReplicaId(1), 4),
|
||||||
|
),
|
||||||
|
causal_context: crate::causal::CausalContext::new(),
|
||||||
|
transaction: None,
|
||||||
|
payload: crate::payload::OperationPayload::Primitive(
|
||||||
|
crate::payload::OperationKind::SetTuningContext(crate::payload::SetTuningContextOp {
|
||||||
|
settings: crate::valuegen::tuning_context_settings(1),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
let tuning_envelope_bytes = tuning_envelope.to_canonical_bytes();
|
||||||
|
v.push(row(
|
||||||
|
OE,
|
||||||
|
"accept",
|
||||||
|
"-",
|
||||||
|
"set_tuning_context",
|
||||||
|
tuning_envelope_bytes.clone(),
|
||||||
|
));
|
||||||
|
let mut tuning_trailing = tuning_envelope_bytes;
|
||||||
|
tuning_trailing.push(0);
|
||||||
|
v.push(row(
|
||||||
|
OE,
|
||||||
|
"reject",
|
||||||
|
"trailing-bytes",
|
||||||
|
"set_tuning_context_trailing",
|
||||||
|
tuning_trailing,
|
||||||
|
));
|
||||||
|
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -555,4 +593,33 @@ mod tests {
|
||||||
"the committed literal bytes must decode and re-encode injectively"
|
"the committed literal bytes must decode and re-encode injectively"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// (s8 analogue) Genesis tranche G2b (`spec/CONTRACT_GENESIS_G2B_TUNING.md`
|
||||||
|
/// touch row 11): the `SetTuningContext` envelope decode vector, pinned to
|
||||||
|
/// a literal byte array copied from the committed corpus — not derived by
|
||||||
|
/// calling `.to_canonical_bytes()` here, for the same reason as the
|
||||||
|
/// sibling tests above (the 3b-i lesson: round-trip locking alone cannot
|
||||||
|
/// see a self-consistent encoder/decoder reorder). The mutation this
|
||||||
|
/// guards against is a swap of discriminant 34 with any neighboring
|
||||||
|
/// discriminant in both the encoder and the decoder — self-consistent, so
|
||||||
|
/// every round-trip test stays green, while this correctly-named literal
|
||||||
|
/// vector dies.
|
||||||
|
#[test]
|
||||||
|
fn set_tuning_context_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, 4, 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, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 48, 0, 0, 0, 6, 0, 0, 0, 99, 109, 110,
|
||||||
|
45, 49, 50, 6, 0, 0, 0, 116, 101, 116, 45, 49, 50, 0, 5, 0, 4, 8, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 144, 123, 64, 1, 0, 40, 0, 1, 0, 40, 0, 0, 0, 0, 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"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,9 +47,9 @@ use epiphany_ops::{
|
||||||
ReplicaAnomalyReason, ReplicaAnomalyRegistryId, ResolutionAction, ResolutionRegistryId,
|
ReplicaAnomalyReason, ReplicaAnomalyRegistryId, ResolutionAction, ResolutionRegistryId,
|
||||||
ResolveConflictPayload, RespellPitchOp, SerializedCanonicalInputs, SetCanvasLayoutDefaultsOp,
|
ResolveConflictPayload, RespellPitchOp, SerializedCanonicalInputs, SetCanvasLayoutDefaultsOp,
|
||||||
SetMetadataOp, SetMetricGridOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp,
|
SetMetadataOp, SetMetricGridOp, SetSpellingPrecedenceOp, SetStaffLayoutOp, SetTempoSegmentOp,
|
||||||
SetTimeSignatureOp, SetUserPageBreakOp, SetUserSystemBreakOp, TransactionCategory,
|
SetTimeSignatureOp, SetTuningContextOp, SetUserPageBreakOp, SetUserSystemBreakOp,
|
||||||
TransactionDescriptor, TransposeIntervalOp, TransposeOp, TupletCompensation,
|
TransactionCategory, TransactionDescriptor, TransposeIntervalOp, TransposeOp,
|
||||||
TupletCompensationKind, UndoPolicy, UndoTransactionPayload,
|
TupletCompensation, TupletCompensationKind, UndoPolicy, UndoTransactionPayload,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::rng::Rng;
|
use crate::rng::Rng;
|
||||||
|
|
@ -646,7 +646,7 @@ pub fn operation_payload(rng: &mut Rng, events: u64, pitches: u64) -> OperationP
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
let kind = match rng.below(34) {
|
let kind = match rng.below(35) {
|
||||||
0 => {
|
0 => {
|
||||||
let pitches = if rng.boolean() {
|
let pitches = if rng.boolean() {
|
||||||
vec![obj_pitch(rng.below(pitches))]
|
vec![obj_pitch(rng.below(pitches))]
|
||||||
|
|
@ -871,6 +871,10 @@ pub fn operation_payload(rng: &mut Rng, events: u64, pitches: u64) -> OperationP
|
||||||
32 => OperationKind::SetSpellingPrecedence(SetSpellingPrecedenceOp {
|
32 => OperationKind::SetSpellingPrecedence(SetSpellingPrecedenceOp {
|
||||||
precedence: valuegen::spelling_precedence(rng.below(3) as u8),
|
precedence: valuegen::spelling_precedence(rng.below(3) as u8),
|
||||||
}),
|
}),
|
||||||
|
// Genesis tranche G2b: the sole genesis payload born at schema major 3.
|
||||||
|
33 => OperationKind::SetTuningContext(SetTuningContextOp {
|
||||||
|
settings: valuegen::tuning_context_settings(rng.below(3) as u8),
|
||||||
|
}),
|
||||||
_ => OperationKind::Registered(
|
_ => OperationKind::Registered(
|
||||||
OperationKindRegistryId(rng.next_u64() as u128),
|
OperationKindRegistryId(rng.next_u64() as u128),
|
||||||
rng.byte_vec(0, 16),
|
rng.byte_vec(0, 16),
|
||||||
|
|
|
||||||
|
|
@ -686,12 +686,18 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn op_block_beyond_the_accept_set_opens_read_only() {
|
fn op_block_beyond_the_accept_set_opens_read_only() {
|
||||||
use epiphany_bundle::IntegrityAnomaly;
|
use epiphany_bundle::IntegrityAnomaly;
|
||||||
// A newer writer's op block, stamped schema major 3 — beyond the reader's
|
// A newer writer's op block, stamped schema major 4 — beyond the reader's
|
||||||
// op-block accept-set [0,2]. The bundle opens read-only preservation (the
|
// op-block accept-set [0,3]. The bundle opens read-only preservation (the
|
||||||
// canonical base and manifest still read) rather than hard-rejecting.
|
// canonical base and manifest still read) rather than hard-rejecting.
|
||||||
|
//
|
||||||
|
// Major 4, not 3: genesis tranche G2b raised the op-block accept-set
|
||||||
|
// to [0, 3] (`SetTuningContext` is born at major 3), so major 3 is
|
||||||
|
// now admitted and this test's "beyond the accept-set" major must
|
||||||
|
// move past it to stay an actual test of the read-only-on-overflow
|
||||||
|
// path.
|
||||||
let block = StagedChunk::operation_block_versioned(
|
let block = StagedChunk::operation_block_versioned(
|
||||||
encode_block(&[vec![1u8, 2, 3, 4]]),
|
encode_block(&[vec![1u8, 2, 3, 4]]),
|
||||||
SchemaVersion::new(3, 0),
|
SchemaVersion::new(4, 0),
|
||||||
);
|
);
|
||||||
let reopened = reopen_with_op_block(0xD2_0002, block);
|
let reopened = reopen_with_op_block(0xD2_0002, block);
|
||||||
assert!(
|
assert!(
|
||||||
|
|
@ -700,7 +706,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert!(reopened.anomalies().iter().any(|a| matches!(
|
assert!(reopened.anomalies().iter().any(|a| matches!(
|
||||||
a,
|
a,
|
||||||
IntegrityAnomaly::UnsupportedCanonicalChunkMajor { schema_major: 3 }
|
IntegrityAnomaly::UnsupportedCanonicalChunkMajor { schema_major: 4 }
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -304,14 +304,15 @@ fn the_kind_productions_are_the_operation_vocabulary() {
|
||||||
// The count is still hand-maintained, which is the same shape the comment
|
// The count is still hand-maintained, which is the same shape the comment
|
||||||
// above warns about — derived list, literal total. Every tranche that
|
// above warns about — derived list, literal total. Every tranche that
|
||||||
// appends a tag must bump it (genesis G1 took it from 31 to 32 by adding
|
// appends a tag must bump it (genesis G1 took it from 31 to 32 by adding
|
||||||
// `CreateInstrument`; genesis G2a takes it from 32 to 34 by adding
|
// `CreateInstrument`; genesis G2a took it from 32 to 34 by adding
|
||||||
// `SetCanvasLayoutDefaults` and `SetSpellingPrecedence`). It stays a
|
// `SetCanvasLayoutDefaults` and `SetSpellingPrecedence`; genesis G2b takes
|
||||||
// literal on purpose: deriving it from `PAYLOAD_FREE.len()` would make the
|
// it from 34 to 35 by adding `SetTuningContext`). It stays a literal on
|
||||||
// assertion vacuous, since that is the very list it exists to pin.
|
// purpose: deriving it from `PAYLOAD_FREE.len()` would make the assertion
|
||||||
|
// vacuous, since that is the very list it exists to pin.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
expected.len(),
|
expected.len(),
|
||||||
34,
|
35,
|
||||||
"33 payload-free kinds plus `Registered`"
|
"34 payload-free kinds plus `Registered`"
|
||||||
);
|
);
|
||||||
|
|
||||||
let actual = alternatives("kind");
|
let actual = alternatives("kind");
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,13 @@ use epiphany_ops::OperationEnvelope;
|
||||||
/// `epiphany-layout-ir` dependency and structurally cannot decode edit-barrier
|
/// `epiphany-layout-ir` dependency and structurally cannot decode edit-barrier
|
||||||
/// bytes). Holding the version while changing the grammar would leave two
|
/// bytes). Holding the version while changing the grammar would leave two
|
||||||
/// incompatible grammars both claiming `(0 9 0)`.
|
/// incompatible grammars both claiming `(0 9 0)`.
|
||||||
pub const COMPANION_VERSION: (u32, u32, u32) = (0, 10, 0);
|
///
|
||||||
|
/// Bumped again 0.10.0 → 0.11.0 by the genesis tranche G2b
|
||||||
|
/// (`spec/CONTRACT_GENESIS_G2B_TUNING.md`), which appended
|
||||||
|
/// `set-tuning-context` to the `kind` production — the same reasoning as G1
|
||||||
|
/// and G2a: extending the grammar without moving this constant would leave
|
||||||
|
/// two incompatible grammars both claiming `(0 10 0)`.
|
||||||
|
pub const COMPANION_VERSION: (u32, u32, u32) = (0, 11, 0);
|
||||||
|
|
||||||
/// A parsed canonical Text Projection document.
|
/// A parsed canonical Text Projection document.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -649,11 +649,12 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bumped with `COMPANION_VERSION` (0.7.0 → 0.8.0, genesis G1; 0.8.0 →
|
// Bumped with `COMPANION_VERSION` (0.7.0 → 0.8.0, genesis G1; 0.8.0 →
|
||||||
// 0.9.0, genesis G2a; 0.9.0 → 0.10.0, G-minor). Kept a literal because
|
// 0.9.0, genesis G2a; 0.9.0 → 0.10.0, G-minor; 0.10.0 → 0.11.0, genesis
|
||||||
// `projection` takes `&[&str]` and a formatted String would ripple
|
// G2b). Kept a literal because `projection` takes `&[&str]` and a
|
||||||
// through every call site; `the_test_header_tracks_the_implemented_
|
// formatted String would ripple through every call site;
|
||||||
// version` below fails loudly if the two ever drift.
|
// `the_test_header_tracks_the_implemented_version` below fails loudly if
|
||||||
const HEADER: &str = "(text-projection (0 10 0))";
|
// the two ever drift.
|
||||||
|
const HEADER: &str = "(text-projection (0 11 0))";
|
||||||
const DOCUMENT: &str = "(document #x00000000000000000000000000000001 (schema 0 1))";
|
const DOCUMENT: &str = "(document #x00000000000000000000000000000001 (schema 0 1))";
|
||||||
|
|
||||||
/// A minimal but complete valid projection: just the two mandatory lines.
|
/// A minimal but complete valid projection: just the two mandatory lines.
|
||||||
|
|
|
||||||
|
|
@ -329,17 +329,17 @@ pub fn document_vectors() -> Vec<TextVector> {
|
||||||
.map(|(name, text)| (SURFACE, "accept", "-", *name, text.as_bytes().to_vec()))
|
.map(|(name, text)| (SURFACE, "accept", "-", *name, text.as_bytes().to_vec()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// The rejected version must be one this crate does NOT implement. The
|
// The rejected version must be one this crate does NOT implement. Genesis
|
||||||
// G-minor rung moved `COMPANION_VERSION` to 0.10.0, which had been this
|
// tranche G2b moved `COMPANION_VERSION` to 0.11.0, which had been this
|
||||||
// vector's "future" version — leaving it would have made the negative
|
// vector's "future" version — leaving it would have made the negative
|
||||||
// vector assert that the *correct* header is rejected. It now names
|
// vector assert that the *correct* header is rejected. It now names
|
||||||
// 0.9.0, the immediately superseded companion, which is the better test
|
// 0.10.0, the immediately superseded companion, which is the better test
|
||||||
// anyway: rejecting the version right behind you is exactly the deferred
|
// anyway: rejecting the version right behind you is exactly the deferred
|
||||||
// migrate-on-read posture (`req:textproj:header-version`).
|
// migrate-on-read posture (`req:textproj:header-version`).
|
||||||
let wrong_version = replace_once(
|
let wrong_version = replace_once(
|
||||||
minimal,
|
minimal,
|
||||||
|
"(text-projection (0 11 0))",
|
||||||
"(text-projection (0 10 0))",
|
"(text-projection (0 10 0))",
|
||||||
"(text-projection (0 9 0))",
|
|
||||||
);
|
);
|
||||||
vectors.push((
|
vectors.push((
|
||||||
SURFACE,
|
SURFACE,
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -6,10 +6,28 @@ reverses Pass-12 K8 and makes every mutable field of `Score` operation-authored.
|
||||||
This plan is the execution scope: what the tranche touches, in what order, and
|
This plan is the execution scope: what the tranche touches, in what order, and
|
||||||
which questions must be answered before a dispatch contract can be written.
|
which questions must be answered before a dispatch contract can be written.
|
||||||
|
|
||||||
**Status:** **G1 landed** (3b09595, CI green) via
|
**Status:** the ladder **G1 → G2a → G-minor → G2b** is **complete**; only **G3**
|
||||||
`spec/CONTRACT_GENESIS_G1_INSTRUMENT.md`. **G2a contracted**
|
remains.
|
||||||
(`spec/CONTRACT_GENESIS_G2A_SETTINGS.md`); **G-minor**, G2b, and G3 scoped, not
|
|
||||||
contracted. §6 lists what still needs ratification.
|
* **G1 landed** (3b09595) — `CreateInstrument`, kind/tag 31.
|
||||||
|
* **G2a landed** (7df5ca1 + 55eff00) — `SetCanvasLayoutDefaults` and
|
||||||
|
`SetSpellingPrecedence`, kinds/tags 32/33, both major 0.
|
||||||
|
* **G-minor landed** (ff9bd0f) — the chunk schema minor became a derived
|
||||||
|
record; epoch ladder ratified at minors 2–9 (`spec/PLAN_GMINOR_SCHEMA_MINOR.md`
|
||||||
|
§4), governed by `spec/AUDIT_GMINOR_VOCABULARIES.md`. Closed **P13-S14**.
|
||||||
|
* **G2b landed** — `SetTuningContext`, kind/tag **34**, schema major **3**,
|
||||||
|
minor epoch **10**. Carried the sole accept-set raise
|
||||||
|
(`OperationEnvelopeBlock` 2→3) and rewrote the `bundle.rs` rationale it
|
||||||
|
falsified. Payload is the five-field subset
|
||||||
|
`epiphany_core::TuningContextSettings`, **not** the full graph type — §5
|
||||||
|
trap 7's holdout, resolved in the contract as *subset over normalization*.
|
||||||
|
Closed **P13-S13**.
|
||||||
|
* **G3** — the five remaining mint families, plus the delete/modify coverage
|
||||||
|
design. Scoped, not contracted.
|
||||||
|
|
||||||
|
§6 lists what still needs ratification. **Standing constraint, now with real
|
||||||
|
teeth:** pruning MUST NOT be implemented until disposition C lands — after G2b
|
||||||
|
it would discard *authored* genesis state, not merely re-derivable state.
|
||||||
|
|
||||||
**G1 shipped documentation debt** — five normative falsehoods across
|
**G1 shipped documentation debt** — five normative falsehoods across
|
||||||
`binary_format.tex`, `core_spec.tex`, and `operation_catalog.tex`, because its
|
`binary_format.tex`, `core_spec.tex`, and `operation_catalog.tex`, because its
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1455,6 +1455,13 @@ and the reader disagree about the field's type.
|
||||||
\tablenums{33} & \texttt{SetSpellingPrecedence} &
|
\tablenums{33} & \texttt{SetSpellingPrecedence} &
|
||||||
$\mathrm{lp}$(\texttt{SpellingPrecedence}) &
|
$\mathrm{lp}$(\texttt{SpellingPrecedence}) &
|
||||||
\sectionsc{SetSpellingPrecedence} \\
|
\sectionsc{SetSpellingPrecedence} \\
|
||||||
|
\tablenums{34} & \texttt{SetTuningContext} &
|
||||||
|
$\mathrm{lp}$(\texttt{TuningContextSettings}) --- the \textbf{authored
|
||||||
|
subset} of \texttt{ScoreTuningContext}: exactly its five wire-bearing
|
||||||
|
fields, in the same order, byte-identical to the schema-major-3
|
||||||
|
\texttt{ScoreTuningContext} layout (Section~\ref{sec:evolution:major3});
|
||||||
|
born at v3 unconditionally &
|
||||||
|
\sectionsc{SetTuningContext} \\
|
||||||
\bottomrule
|
\bottomrule
|
||||||
\end{longtable}
|
\end{longtable}
|
||||||
\endgroup
|
\endgroup
|
||||||
|
|
@ -1525,6 +1532,7 @@ discriminants and wrong lengths are decode errors. Append-only past
|
||||||
\tablenums{28} & \texttt{CreateRepeatStructure} & \tablenums{29} & \texttt{DeleteRepeatStructure} \\
|
\tablenums{28} & \texttt{CreateRepeatStructure} & \tablenums{29} & \texttt{DeleteRepeatStructure} \\
|
||||||
\tablenums{30} & \texttt{TransposeInterval} & \tablenums{31} & \texttt{CreateInstrument} \\
|
\tablenums{30} & \texttt{TransposeInterval} & \tablenums{31} & \texttt{CreateInstrument} \\
|
||||||
\tablenums{32} & \texttt{SetCanvasLayoutDefaults} & \tablenums{33} & \texttt{SetSpellingPrecedence} \\
|
\tablenums{32} & \texttt{SetCanvasLayoutDefaults} & \tablenums{33} & \texttt{SetSpellingPrecedence} \\
|
||||||
|
\tablenums{34} & \texttt{SetTuningContext} & & \\
|
||||||
\bottomrule
|
\bottomrule
|
||||||
\end{longtable}
|
\end{longtable}
|
||||||
\endgroup
|
\endgroup
|
||||||
|
|
@ -2332,9 +2340,13 @@ Every chunk declares a \texttt{SchemaVersion} (major, minor) in its
|
||||||
role}, not one shared bound (Section~\ref{sec:evolution:major1}'s ``raised
|
role}, not one shared bound (Section~\ref{sec:evolution:major1}'s ``raised
|
||||||
per chunk role'' rule, sharpened by major~3, the first bump under which the
|
per chunk role'' rule, sharpened by major~3, the first bump under which the
|
||||||
roles' maxima genuinely diverge): the \texttt{Snapshot} role's max is
|
roles' maxima genuinely diverge): the \texttt{Snapshot} role's max is
|
||||||
\tablenums{3}; the \texttt{OperationEnvelopeBlock} role's max stays
|
\tablenums{3}; the \texttt{OperationEnvelopeBlock} role's max is
|
||||||
\tablenums{2} (schema major~3 embeds no operation payload, so this role
|
\tablenums{3} as of genesis tranche G2b
|
||||||
does not rise); every other role's max is \tablenums{0}. The reference
|
(\texttt{spec/CONTRACT\_GENESIS\_G2B\_TUNING.md} ---
|
||||||
|
\texttt{SetTuningContext}, \tablenums{34}, is born at v3
|
||||||
|
unconditionally; the role stayed at \tablenums{2} from Push~4b tranche
|
||||||
|
3b-i, when schema major~3 embedded no operation payload, until this
|
||||||
|
rung); every other role's max is \tablenums{0}. The reference
|
||||||
implementation's overall envelope is $\{0, 1, 2, 3\}$ ($\textsc{min} = 0$,
|
implementation's overall envelope is $\{0, 1, 2, 3\}$ ($\textsc{min} = 0$,
|
||||||
$\textsc{max} = 3$), realized as these differing per-role maxima rather
|
$\textsc{max} = 3$), realized as these differing per-role maxima rather
|
||||||
than a single shared bound.
|
than a single shared bound.
|
||||||
|
|
@ -2370,22 +2382,26 @@ The \emph{only} minor-additive mechanism in schema major~0 is
|
||||||
\textbf{appending discriminants to open vocabularies}:
|
\textbf{appending discriminants to open vocabularies}:
|
||||||
|
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item \texttt{OperationKind}: append at ${\geq}\,\tablenums{34}$
|
\item \texttt{OperationKind}: append at ${\geq}\,\tablenums{35}$
|
||||||
(Requirement~\ref{req:binfmt:kind-discriminants}; the Phase-3
|
(Requirement~\ref{req:binfmt:kind-discriminants}; the Phase-3
|
||||||
tranche took \tablenums{24}--\tablenums{27} under this mechanism,
|
tranche took \tablenums{24}--\tablenums{27} under this mechanism,
|
||||||
the repeat pair \tablenums{28}/\tablenums{29} in the
|
the repeat pair \tablenums{28}/\tablenums{29} in the
|
||||||
schema-major-2 revision, Push~4a took \tablenums{30}
|
schema-major-2 revision, Push~4a took \tablenums{30}
|
||||||
(\texttt{TransposeInterval}), genesis tranche G1 took \tablenums{31}
|
(\texttt{TransposeInterval}), genesis tranche G1 took \tablenums{31}
|
||||||
(\texttt{CreateInstrument}), and genesis tranche G2a took
|
(\texttt{CreateInstrument}), genesis tranche G2a took
|
||||||
\tablenums{32}/\tablenums{33} (\texttt{SetCanvasLayoutDefaults},
|
\tablenums{32}/\tablenums{33} (\texttt{SetCanvasLayoutDefaults},
|
||||||
\texttt{SetSpellingPrecedence}) --- the discriminant space is one
|
\texttt{SetSpellingPrecedence}), and genesis tranche G2b took
|
||||||
append-only table across majors, but a kind's \emph{block stamp} follows
|
\tablenums{34} (\texttt{SetTuningContext}) --- the discriminant space is
|
||||||
minimal stamping over its payload: \tablenums{28}'s payload embeds a v2
|
one append-only table across majors, but a kind's \emph{block stamp}
|
||||||
layout, so its blocks stamp major~2, Section~\ref{sec:evolution:major2});
|
follows minimal stamping over its payload: \tablenums{28}'s payload
|
||||||
\item \texttt{OperationKindTag}: append at ${\geq}\,\tablenums{34}$
|
embeds a v2 layout, so its blocks stamp major~2,
|
||||||
(Requirement~\ref{req:binfmt:kind-tag}; the same ten variants as
|
Section~\ref{sec:evolution:major2}; \tablenums{34}'s payload embeds a v3
|
||||||
\texttt{OperationKind}, at the same ten discriminants, appended by the
|
layout unconditionally, so its blocks stamp major~3,
|
||||||
same five tranches);
|
Section~\ref{sec:evolution:major3} --- the sole appended kind to do so);
|
||||||
|
\item \texttt{OperationKindTag}: append at ${\geq}\,\tablenums{35}$
|
||||||
|
(Requirement~\ref{req:binfmt:kind-tag}; the same eleven variants as
|
||||||
|
\texttt{OperationKind}, at the same eleven discriminants, appended by
|
||||||
|
the same six tranches);
|
||||||
\item \texttt{OperationPayload}: append at ${\geq}\,\tablenums{4}$
|
\item \texttt{OperationPayload}: append at ${\geq}\,\tablenums{4}$
|
||||||
(Section~\ref{sec:ops:payload}; \texttt{ResolveEquivocation} = 3, Push~3,
|
(Section~\ref{sec:ops:payload}; \texttt{ResolveEquivocation} = 3, Push~3,
|
||||||
is the one and only append this vocabulary has had);
|
is the one and only append this vocabulary has had);
|
||||||
|
|
@ -2977,24 +2993,39 @@ layout ahead of a real consumer is exactly what the frozen-layout rule
|
||||||
major~1.
|
major~1.
|
||||||
|
|
||||||
\subsection{Where the changed fields reach}
|
\subsection{Where the changed fields reach}
|
||||||
Only one payload type changes, and it changes at exactly one site:
|
|
||||||
|
\textbf{As first defined (Push~4b tranche 3b-i), no operation payload
|
||||||
|
embedded the tuning context} --- \texttt{ScoreTuningContext} reached the
|
||||||
|
wire only through the acceleration full-\texttt{Score} snapshot, and the
|
||||||
|
\texttt{OperationEnvelopeBlock} role's accept-set stayed at major~2. This
|
||||||
|
changed at genesis tranche G2b
|
||||||
|
(\texttt{spec/CONTRACT\_GENESIS\_G2B\_TUNING.md}), which corrects the claim
|
||||||
|
below:
|
||||||
|
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item \textbf{Snapshot-only:} \texttt{ScoreTuningContext} reaches the wire
|
\item \textbf{Reaches two sites, as of genesis tranche G2b.}
|
||||||
\emph{only} through the acceleration full-\texttt{Score} snapshot. No
|
\texttt{ScoreTuningContext} still reaches the wire through the
|
||||||
operation payload embeds the tuning context (core Chapter~6's operation
|
acceleration full-\texttt{Score} snapshot, \emph{and} its authored
|
||||||
vocabulary carries no \texttt{ScoreTuningContext} / \texttt{TuningOverride}
|
subset --- \texttt{TuningContextSettings}, exactly the five
|
||||||
/ \texttt{SmuflVersionRequirement} field anywhere), so the
|
wire-bearing fields, byte-identical to this section's layout
|
||||||
\textbf{canonical operation layer is untouched}: no op payload is ``born
|
(Section~\ref{sec:ops:kinds}, \tablenums{34}
|
||||||
at v3'', and no frozen v2 op-payload decoder is needed. The
|
\texttt{SetTuningContext}) --- now reaches the wire through the
|
||||||
\texttt{OperationEnvelopeBlock} role's accept-set therefore stays at
|
canonical operation layer: \texttt{SetTuningContext} is \emph{born at
|
||||||
major~2 (Section~\ref{sec:evolution:major2}) --- schema major~3 is the
|
v3 unconditionally} (the same shape as \texttt{CreateInstrument}'s v2
|
||||||
first data-model bump under which a chunk role's max does \emph{not}
|
birth, Section~\ref{sec:evolution:major2}), since \texttt{smufl} and
|
||||||
move in lockstep with the others.
|
\texttt{overrides} are mandatory appends with no lower-major layout for
|
||||||
|
this payload to fall back to. The \texttt{OperationEnvelopeBlock}
|
||||||
|
role's accept-set therefore \textbf{widens to major~3}
|
||||||
|
(Section~\ref{sec:evolution:gate}) --- schema major~3 stopped being the
|
||||||
|
data-model bump under which a chunk role's max does not move in
|
||||||
|
lockstep with the others; that distinction now belongs to no major.
|
||||||
\item \textbf{The canonical base is unchanged.} The
|
\item \textbf{The canonical base is unchanged.} The
|
||||||
\texttt{MaterializedState} embeds no tuning context, so it remains
|
\texttt{MaterializedState} embeds no tuning context (nor any other
|
||||||
major~0, byte-identical across the bump --- the same keystone as
|
\texttt{Score} field value), so it remains major~0, byte-identical
|
||||||
majors~1 and~2, and a conformance test \SHOULD{} assert it again.
|
across the bump --- the same keystone as majors~1 and~2, and a
|
||||||
|
conformance test \SHOULD{} assert it again. This is unaffected by G2b:
|
||||||
|
the canonical carrier of the tuning context is the operation log, not
|
||||||
|
the base, so the base's own stamping never moves.
|
||||||
\item The manifest stays major~0 (nothing here touches it).
|
\item The manifest stays major~0 (nothing here touches it).
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
|
|
@ -3005,10 +3036,14 @@ or migrate it on read (the reference implementation migrates). Canonical
|
||||||
chunks parse or the bundle opens read-only. Migration \emph{composes}: a
|
chunks parse or the bundle opens read-only. Migration \emph{composes}: a
|
||||||
major-3 reader migrates a major-0 snapshot
|
major-3 reader migrates a major-0 snapshot
|
||||||
v0${\to}$v1${\to}$v2${\to}$v3 in one read, each step total and
|
v0${\to}$v1${\to}$v2${\to}$v3 in one read, each step total and
|
||||||
default-filling. Because no operation payload changes at this major, a
|
default-filling. As originally defined (Push~4b tranche 3b-i), no operation
|
||||||
major-2-only reader's op-block admission is exactly as before this bump ---
|
payload changed at this major, so a major-2-only reader's op-block
|
||||||
only the \texttt{Snapshot} role's accept-set widens, to \tablenums{3}
|
admission was exactly as before the bump and only the \texttt{Snapshot}
|
||||||
(Section~\ref{sec:evolution:gate}).
|
role's accept-set widened, to \tablenums{3}
|
||||||
|
(Section~\ref{sec:evolution:gate}). Genesis tranche G2b (above) changes
|
||||||
|
this: a major-2-only reader now meets a possible major-3 op block
|
||||||
|
(\texttt{SetTuningContext}) and opens read-only, exactly the one-way door
|
||||||
|
Section~\ref{sec:evolution:gate} describes for every other accept-set raise.
|
||||||
|
|
||||||
\subsection{Changed value layout}
|
\subsection{Changed value layout}
|
||||||
As in majors~1 and~2, the wire form appends new fields \emph{after} the
|
As in majors~1 and~2, the wire form appends new fields \emph{after} the
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -6963,6 +6963,11 @@ pub enum OperationKind {
|
||||||
// SetMetadata advisory-LWW pattern.
|
// SetMetadata advisory-LWW pattern.
|
||||||
SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp),
|
SetCanvasLayoutDefaults(SetCanvasLayoutDefaultsOp),
|
||||||
SetSpellingPrecedence(SetSpellingPrecedenceOp),
|
SetSpellingPrecedence(SetSpellingPrecedenceOp),
|
||||||
|
// Genesis tranche G2b: the sole genesis payload born at schema major 3,
|
||||||
|
// on the same advisory-LWW pattern. Carries TuningContextSettings, the
|
||||||
|
// authored subset of ScoreTuningContext (accidental_extensions is not
|
||||||
|
// on the wire and is left untouched by reduction).
|
||||||
|
SetTuningContext(SetTuningContextOp),
|
||||||
|
|
||||||
// Layout-semantic operations
|
// Layout-semantic operations
|
||||||
SetUserSystemBreak(SetUserSystemBreakOp),
|
SetUserSystemBreak(SetUserSystemBreakOp),
|
||||||
|
|
@ -11931,6 +11936,8 @@ pub enum OperationKindTag {
|
||||||
// Genesis tranche G2a: the two major-0 settings setters.
|
// Genesis tranche G2a: the two major-0 settings setters.
|
||||||
SetCanvasLayoutDefaults,
|
SetCanvasLayoutDefaults,
|
||||||
SetSpellingPrecedence,
|
SetSpellingPrecedence,
|
||||||
|
// Genesis tranche G2b: name-verbatim, as the two prior additions are.
|
||||||
|
SetTuningContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum BarrierScope {
|
pub enum BarrierScope {
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -231,7 +231,7 @@
|
||||||
{\Large\scshape\color{epiphanyslate}Operation Catalog}\\[6pt]
|
{\Large\scshape\color{epiphanyslate}Operation Catalog}\\[6pt]
|
||||||
{\large\itshape\color{epiphanyslate}A companion to the Core Specification}\\[14pt]
|
{\large\itshape\color{epiphanyslate}A companion to the Core Specification}\\[14pt]
|
||||||
{\color{epiphanygold}\rule{3in}{0.8pt}}\\[24pt]
|
{\color{epiphanygold}\rule{3in}{0.8pt}}\\[24pt]
|
||||||
{\normalsize\color{epiphanyink}Version 0.10.0 --- The genesis operation tranche (G1 + G2a)}\\[4pt]
|
{\normalsize\color{epiphanyink}Version 0.11.0 --- The genesis operation tranche reaches schema major 3 (G2b)}\\[4pt]
|
||||||
{\small\color{epiphanyslate}Normative for the operation kinds it defines}
|
{\small\color{epiphanyslate}Normative for the operation kinds it defines}
|
||||||
\vfill
|
\vfill
|
||||||
\end{titlepage}
|
\end{titlepage}
|
||||||
|
|
@ -382,6 +382,41 @@ clause is narrowed to the canvas object itself, per
|
||||||
are no longer outside the operation set; the canvas is still never
|
are no longer outside the operation set; the canvas is still never
|
||||||
op-minted.
|
op-minted.
|
||||||
|
|
||||||
|
\medskip
|
||||||
|
|
||||||
|
\noindent\textbf{Version 0.11.0 (genesis tranche G2b,
|
||||||
|
\texttt{spec/CONTRACT\_GENESIS\_G2B\_TUNING.md}).} Adds one operation kind,
|
||||||
|
\texttt{SetTuningContext} (Section~\ref{sec:k0:set-tuning-context}), the
|
||||||
|
third and final genesis-ladder setter deferred at 0.10.0. Carries
|
||||||
|
\texttt{TuningContextSettings}, the authored subset of
|
||||||
|
\texttt{ScoreTuningContext} --- exactly its five wire-bearing fields, byte-
|
||||||
|
identical to the existing schema-major-3 wire walk (Binary Format companion
|
||||||
|
\sectionsc{Schema Major 3}) --- rather than the full graph type, so that
|
||||||
|
\texttt{accidental\_extensions} (staged off the wire) cannot diverge between
|
||||||
|
a live-authored session and the same document reloaded from bytes.
|
||||||
|
|
||||||
|
\textbf{The sole accept-set-raising surface among the nine genesis
|
||||||
|
settings/creates.} \texttt{SetTuningContext} is schema major~3
|
||||||
|
\emph{unconditionally} (\texttt{ScoreTuningContext}'s \texttt{smufl}/
|
||||||
|
\texttt{overrides} appends are mandatory, so no lower-major layout for this
|
||||||
|
payload exists at any value), which is why it alone --- not
|
||||||
|
\texttt{CreateInstrument} at major~2, and not either G2a setter at major~0 ---
|
||||||
|
drags the \texttt{OperationEnvelopeBlock} accept-set from \texttt{[0, 2]} to
|
||||||
|
\texttt{[0, 3]} (Binary Format companion \sectionsc{The Chunk-Level Gate}).
|
||||||
|
This is the reason the genesis ladder split \texttt{SetTuningContext} into
|
||||||
|
its own rung rather than landing it alongside \texttt{SetCanvasLayoutDefaults}
|
||||||
|
/ \texttt{SetSpellingPrecedence}: a one-way accept-set door is not something
|
||||||
|
to bury inside two unrelated major-0 setters.
|
||||||
|
|
||||||
|
Undo restores the \textbf{seeded base} settings --- default or non-default
|
||||||
|
alike --- exactly as \texttt{SetMetadata} does; the never-authored /
|
||||||
|
authored-to-default distinction stays unobservable
|
||||||
|
(Section~\ref{sec:k0:set-tuning-context}). This closes P13-S13: the
|
||||||
|
canonical operation log is now the sole canonical carrier of the tuning
|
||||||
|
context (the canonical base embeds no \texttt{Score} field value for any
|
||||||
|
setting, \texttt{metadata} included), on the same reasoning that already
|
||||||
|
applied to \texttt{SetMetadata}.
|
||||||
|
|
||||||
% ===========================================================================
|
% ===========================================================================
|
||||||
\chapter{The Catalog Framework}
|
\chapter{The Catalog Framework}
|
||||||
\label{ch:framework}
|
\label{ch:framework}
|
||||||
|
|
@ -1247,6 +1282,79 @@ state rather than absence.
|
||||||
\textbf{Re-anchoring.} Not applicable: the field is a score singleton with no
|
\textbf{Re-anchoring.} Not applicable: the field is a score singleton with no
|
||||||
tombstonable anchor.
|
tombstonable anchor.
|
||||||
|
|
||||||
|
\section{SetTuningContext}
|
||||||
|
\label{sec:k0:set-tuning-context}
|
||||||
|
|
||||||
|
Ratified with the genesis operation tranche's G2b rung (\texttt{spec/
|
||||||
|
CONTRACT\_GENESIS\_G2B\_TUNING.md}, executing \texttt{spec/
|
||||||
|
RULING\_GENESIS\_PERSISTENCE.md}): the score's tuning context settings
|
||||||
|
(\texttt{Score.tuning\_context}) join the operation-authored surfaces, on
|
||||||
|
the same \texttt{SetMetadata} pattern as \texttt{SetCanvasLayoutDefaults}
|
||||||
|
and \texttt{SetSpellingPrecedence} above. Unlike either sibling,
|
||||||
|
\texttt{SetTuningContext} is the \textbf{sole genesis payload born at
|
||||||
|
schema major~3} and is the surface that raises the
|
||||||
|
\texttt{OperationEnvelopeBlock} accept-set from \texttt{[0, 2]} to
|
||||||
|
\texttt{[0, 3]} (Binary Format companion \sectionsc{The Chunk-Level Gate}).
|
||||||
|
|
||||||
|
\textbf{Payload schema.} \texttt{SetTuningContextOp \{ settings:
|
||||||
|
TuningContextSettings \}}. \texttt{TuningContextSettings} is the
|
||||||
|
\textbf{authored subset} of \texttt{ScoreTuningContext}: exactly its five
|
||||||
|
wire-bearing fields (\texttt{default\_pitch\_space},
|
||||||
|
\texttt{default\_tuning\_system}, \texttt{reference}, \texttt{smufl},
|
||||||
|
\texttt{overrides}), in the codec's existing order --- not the full
|
||||||
|
six-field graph type. \texttt{accidental\_extensions} is deliberately
|
||||||
|
\textbf{not} a field of the carried payload: it is staged out of schema
|
||||||
|
major~3 (Binary Format companion \sectionsc{Schema Major 3}) and
|
||||||
|
\texttt{OperationSet::accept} stores the authored envelope as a
|
||||||
|
\emph{value}, so a payload carrying the full \texttt{ScoreTuningContext}
|
||||||
|
would let \texttt{accidental\_extensions} reach the graph on the authoring
|
||||||
|
replica while decoding to empty on every replica that received the
|
||||||
|
document through serialization --- the same document in two graph states,
|
||||||
|
depending only on whether it was just authored or just reloaded. The
|
||||||
|
subset type makes this divergence unrepresentable: a field the payload
|
||||||
|
does not carry cannot be set inconsistently.
|
||||||
|
|
||||||
|
\textbf{Canonical encoding.} The length-framed canonical bytes of
|
||||||
|
\texttt{settings}. \texttt{TuningContextSettings}'s encoding is
|
||||||
|
\textbf{byte-identical} to \texttt{ScoreTuningContext}'s existing
|
||||||
|
five-field wire walk --- a type-level narrowing, not a new wire form. Since
|
||||||
|
\texttt{ScoreTuningContext}'s \texttt{smufl} and \texttt{overrides} appends
|
||||||
|
are mandatory (not \texttt{Option}-hidden), no lower-major layout for this
|
||||||
|
payload exists at any value: \texttt{SetTuningContext} is \textbf{born at
|
||||||
|
schema major~3 unconditionally}, the same shape as \texttt{CreateInstrument}'s
|
||||||
|
unconditional birth at major~2 (Section~\ref{sec:k0:create-instrument}), not
|
||||||
|
the value-dependent shape \texttt{CreateRegion}/\texttt{SetStaffLayout} use.
|
||||||
|
|
||||||
|
\textbf{Reduction rule.} An advisory last-writer-wins field overwrite,
|
||||||
|
identical in discipline to \texttt{SetMetadata}: no working state, no
|
||||||
|
conflict, and no idempotence short-circuit. Graph-aware reduction writes
|
||||||
|
exactly the five subset fields onto \texttt{Score.tuning\_context} and
|
||||||
|
\textbf{leaves \texttt{accidental\_extensions} untouched} --- preserving
|
||||||
|
whatever the graph already held, since the operation carries no
|
||||||
|
information about that field and normalizing it away (clearing it at
|
||||||
|
construction, or rejecting a populated in-memory value) would either make
|
||||||
|
correctness depend on a clearing discipline the compiler cannot see, or
|
||||||
|
turn an in-memory-only field into an authoring error for callers who never
|
||||||
|
opted into its persistence.
|
||||||
|
|
||||||
|
\textbf{Conflict cases.} None (advisory LWW).
|
||||||
|
|
||||||
|
\textbf{Undo semantics.} A value-restoring field overwrite
|
||||||
|
(Section~\ref{sec:k0:undo}), with the chain's value type the \textbf{subset}
|
||||||
|
\texttt{TuningContextSettings}, not \texttt{ScoreTuningContext}: the write
|
||||||
|
chain is seeded from the base's five wire-bearing fields at ingest, so
|
||||||
|
undoing the first operational write restores the pre-operational settings
|
||||||
|
rather than absence, identically whether the base was seeded with the type
|
||||||
|
default or a genuine non-default value --- the never-authored /
|
||||||
|
authored-to-default distinction is unobservable and stays so, since
|
||||||
|
\texttt{ScoreTuningContext} is an always-valued \texttt{Score} field, like
|
||||||
|
\texttt{metadata}, with no absent state to return to. \texttt{accidental\_
|
||||||
|
extensions} never participates in undo: no operation ever writes it, so
|
||||||
|
undo leaves it exactly as it found it.
|
||||||
|
|
||||||
|
\textbf{Re-anchoring.} Not applicable: the field is a score singleton with no
|
||||||
|
tombstonable anchor.
|
||||||
|
|
||||||
\section{Repeat Structures}
|
\section{Repeat Structures}
|
||||||
\label{sec:k0:repeat-structures}
|
\label{sec:k0:repeat-structures}
|
||||||
|
|
||||||
|
|
@ -1604,8 +1712,8 @@ transaction minted is tombstoned. \texttt{StrictInverse} conflicts
|
||||||
\emph{Value restoration} (this revision): for every last-writer-wins overwrite
|
\emph{Value restoration} (this revision): for every last-writer-wins overwrite
|
||||||
the target transaction performed --- event and identified-pitch modification,
|
the target transaction performed --- event and identified-pitch modification,
|
||||||
respelling, cross-cutting modification, metadata, canvas layout defaults,
|
respelling, cross-cutting modification, metadata, canvas layout defaults,
|
||||||
spelling precedence, metric grid, meter change, tempo segment, staff layout,
|
spelling precedence, tuning context settings, metric grid, meter change,
|
||||||
and the user break advisories --- the reducer
|
tempo segment, staff layout, and the user break advisories --- the reducer
|
||||||
maintains, per overwritten key, the \emph{canonical-order write chain} of
|
maintains, per overwritten key, the \emph{canonical-order write chain} of
|
||||||
(writer, value) pairs. Undoing the transaction restores each written key to
|
(writer, value) pairs. Undoing the transaction restores each written key to
|
||||||
its chain-predecessor value (or its absence, where the transaction introduced
|
its chain-predecessor value (or its absence, where the transaction introduced
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -234,7 +234,7 @@
|
||||||
{\Large\scshape\color{epiphanyslate}Text Projection}\\[6pt]
|
{\Large\scshape\color{epiphanyslate}Text Projection}\\[6pt]
|
||||||
{\large\itshape\color{epiphanyslate}A companion to the Core Specification}\\[14pt]
|
{\large\itshape\color{epiphanyslate}A companion to the Core Specification}\\[14pt]
|
||||||
{\color{epiphanygold}\rule{3in}{0.8pt}}\\[24pt]
|
{\color{epiphanygold}\rule{3in}{0.8pt}}\\[24pt]
|
||||||
{\normalsize\color{epiphanyink}Version 0.10.0 --- The carried manifest schema version reaches the document line}\\[4pt]
|
{\normalsize\color{epiphanyink}Version 0.11.0 --- The genesis tuning-context setter reaches the grammar}\\[4pt]
|
||||||
{\small\color{epiphanyslate}Normative for the text form it defines}
|
{\small\color{epiphanyslate}Normative for the text form it defines}
|
||||||
\vfill
|
\vfill
|
||||||
\end{titlepage}
|
\end{titlepage}
|
||||||
|
|
@ -483,7 +483,7 @@ A projection is, in order:
|
||||||
\begin{requirement}
|
\begin{requirement}
|
||||||
\label{req:textproj:header-version}
|
\label{req:textproj:header-version}
|
||||||
A parser implementing this companion \MUST{} accept exactly one header
|
A parser implementing this companion \MUST{} accept exactly one header
|
||||||
version: \texttt{(0 10 0)}, the version of the companion it implements. It
|
version: \texttt{(0 11 0)}, the version of the companion it implements. It
|
||||||
\MUST{} reject any other version at line one.
|
\MUST{} reject any other version at line one.
|
||||||
|
|
||||||
Multi-version acceptance and text migrate-on-read are deferred in the same
|
Multi-version acceptance and text migrate-on-read are deferred in the same
|
||||||
|
|
@ -534,7 +534,7 @@ projection introduces no ordering of its own.
|
||||||
A parser \MUST{} reject every \texttt{(blob ...)} line whose blob is
|
A parser \MUST{} reject every \texttt{(blob ...)} line whose blob is
|
||||||
unreferenced by canonical state
|
unreferenced by canonical state
|
||||||
(Requirement~\ref{req:textproj:canonical-blobs}). At companion
|
(Requirement~\ref{req:textproj:canonical-blobs}). At companion
|
||||||
version~0.10.0, neither a canonical operation nor canonical reduced state can
|
version~0.11.0, neither a canonical operation nor canonical reduced state can
|
||||||
carry a \texttt{BlobId}; canonical state therefore cannot reference a blob,
|
carry a \texttt{BlobId}; canonical state therefore cannot reference a blob,
|
||||||
and a parser \MUST{} reject every \texttt{(blob ...)} line.
|
and a parser \MUST{} reject every \texttt{(blob ...)} line.
|
||||||
\end{requirement}
|
\end{requirement}
|
||||||
|
|
@ -1061,6 +1061,7 @@ kind ::= "(insert-event " bytes " " value ")"
|
||||||
| "(create-instrument " value ")"
|
| "(create-instrument " value ")"
|
||||||
| "(set-canvas-layout-defaults " value ")"
|
| "(set-canvas-layout-defaults " value ")"
|
||||||
| "(set-spelling-precedence " value ")"
|
| "(set-spelling-precedence " value ")"
|
||||||
|
| "(set-tuning-context " value ")"
|
||||||
|
|
||||||
tuplet-comp ::= "not-in-tuplet" | "(replace-with-rest " value ")"
|
tuplet-comp ::= "not-in-tuplet" | "(replace-with-rest " value ")"
|
||||||
| "(rewrite-tuplets (" bytes* "))"
|
| "(rewrite-tuplets (" bytes* "))"
|
||||||
|
|
@ -1137,7 +1138,7 @@ A document of one operation --- a transposition of two pitches up a perfect
|
||||||
fifth, over a compacted base --- projects to five lines:
|
fifth, over a compacted base --- projects to five lines:
|
||||||
|
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
(text-projection (0 10 0))
|
(text-projection (0 11 0))
|
||||||
(document #x05050505050505050505050505050505 (schema 0 1))
|
(document #x05050505050505050505050505050505 (schema 0 1))
|
||||||
(profile full (0 1 0) (constraints 67108864 (retention 1 () true)))
|
(profile full (0 1 0) (constraints 67108864 (retention 1 () true)))
|
||||||
(canonical-base #x1f8b0000000000000000000000000000 #x 1 full (schema 0 1) #x0000)
|
(canonical-base #x1f8b0000000000000000000000000000 #x 1 full (schema 0 1) #x0000)
|
||||||
|
|
@ -1372,6 +1373,18 @@ absorb it, exactly as the binary decoder does.
|
||||||
both claiming \texttt{(0 9 0)}. Cached projections at \texttt{(0 9 0)} do not
|
both claiming \texttt{(0 9 0)}. Cached projections at \texttt{(0 9 0)} do not
|
||||||
migrate; a stale \texttt{TextProjection} chunk is regenerated, not
|
migrate; a stale \texttt{TextProjection} chunk is regenerated, not
|
||||||
converted. \\
|
converted. \\
|
||||||
|
\today & Chapter 5 & 0.11.0 --- The genesis tuning-context setter reaches
|
||||||
|
the grammar (genesis tranche G2b,
|
||||||
|
\texttt{spec/CONTRACT\_GENESIS\_G2B\_TUNING.md}). The \texttt{kind}
|
||||||
|
production gains \texttt{"(set-tuning-context " value ")"}
|
||||||
|
(\texttt{req:textproj:operation-vocabulary}), the third appended kind since
|
||||||
|
the header was gated to a single version at 0.7.0.
|
||||||
|
|
||||||
|
Same forcing reason as every prior grammar-extending bump: holding the
|
||||||
|
version while extending the grammar would leave two mutually incompatible
|
||||||
|
grammars both claiming \texttt{(0 10 0)}. Cached projections at
|
||||||
|
\texttt{(0 10 0)} do not migrate; a stale \texttt{TextProjection} chunk is
|
||||||
|
regenerated, not converted. \\
|
||||||
\bottomrule
|
\bottomrule
|
||||||
\end{longtable}
|
\end{longtable}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,8 +71,9 @@ ops.operation_kind_tag accept - tag_30 1e
|
||||||
ops.operation_kind_tag accept - tag_31 1f
|
ops.operation_kind_tag accept - tag_31 1f
|
||||||
ops.operation_kind_tag accept - tag_32 20
|
ops.operation_kind_tag accept - tag_32 20
|
||||||
ops.operation_kind_tag accept - tag_33 21
|
ops.operation_kind_tag accept - tag_33 21
|
||||||
|
ops.operation_kind_tag accept - tag_34 22
|
||||||
ops.operation_kind_tag accept - registered 1000000000000000000123456789abcdef
|
ops.operation_kind_tag accept - registered 1000000000000000000123456789abcdef
|
||||||
ops.operation_kind_tag reject unknown-discriminant tag_34_one_past_the_vocabulary 22
|
ops.operation_kind_tag reject unknown-discriminant tag_35_one_past_the_vocabulary 23
|
||||||
ops.operation_kind_tag reject unknown-discriminant tag_200 c8
|
ops.operation_kind_tag reject unknown-discriminant tag_200 c8
|
||||||
ops.operation_kind_tag reject truncated tag_empty -
|
ops.operation_kind_tag reject truncated tag_empty -
|
||||||
ops.operation_kind_tag reject trailing-bytes insert_event_trailing 0000
|
ops.operation_kind_tag reject trailing-bytes insert_event_trailing 0000
|
||||||
|
|
@ -85,6 +86,8 @@ ops.operation_envelope accept - set_canvas_layout_defaults 000000000000000100000
|
||||||
ops.operation_envelope reject trailing-bytes set_canvas_layout_defaults_trailing 000000000000000100000000000000020000000000000000000000000000000001000000000000000100000000000000000000010000000000000002000000000000000000002048000000080000000000000000805a40080000000000000000906240080000000000000000001e40080000000000000000001e40080000000000000000001e40080000000000000000001e4000
|
ops.operation_envelope reject trailing-bytes set_canvas_layout_defaults_trailing 000000000000000100000000000000020000000000000000000000000000000001000000000000000100000000000000000000010000000000000002000000000000000000002048000000080000000000000000805a40080000000000000000906240080000000000000000001e40080000000000000000001e40080000000000000000001e40080000000000000000001e4000
|
||||||
ops.operation_envelope accept - set_spelling_precedence 000000000000000100000000000000030000000000000000000000000000000001000000000000000100000000000000000000010000000000000003000000000000000000002109000000050000000403020100
|
ops.operation_envelope accept - set_spelling_precedence 000000000000000100000000000000030000000000000000000000000000000001000000000000000100000000000000000000010000000000000003000000000000000000002109000000050000000403020100
|
||||||
ops.operation_envelope reject trailing-bytes set_spelling_precedence_trailing 00000000000000010000000000000003000000000000000000000000000000000100000000000000010000000000000000000001000000000000000300000000000000000000210900000005000000040302010000
|
ops.operation_envelope reject trailing-bytes set_spelling_precedence_trailing 00000000000000010000000000000003000000000000000000000000000000000100000000000000010000000000000000000001000000000000000300000000000000000000210900000005000000040302010000
|
||||||
|
ops.operation_envelope accept - set_tuning_context 00000000000000010000000000000004000000000000000000000000000000000100000000000000010000000000000000000001000000000000000400000000000000000000223000000006000000636d6e2d3132060000007465742d313200050004080000000000000000907b40010028000100280000000000
|
||||||
|
ops.operation_envelope reject trailing-bytes set_tuning_context_trailing 00000000000000010000000000000004000000000000000000000000000000000100000000000000010000000000000000000001000000000000000400000000000000000000223000000006000000636d6e2d3132060000007465742d313200050004080000000000000000907b4001002800010028000000000000
|
||||||
|
|
||||||
# bundle.manifest
|
# bundle.manifest
|
||||||
bundle.manifest accept - empty_manifest 6f9e7d11689ab113c4a1f05faf60fe60050505050505050505050505050505050000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000001000000000000000000000400000000010000000001000000000000
|
bundle.manifest accept - empty_manifest 6f9e7d11689ab113c4a1f05faf60fe60050505050505050505050505050505050000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000001000000000000000000000400000000010000000001000000000000
|
||||||
|
|
|
||||||
|
|
@ -22,16 +22,16 @@
|
||||||
# document bytes are normative. `<utf8-hex>` is lowercase with no separators.
|
# document bytes are normative. `<utf8-hex>` is lowercase with no separators.
|
||||||
|
|
||||||
# textproj.document
|
# textproj.document
|
||||||
textproj.document accept - minimal 28746578742d70726f6a656374696f6e202830203130203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a
|
textproj.document accept - minimal 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a
|
||||||
textproj.document accept - lineage_custom_profile 28746578742d70726f6a656374696f6e202830203130203029290a28646f63756d656e7420237830323032303230323032303230323032303230323032303230323032303230322028736368656d612030203129290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a
|
textproj.document accept - lineage_custom_profile 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830323032303230323032303230323032303230323032303230323032303230322028736368656d612030203129290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a
|
||||||
textproj.document accept - extension_base_two_envelopes 28746578742d70726f6a656374696f6e202830203130203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a
|
textproj.document accept - extension_base_two_envelopes 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a
|
||||||
textproj.document accept - rich_document 28746578742d70726f6a656374696f6e202830203130203029290a28646f63756d656e7420237830343034303430343034303430343034303430343034303430343034303430342028736368656d612030203129290a286c696e656167652023783134313431343134313431343134313431343134313431343134313431343134290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a28657874656e73696f6e202378303230323032303230323032303230323032303230323032303230323032303220283120302032292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830332929202378303220237830323033290a2863616e6f6e6963616c2d62617365202378303430343034303430343034303430343034303430343034303430343034303420237830313032303420312066756c6c2028736368656d61203020312920237861303034290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303034202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203430302030202378303030303030303030303030303030313030303030303030303030303030303429202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030342929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303035202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203530302030202378303030303030303030303030303030313030303030303030303030303030303529202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030352929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303036202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203630302030202378303030303030303030303030303030313030303030303030303030303030303629202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030362929290a
|
textproj.document accept - rich_document 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830343034303430343034303430343034303430343034303430343034303430342028736368656d612030203129290a286c696e656167652023783134313431343134313431343134313431343134313431343134313431343134290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a28657874656e73696f6e202378303230323032303230323032303230323032303230323032303230323032303220283120302032292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830332929202378303220237830323033290a2863616e6f6e6963616c2d62617365202378303430343034303430343034303430343034303430343034303430343034303420237830313032303420312066756c6c2028736368656d61203020312920237861303034290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303034202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203430302030202378303030303030303030303030303030313030303030303030303030303030303429202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030342929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303035202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203530302030202378303030303030303030303030303030313030303030303030303030303030303529202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030352929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303036202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203630302030202378303030303030303030303030303030313030303030303030303030303030303629202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030362929290a
|
||||||
textproj.document reject wrong-header-version superseded_companion_version 28746578742d70726f6a656374696f6e2028302039203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a
|
textproj.document reject wrong-header-version superseded_companion_version 28746578742d70726f6a656374696f6e202830203130203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a
|
||||||
textproj.document reject blob-line unreferenced_blob 28746578742d70726f6a656374696f6e202830203130203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28626c6f6220226170706c69636174696f6e2f6f637465742d73747265616d222028292023783031290a
|
textproj.document reject blob-line unreferenced_blob 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28626c6f6220226170706c69636174696f6e2f6f637465742d73747265616d222028292023783031290a
|
||||||
textproj.document reject out-of-order-sections canonical_base_before_extension 28746578742d70726f6a656374696f6e202830203130203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a
|
textproj.document reject out-of-order-sections canonical_base_before_extension 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a
|
||||||
textproj.document reject repeated-singular-section lineage_repeated 28746578742d70726f6a656374696f6e202830203130203029290a28646f63756d656e7420237830323032303230323032303230323032303230323032303230323032303230322028736368656d612030203129290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a
|
textproj.document reject repeated-singular-section lineage_repeated 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830323032303230323032303230323032303230323032303230323032303230322028736368656d612030203129290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a
|
||||||
textproj.document reject operation-envelope-order envelopes_reversed 28746578742d70726f6a656374696f6e202830203130203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a
|
textproj.document reject operation-envelope-order envelopes_reversed 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a
|
||||||
textproj.document reject profile-declaration-order profiles_reversed 28746578742d70726f6a656374696f6e202830203130203029290a28646f63756d656e7420237830323032303230323032303230323032303230323032303230323032303230322028736368656d612030203129290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a
|
textproj.document reject profile-declaration-order profiles_reversed 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830323032303230323032303230323032303230323032303230323032303230322028736368656d612030203129290a286c696e656167652023783132313231323132313231323132313231323132313231323132313231323132290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303031202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203130302030202378303030303030303030303030303030313030303030303030303030303030303129202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030312929290a
|
||||||
textproj.document reject extension-declaration-order extensions_reversed 28746578742d70726f6a656374696f6e202830203130203029290a28646f63756d656e7420237830343034303430343034303430343034303430343034303430343034303430342028736368656d612030203129290a286c696e656167652023783134313431343134313431343134313431343134313431343134313431343134290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303230323032303230323032303230323032303230323032303230323032303220283120302032292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830332929202378303220237830323033290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303430343034303430343034303430343034303430343034303430343034303420237830313032303420312066756c6c2028736368656d61203020312920237861303034290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303034202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203430302030202378303030303030303030303030303030313030303030303030303030303030303429202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030342929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303035202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203530302030202378303030303030303030303030303030313030303030303030303030303030303529202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030352929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303036202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203630302030202378303030303030303030303030303030313030303030303030303030303030303629202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030362929290a
|
textproj.document reject extension-declaration-order extensions_reversed 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830343034303430343034303430343034303430343034303430343034303430342028736368656d612030203129290a286c696e656167652023783134313431343134313431343134313431343134313431343134313431343134290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a2870726f66696c652028637573746f6d20237863636363636363636363636363636363636363636363636363636363636363632920283120322033292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303230323032303230323032303230323032303230323032303230323032303220283120302032292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830332929202378303220237830323033290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303430343034303430343034303430343034303430343034303430343034303420237830313032303420312066756c6c2028736368656d61203020312920237861303034290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303034202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203430302030202378303030303030303030303030303030313030303030303030303030303030303429202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030342929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303035202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203530302030202378303030303030303030303030303030313030303030303030303030303030303529202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030352929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303036202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203630302030202378303030303030303030303030303030313030303030303030303030303030303629202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030362929290a
|
||||||
textproj.document reject extension-chunk-order extension_chunks_reversed 28746578742d70726f6a656374696f6e202830203130203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a
|
textproj.document reject extension-chunk-order extension_chunks_reversed 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830333033303330333033303330333033303330333033303330333033303330332028736368656d612030203829290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e203120282920747275652929290a28657874656e73696f6e202378303130313031303130313031303130313031303130313031303130313031303120283120302031292066616c73652028286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830322920286368756e6b20657874656e73696f6e2d646174612028736368656d61203020312920237830312929202378303120237830313032290a2863616e6f6e6963616c2d62617365202378303330333033303330333033303330333033303330333033303330333033303320237830313032303320312066756c6c2028736368656d61203020312920237861303033290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303032202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203230302030202378303030303030303030303030303030313030303030303030303030303030303229202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030322929290a28656e76656c6f70652023783030303030303030303030303030303130303030303030303030303030303033202378303030303030303030303030303030303030303030303030303030303030616220287374616d70203330302030202378303030303030303030303030303030313030303030303030303030303030303329202863617573616c2028292028292920282920287072696d6974697665202864656c6574652d726567696f6e20237830303030303030303030303030303031303030303030303030303030303030332929290a
|
||||||
textproj.document reject missing-trailing-lf final_lf_missing 28746578742d70726f6a656374696f6e202830203130203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e20312028292074727565292929
|
textproj.document reject missing-trailing-lf final_lf_missing 28746578742d70726f6a656374696f6e202830203131203029290a28646f63756d656e7420237830313031303130313031303130313031303130313031303130313031303130312028736368656d612030203129290a2870726f66696c652066756c6c20283020312030292028636f6e73747261696e74732036373130383836342028726574656e74696f6e20312028292074727565292929
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue