From 567e8214a4c9f1f66a4110e86034b6bc164e7b2d Mon Sep 17 00:00:00 2001 From: Levi Neuwirth Date: Thu, 9 Jul 2026 20:32:35 -0400 Subject: [PATCH] One tag vocabulary the compiler owns, and ratify the corpus in the companion Two review findings after P4. Both real. The tag-omission failure could recur. After the P4 fix there were STILL four hand-maintained lists -- a test-local all_tags(), a barrier test spelling 0u8..=30, a fuzz corpus naming five tags, a vector corpus naming four -- plus a malformed-bytes test asserting that 31 rejects. A future tag 31 added to discriminant() and omitted from decode_canonical() would have left every one of them green, and the malformed test would have LOCKED it, exactly as the 30 version did two commits ago. operation_kind_tag_vocabulary! is now the single source. It generates discriminant, from_discriminant, and OperationKindTag::PAYLOAD_FREE from one list, and the generated discriminant match is exhaustive over the enum -- so a variant added to the enum and not to the macro fails to COMPILE. Everything downstream reads PAYLOAD_FREE: the decoder, the fuzz corpus (all 31 tags, not five), the conformance vectors (an accept vector per tag: 65 vectors, not 37), and the edit-barrier round-trip. Every "one past the vocabulary" constant is computed, never spelled; a spelled constant is the trap that springs on whoever appends the next tag. Verified end to end with a hypothetical tag 31. Added to the enum alone: compile error. Added to the enum and the macro: it compiles, decodes, and every derived check passes because they read PAYLOAD_FREE -- while the committed corpus's drift lock AND its now-stale "one past the vocabulary" reject vector both fail, forcing the new vectors into the diff. There is no path where a new tag leaves everything green. Second finding: the corpus called itself normative while the spec said it was deferred. Binary Format's "About This Companion" listed the cross-implementation decoder test among things the document does not cover, and the Golden Anchor Registry called it "the deferred conformance harness" whose literal-byte vectors a future test "should add". Both now ratify it. New req:binfmt:decode-vectors and a "The Decode Vector Corpus" section: a conforming decoder MUST accept every accept vector for a surface it implements, MUST reject every reject vector, and MUST re-encode an accepted value to exactly its bytes -- and accepting a reject vector and then normalizing it IS accepting it. Binary Format 0.8.0 -> 0.9.0. The wire-format fuzzer stays an implementation deliverable. The corpus header now cites the requirement instead of asserting one. Gate: fmt clean, clippy 0, 30 targets / 1024 passed / 0 failed, docs 0 under -D warnings, conformance 8/8 with [7d] at 65 vectors, zero golden churn, binary_format rebuilds with no undefined references. Co-Authored-By: Claude Opus 4.8 (1M context) --- crates/epiphany-bundle/src/vectors.rs | 74 ++++--- crates/epiphany-layout-ir/src/barrier.rs | 16 +- crates/epiphany-ops/DECISIONS.md | 42 ++++ crates/epiphany-ops/src/fuzz.rs | 21 +- crates/epiphany-ops/src/payload.rs | 255 +++++++++++------------ crates/epiphany-ops/src/vectors.rs | 101 ++++++--- crates/epiphany-testkit/src/vectors.rs | 24 ++- spec/binary_format.pdf | Bin 254401 -> 258211 bytes spec/binary_format.tex | 70 ++++++- spec/vectors/decode_vectors.txt | 49 ++++- 10 files changed, 423 insertions(+), 229 deletions(-) diff --git a/crates/epiphany-bundle/src/vectors.rs b/crates/epiphany-bundle/src/vectors.rs index c99c5cf..e004801 100644 --- a/crates/epiphany-bundle/src/vectors.rs +++ b/crates/epiphany-bundle/src/vectors.rs @@ -14,13 +14,17 @@ use crate::{block, DecodeError}; use epiphany_determinism::{ChunkId, ContentHash}; /// `(surface, verdict, class, name, bytes)` — see `epiphany_ops::vectors`. -pub type DecodeVector = ( - &'static str, - &'static str, - &'static str, - &'static str, - Vec, -); +pub type DecodeVector = (&'static str, &'static str, &'static str, String, Vec); + +fn row( + surface: &'static str, + verdict: &'static str, + class: &'static str, + name: impl Into, + bytes: Vec, +) -> DecodeVector { + (surface, verdict, class, name.into(), bytes) +} /// A `ChunkRef` encodes as 95 bytes: id 32, kind 1, schema 4, offset 8, /// compressed_length 8, uncompressed_length 8, compression 2, hash 32. @@ -57,18 +61,24 @@ pub fn decode_vectors() -> Vec { const MAN: &str = "bundle.manifest"; let doc = DocumentId([5; 16]); let empty = Manifest::empty(doc); - v.push((MAN, "accept", "-", "empty_manifest", empty.encode())); + v.push(row(MAN, "accept", "-", "empty_manifest", empty.encode())); let mut one = Manifest::empty(doc); one.operation_roots.push(block_ref(0x11, 576)); let one_bytes = one.encode(); - v.push((MAN, "accept", "-", "one_operation_root", one_bytes.clone())); + v.push(row( + MAN, + "accept", + "-", + "one_operation_root", + one_bytes.clone(), + )); // Body edit: `manifest_id` is derived from the body, so it no longer matches. let mut id_mismatch = one_bytes.clone(); let last = id_mismatch.len() - 1; id_mismatch[last] ^= 0xFF; - v.push(( + v.push(row( MAN, "reject", "manifest-id-mismatch", @@ -84,7 +94,13 @@ pub fn decode_vectors() -> Vec { two.operation_roots.push(block_ref(0x11, 576)); two.operation_roots.push(block_ref(0x22, 1024)); let two_bytes = two.encode(); - v.push((MAN, "accept", "-", "two_operation_roots", two_bytes.clone())); + v.push(row( + MAN, + "accept", + "-", + "two_operation_roots", + two_bytes.clone(), + )); // Locate the first root: id(16) + document_id(16) + lineage option tag(1) // + generation(8) + roots count(4). @@ -93,7 +109,7 @@ pub fn decode_vectors() -> Vec { let body = &reordered[16..]; let redone = ManifestId::derive(doc, 0, body); reordered[0..16].copy_from_slice(&redone.0.to_be_bytes()); - v.push(( + v.push(row( MAN, "reject", "non-canonical-vec-order", @@ -103,7 +119,7 @@ pub fn decode_vectors() -> Vec { let mut trailing = one_bytes.clone(); trailing.push(0); - v.push(( + v.push(row( MAN, "reject", "trailing-bytes", @@ -114,12 +130,18 @@ pub fn decode_vectors() -> Vec { // --- OperationIndex ---------------------------------------------------- const IDX: &str = "bundle.operation_index"; let empty_index = OperationIndex::build(&[]).expect("empty").encode(); - v.push((IDX, "accept", "-", "empty_index", empty_index.clone())); + v.push(row(IDX, "accept", "-", "empty_index", empty_index.clone())); let one_index = OperationIndex::build(&[(block_ref(0x11, 576), vec![([2; 16], 8)])]) .expect("one block") .encode(); - v.push((IDX, "accept", "-", "one_block_one_entry", one_index.clone())); + v.push(row( + IDX, + "accept", + "-", + "one_block_one_entry", + one_index.clone(), + )); let two_index = OperationIndex::build(&[ (block_ref(0x11, 576), vec![([1; 16], 8), ([3; 16], 40)]), @@ -127,7 +149,7 @@ pub fn decode_vectors() -> Vec { ]) .expect("two blocks") .encode(); - v.push((IDX, "accept", "-", "two_blocks", two_index.clone())); + v.push(row(IDX, "accept", "-", "two_blocks", two_index.clone())); // The lenient-compression class. `CompressionAlgorithm::None` used to ignore // this byte, so `[0, 0xFF]` and `[0, 0]` decoded alike: two byte strings, one @@ -135,7 +157,7 @@ pub fn decode_vectors() -> Vec { // (Push 5 / P3; `req:binfmt:compression-none-parameter`.) let mut lenient = one_index.clone(); lenient[4 + CHUNK_REF_COMPRESSION_PARAM] = 0xFF; - v.push(( + v.push(row( IDX, "reject", "lenient-sub-codec", @@ -144,7 +166,7 @@ pub fn decode_vectors() -> Vec { )); // Strict ascent, checked per-site (there is no guard here to catch it). - v.push(( + v.push(row( IDX, "reject", "non-canonical-vec-order", @@ -155,7 +177,7 @@ pub fn decode_vectors() -> Vec { // Entries are 24 bytes: id(16) + block(4) + offset(4). They begin after the // blocks and their count. let entries_at = 4 + 2 * CHUNK_REF_LEN + 4; - v.push(( + v.push(row( IDX, "reject", "non-canonical-vec-order", @@ -167,7 +189,7 @@ pub fn decode_vectors() -> Vec { let mut bad_ordinal = one_index.clone(); let ordinal_at = 4 + CHUNK_REF_LEN + 4 + 16; bad_ordinal[ordinal_at..ordinal_at + 4].copy_from_slice(&7u32.to_le_bytes()); - v.push(( + v.push(row( IDX, "reject", "block-ordinal-out-of-range", @@ -178,7 +200,7 @@ pub fn decode_vectors() -> Vec { // A block reference whose kind is not an operation-envelope block. let mut wrong_kind = one_index.clone(); wrong_kind[4 + 32] = ChunkKind::Snapshot.discriminant(); - v.push(( + v.push(row( IDX, "reject", "wrong-chunk-kind", @@ -188,7 +210,7 @@ pub fn decode_vectors() -> Vec { let mut idx_trailing = empty_index.clone(); idx_trailing.push(0); - v.push(( + v.push(row( IDX, "reject", "trailing-bytes", @@ -201,11 +223,11 @@ pub fn decode_vectors() -> Vec { let payloads: Vec> = vec![vec![0xAA; 8], vec![0xBB; 13]]; let packed = block::pack_operation_blocks(&payloads); let good = packed.first().expect("one block").clone(); - v.push((BLK, "accept", "-", "two_envelopes", good.clone())); + v.push(row(BLK, "accept", "-", "two_envelopes", good.clone())); let mut blk_trailing = good.clone(); blk_trailing.push(0); - v.push(( + v.push(row( BLK, "reject", "trailing-bytes", @@ -215,7 +237,7 @@ pub fn decode_vectors() -> Vec { let mut blk_truncated = good.clone(); blk_truncated.pop(); - v.push(( + v.push(row( BLK, "reject", "truncated", @@ -227,7 +249,7 @@ pub fn decode_vectors() -> Vec { // reject on the count, not pre-allocate for it. let mut huge = good.clone(); huge[0..4].copy_from_slice(&u32::MAX.to_le_bytes()); - v.push(( + v.push(row( BLK, "reject", "count-exceeds-remaining", diff --git a/crates/epiphany-layout-ir/src/barrier.rs b/crates/epiphany-layout-ir/src/barrier.rs index 6ae46f9..bbb5f02 100644 --- a/crates/epiphany-layout-ir/src/barrier.rs +++ b/crates/epiphany-layout-ir/src/barrier.rs @@ -1127,14 +1127,16 @@ mod tests { #[test] fn a_barrier_prohibiting_every_operation_tag_round_trips() { use epiphany_ops::OperationKindRegistryId; - let mut tags: Vec = (0u8..=30) - .filter(|d| *d != 16) - .map(|d| { - epiphany_determinism::CanonicalDecode::decode_canonical(&[d][..]) - .unwrap_or_else(|e| panic!("tag {d} must decode: {e:?}")) - }) - .collect(); + // From the production vocabulary, not a spelled range. `(0u8..=30)` would + // silently stop covering the newest tag the day one is appended — which + // is precisely how this surface broke. + let mut tags: Vec = OperationKindTag::PAYLOAD_FREE.to_vec(); tags.push(OperationKindTag::Registered(OperationKindRegistryId(7))); + assert!( + tags.len() > 30, + "the barrier round-trip must cover every tag, got {}", + tags.len() + ); let barrier = EditBarrier { scope: BarrierScope::WholeScore, diff --git a/crates/epiphany-ops/DECISIONS.md b/crates/epiphany-ops/DECISIONS.md index 9f88352..8f939a6 100644 --- a/crates/epiphany-ops/DECISIONS.md +++ b/crates/epiphany-ops/DECISIONS.md @@ -1569,3 +1569,45 @@ fails if one goes missing. Gated in the conformance suite as `[7d]`, and drift-locked: the committed file must equal `vectors::render()`, so a wire-format change lands in the diff. + +### P4 follow-up: one production-owned tag vocabulary, and the corpus ratified + +Two review findings, both real. + +**1. The tag-omission failure could recur.** After the P4 fix there were *still* +four hand-maintained lists of tags — a test-local `all_tags()`, a barrier test +spelling `0u8..=30`, a fuzz corpus naming five, a vector corpus naming four — +plus a malformed-bytes test asserting `31` rejects. A future tag 31 added to +`discriminant()` and omitted from `decode_canonical()` would have left every one +of them green, and the malformed test would have *locked* it, exactly as the `30` +version did. + +`operation_kind_tag_vocabulary!` is now the single source: it generates +`discriminant`, `from_discriminant`, and `OperationKindTag::PAYLOAD_FREE` from +one list. The generated `discriminant` match is **exhaustive over the enum**, so +a variant added to `OperationKindTag` and not to the macro **fails to compile** +(verified). Everything downstream reads `PAYLOAD_FREE`: the decoder, the fuzz +corpus (all 31 tags, not five), the conformance vectors (an accept vector per +tag, so 65 vectors not 37), and the edit-barrier round-trip. Every "one past the +vocabulary" constant is *computed*, never spelled — a spelled constant is the +trap that springs on whoever appends the next tag. + +Verified end to end by adding a hypothetical tag 31: +- to the enum only → **compile error**; +- to the enum and the macro → compiles, decodes, and every derived check passes + *because* they read `PAYLOAD_FREE` — while the committed corpus's drift lock + and its stale "one past the vocabulary" reject vector both fail, forcing the + new vectors into the diff. + +There is no path where a new tag leaves everything green. + +**2. The corpus called itself normative; the spec said it was deferred.** Binary +Format's §"About This Companion" listed the cross-implementation decoder test +among things the document does *not* cover, and its Golden Anchor Registry called +it "the deferred conformance harness". Both now ratify it: +`req:binfmt:decode-vectors` and §"The Decode Vector Corpus" state that a +conforming decoder MUST accept every `accept` vector, MUST reject every `reject` +vector, and MUST re-encode an accepted value to its own bytes — and that +**accepting a `reject` vector and then normalizing it is accepting it**. Binary +Format 0.8.0 → 0.9.0. The wire-format fuzzer stays an implementation deliverable. +The corpus header now cites the requirement rather than asserting one. diff --git a/crates/epiphany-ops/src/fuzz.rs b/crates/epiphany-ops/src/fuzz.rs index 96e83ac..e8b2d0f 100644 --- a/crates/epiphany-ops/src/fuzz.rs +++ b/crates/epiphany-ops/src/fuzz.rs @@ -707,16 +707,17 @@ fn build_decode_corpus(rng: &mut SplitMix64) -> DecodeCorpus { exactly those branches" ); - let tags = [ - OperationKindTag::InsertEvent, - OperationKindTag::Transpose, - OperationKindTag::TransposeInterval, - OperationKindTag::DeleteRepeatStructure, - OperationKindTag::Registered(crate::OperationKindRegistryId(0x0123_4567_89AB_CDEF)), - ] - .iter() - .map(|t| t.to_canonical_bytes()) - .collect(); + // EVERY tag, from the production vocabulary — not a hand-picked five. A tag + // named nowhere is a tag whose decoder is never exercised, which is how + // `TransposeInterval` encoded to a byte its own decoder rejected. + let tags = OperationKindTag::PAYLOAD_FREE + .iter() + .copied() + .chain(std::iter::once(OperationKindTag::Registered( + crate::OperationKindRegistryId(0x0123_4567_89AB_CDEF), + ))) + .map(|t| t.to_canonical_bytes()) + .collect(); DecodeCorpus { states, tags } } diff --git a/crates/epiphany-ops/src/payload.rs b/crates/epiphany-ops/src/payload.rs index e73e257..dedf68c 100644 --- a/crates/epiphany-ops/src/payload.rs +++ b/crates/epiphany-ops/src/payload.rs @@ -418,45 +418,88 @@ pub enum OperationKindTag { TransposeInterval, } -impl OperationKindTag { - fn discriminant(&self) -> u8 { - match self { - OperationKindTag::InsertEvent => 0, - OperationKindTag::DeleteEvent => 1, - OperationKindTag::ModifyEvent => 2, - OperationKindTag::RespellPitch => 3, - OperationKindTag::Transpose => 4, - OperationKindTag::CreateCrossCutting => 5, - OperationKindTag::DeleteCrossCutting => 6, - OperationKindTag::ModifyCrossCutting => 7, - OperationKindTag::ChangeRegionTimeModel => 8, - OperationKindTag::InsertRegion => 9, - OperationKindTag::DeleteRegion => 10, - OperationKindTag::InsertStaffInstance => 11, - OperationKindTag::DeleteStaffInstance => 12, - OperationKindTag::SetUserSystemBreak => 13, - OperationKindTag::SetUserPageBreak => 14, - OperationKindTag::DeclareTransaction => 15, - OperationKindTag::Registered(_) => 16, - OperationKindTag::InsertIdentifiedPitch => 17, - OperationKindTag::DeleteIdentifiedPitch => 18, - OperationKindTag::ModifyIdentifiedPitch => 19, - OperationKindTag::CreateVoice => 20, - OperationKindTag::DeleteVoice => 21, - OperationKindTag::SetMetadata => 22, - OperationKindTag::SetMetricGrid => 23, - // Phase-3 first tranche; appended past the golden-locked 0..=23. - OperationKindTag::InsertStaff => 24, - OperationKindTag::SetTimeSignature => 25, - OperationKindTag::SetTempoSegment => 26, - OperationKindTag::SetStaffLayout => 27, - // Schema-major-2 revision; appended past the Phase-3 24..=27. - OperationKindTag::CreateRepeatStructure => 28, - OperationKindTag::DeleteRepeatStructure => 29, - // Push 4a; appended past 29. - OperationKindTag::TransposeInterval => 30, +/// The discriminant of [`OperationKindTag::Registered`], the one tag that +/// carries a payload. It sits inside the payload-free range, so it is named +/// rather than derived. +pub const REGISTERED_TAG_DISCRIMINANT: u8 = 16; + +/// The single source of truth for the payload-free tag vocabulary. +/// +/// Generates the discriminant mapping, its inverse, and +/// [`OperationKindTag::PAYLOAD_FREE`] from one list. The generated +/// `discriminant` match is **exhaustive over the enum**, so a variant added to +/// `OperationKindTag` without being added here fails to compile — and because +/// the decoder, the fuzz corpus, the conformance vectors, and the edit-barrier +/// round-trip all read `PAYLOAD_FREE`, adding it here reaches every one of them. +/// +/// This exists because it did not. Push 4a added `TransposeInterval` to a +/// hand-written `discriminant` match and to nothing else: the decoder rejected +/// its own encoding, an edit barrier naming it could not be reopened, and four +/// separate hand-maintained lists — two of them asserting the tag was *unknown* +/// — stayed green (Push 5 / P4). +macro_rules! operation_kind_tag_vocabulary { + ($($variant:ident = $disc:literal),+ $(,)?) => { + impl OperationKindTag { + /// Every payload-free tag, in discriminant order. [`Registered`] + /// is excluded: it carries an id and has no bare encoding. + /// + /// [`Registered`]: OperationKindTag::Registered + pub const PAYLOAD_FREE: &'static [OperationKindTag] = + &[$(OperationKindTag::$variant),+]; + + /// The tag's one-byte wire discriminant + /// (`req:binfmt:kind-tag`; append-only). + pub fn discriminant(&self) -> u8 { + match self { + $(OperationKindTag::$variant => $disc,)+ + OperationKindTag::Registered(_) => REGISTERED_TAG_DISCRIMINANT, + } + } + + /// The payload-free tag for `discriminant`, or `None` if it names + /// no tag. `Registered` is never returned: it is decoded separately, + /// with its id. + fn from_discriminant(discriminant: u8) -> Option { + Some(match discriminant { + $($disc => OperationKindTag::$variant,)+ + _ => return None, + }) + } } - } + }; +} + +operation_kind_tag_vocabulary! { + InsertEvent = 0, + DeleteEvent = 1, + ModifyEvent = 2, + RespellPitch = 3, + Transpose = 4, + CreateCrossCutting = 5, + DeleteCrossCutting = 6, + ModifyCrossCutting = 7, + ChangeRegionTimeModel = 8, + InsertRegion = 9, + DeleteRegion = 10, + InsertStaffInstance = 11, + DeleteStaffInstance = 12, + SetUserSystemBreak = 13, + SetUserPageBreak = 14, + DeclareTransaction = 15, + InsertIdentifiedPitch = 17, + DeleteIdentifiedPitch = 18, + ModifyIdentifiedPitch = 19, + CreateVoice = 20, + DeleteVoice = 21, + SetMetadata = 22, + SetMetricGrid = 23, + InsertStaff = 24, + SetTimeSignature = 25, + SetTempoSegment = 26, + SetStaffLayout = 27, + CreateRepeatStructure = 28, + DeleteRepeatStructure = 29, + TransposeInterval = 30, } impl CanonicalEncode for OperationKindTag { @@ -481,7 +524,7 @@ impl CanonicalDecode for OperationKindTag { expected: 1, actual: 0, })?; - if tag == 16 { + if tag == REGISTERED_TAG_DISCRIMINANT { let arr: [u8; 16] = rest.try_into().map_err(|_| DecodeError::UnexpectedLength { expected: 17, actual: bytes.len(), @@ -496,43 +539,9 @@ impl CanonicalDecode for OperationKindTag { actual: bytes.len(), }); } - Ok(match tag { - 0 => OperationKindTag::InsertEvent, - 1 => OperationKindTag::DeleteEvent, - 2 => OperationKindTag::ModifyEvent, - 3 => OperationKindTag::RespellPitch, - 4 => OperationKindTag::Transpose, - 5 => OperationKindTag::CreateCrossCutting, - 6 => OperationKindTag::DeleteCrossCutting, - 7 => OperationKindTag::ModifyCrossCutting, - 8 => OperationKindTag::ChangeRegionTimeModel, - 9 => OperationKindTag::InsertRegion, - 10 => OperationKindTag::DeleteRegion, - 11 => OperationKindTag::InsertStaffInstance, - 12 => OperationKindTag::DeleteStaffInstance, - 13 => OperationKindTag::SetUserSystemBreak, - 14 => OperationKindTag::SetUserPageBreak, - 15 => OperationKindTag::DeclareTransaction, - 17 => OperationKindTag::InsertIdentifiedPitch, - 18 => OperationKindTag::DeleteIdentifiedPitch, - 19 => OperationKindTag::ModifyIdentifiedPitch, - 20 => OperationKindTag::CreateVoice, - 21 => OperationKindTag::DeleteVoice, - 22 => OperationKindTag::SetMetadata, - 23 => OperationKindTag::SetMetricGrid, - 24 => OperationKindTag::InsertStaff, - 25 => OperationKindTag::SetTimeSignature, - 26 => OperationKindTag::SetTempoSegment, - 27 => OperationKindTag::SetStaffLayout, - 28 => OperationKindTag::CreateRepeatStructure, - 29 => OperationKindTag::DeleteRepeatStructure, - // Push 4a. Omitting this made `to_canonical_bytes` and - // `decode_canonical` asymmetric: the tag encoded to `[30]` and - // would not read back, so an edit barrier that named - // `TransposeInterval` could be persisted and never reopened. - 30 => OperationKindTag::TransposeInterval, - _ => return Err(DecodeError::MalformedDomainTag), - }) + // The mapping is generated from the same list as `discriminant` + // (`operation_kind_tag_vocabulary!`), so encode and decode cannot drift. + OperationKindTag::from_discriminant(tag).ok_or(DecodeError::MalformedDomainTag) } } @@ -1902,71 +1911,58 @@ mod tests { assert_eq!(prim.tag(), OperationKindTag::RespellPitch); } - /// **Every** `OperationKindTag` variant, listed by name. + /// **Every** `OperationKindTag`, derived from the production vocabulary. /// - /// Enumerating *variants* is the point. The round-trip test used to - /// enumerate *discriminants* — `(0u8..30).map(decode_canonical)` — which - /// starts from bytes the decoder already knows and therefore cannot notice a - /// variant the decoder is missing. Push 4a added `TransposeInterval` to - /// `discriminant()` and not to `decode_canonical`, and that test stayed - /// green while the tag encoded to `[30]` and would not read back. - /// - /// Adding a variant without adding it here fails `the_tag_vocabulary_is_complete`. + /// Not a hand-written list. `OperationKindTag::PAYLOAD_FREE` is generated by + /// `operation_kind_tag_vocabulary!`, whose `discriminant` match is + /// exhaustive over the enum — so a variant that exists cannot be missing + /// here, and the fuzz corpus, the conformance vectors, and the edit-barrier + /// round-trip all read the same constant. fn all_tags() -> Vec { - let mut tags = vec![ - OperationKindTag::InsertEvent, - OperationKindTag::DeleteEvent, - OperationKindTag::ModifyEvent, - OperationKindTag::RespellPitch, - OperationKindTag::Transpose, - OperationKindTag::CreateCrossCutting, - OperationKindTag::DeleteCrossCutting, - OperationKindTag::ModifyCrossCutting, - OperationKindTag::ChangeRegionTimeModel, - OperationKindTag::InsertRegion, - OperationKindTag::DeleteRegion, - OperationKindTag::InsertStaffInstance, - OperationKindTag::DeleteStaffInstance, - OperationKindTag::SetUserSystemBreak, - OperationKindTag::SetUserPageBreak, - OperationKindTag::DeclareTransaction, - OperationKindTag::InsertIdentifiedPitch, - OperationKindTag::DeleteIdentifiedPitch, - OperationKindTag::ModifyIdentifiedPitch, - OperationKindTag::CreateVoice, - OperationKindTag::DeleteVoice, - OperationKindTag::SetMetadata, - OperationKindTag::SetMetricGrid, - OperationKindTag::InsertStaff, - OperationKindTag::SetTimeSignature, - OperationKindTag::SetTempoSegment, - OperationKindTag::SetStaffLayout, - OperationKindTag::CreateRepeatStructure, - OperationKindTag::DeleteRepeatStructure, - OperationKindTag::TransposeInterval, - ]; + let mut tags = OperationKindTag::PAYLOAD_FREE.to_vec(); tags.push(OperationKindTag::Registered(OperationKindRegistryId( 0x0102_0304_0506_0708_090A_0B0C_0D0E_0F10, ))); tags } + /// One past the payload-free vocabulary — computed, never spelled. Spelling + /// it is how `30` came to be asserted *unknown* while it was + /// `TransposeInterval`. + fn first_unknown_discriminant() -> u8 { + OperationKindTag::PAYLOAD_FREE + .iter() + .map(OperationKindTag::discriminant) + .max() + .expect("a non-empty vocabulary") + + 1 + } + /// A compile-time-ish completeness check: `all_tags` must match the /// vocabulary the decoder accepts, in both directions. #[test] fn the_tag_vocabulary_is_complete() { let tags = all_tags(); - assert_eq!(tags.len(), 31, "30 payload-less tags plus `Registered`"); + let unknown = first_unknown_discriminant(); - // Every payload-less discriminant 0..=30 except 16 decodes to a variant - // that is in the list. - for d in (0u8..=30).filter(|d| *d != 16) { + // The payload-free discriminants are exactly `0..unknown`, minus the one + // `Registered` occupies. No gaps: the vocabulary is dense and + // append-only. + for d in (0..unknown).filter(|d| *d != REGISTERED_TAG_DISCRIMINANT) { let decoded = OperationKindTag::decode_canonical(&[d]) .unwrap_or_else(|e| panic!("discriminant {d} must decode: {e:?}")); - assert!(tags.contains(&decoded), "{decoded:?} missing from all_tags"); + assert!( + tags.contains(&decoded), + "{decoded:?} missing from PAYLOAD_FREE" + ); } - // And 31 is one past the vocabulary. - assert!(OperationKindTag::decode_canonical(&[31]).is_err()); + assert_eq!( + tags.len(), + usize::from(unknown), + "{unknown} payload-free discriminants (one of them `Registered`'s), \ + plus the `Registered` value itself" + ); + assert!(OperationKindTag::decode_canonical(&[unknown]).is_err()); } #[test] @@ -2002,12 +1998,13 @@ mod tests { #[test] fn operation_kind_tag_decode_rejects_malformed_bytes() { use epiphany_determinism::DecodeError; - // Unknown discriminant (31 is one past the vocabulary): rejected, - // never normalized. This assertion named 30 until Push 5 / P4, by which - // time 30 was `TransposeInterval` — so the test was actively locking a - // bug in place rather than guarding against one. + // One past the vocabulary: rejected, never normalized. COMPUTED, not + // spelled. This assertion literally said `30` until Push 5 / P4, by + // which time 30 was `TransposeInterval` — so the test was locking a bug + // in place rather than guarding against one. A spelled constant here is + // a trap that springs on whoever appends the next tag. assert_eq!( - OperationKindTag::decode_canonical(&[31]), + OperationKindTag::decode_canonical(&[first_unknown_discriminant()]), Err(DecodeError::MalformedDomainTag) ); // Empty input. diff --git a/crates/epiphany-ops/src/vectors.rs b/crates/epiphany-ops/src/vectors.rs index 53477b8..7ba133d 100644 --- a/crates/epiphany-ops/src/vectors.rs +++ b/crates/epiphany-ops/src/vectors.rs @@ -29,13 +29,19 @@ use crate::{ /// `verdict` is `"accept"` or `"reject"`. An `accept` vector additionally /// asserts **injectivity**: the decoded value must re-encode to exactly these /// bytes. -pub type DecodeVector = ( - &'static str, - &'static str, - &'static str, - &'static str, - Vec, -); +pub type DecodeVector = (&'static str, &'static str, &'static str, String, Vec); + +/// One row. `name` is a `String` because the tag vectors derive theirs from the +/// production vocabulary rather than spelling them. +fn row( + surface: &'static str, + verdict: &'static str, + class: &'static str, + name: impl Into, + bytes: Vec, +) -> DecodeVector { + (surface, verdict, class, name.into(), bytes) +} /// Swaps the two equal-length records of `entry` bytes that begin at `first`. fn swap_records(bytes: &[u8], first: usize, entry: usize) -> Vec { @@ -75,7 +81,7 @@ pub fn decode_vectors() -> Vec { // --- MaterializedState ------------------------------------------------- const MS: &str = "ops.materialized_state"; let empty = MaterializedState::default().canonical_bytes(); - v.push((MS, "accept", "-", "empty_state", empty.clone())); + v.push(row(MS, "accept", "-", "empty_state", empty.clone())); // Two objects, canonically ordered. Swapping them is caught only by the // whole-state re-encode guard: `objects` is a BTreeMap, so the decoder @@ -91,8 +97,8 @@ pub fn decode_vectors() -> Vec { } .canonical_bytes(); let (at, entry) = count_and_entry(&empty, &two_objects); - v.push((MS, "accept", "-", "two_objects", two_objects.clone())); - v.push(( + v.push(row(MS, "accept", "-", "two_objects", two_objects.clone())); + v.push(row( MS, "reject", "non-canonical-map-order", @@ -117,8 +123,14 @@ pub fn decode_vectors() -> Vec { } .canonical_bytes(); let (at, entry) = count_and_entry(&empty, &two_anomalies); - v.push((MS, "accept", "-", "two_anomalies", two_anomalies.clone())); - v.push(( + v.push(row( + MS, + "accept", + "-", + "two_anomalies", + two_anomalies.clone(), + )); + v.push(row( MS, "reject", "non-canonical-vec-order", @@ -140,8 +152,8 @@ pub fn decode_vectors() -> Vec { } .canonical_bytes(); let (at, entry) = count_and_entry(&empty, &two_pending); - v.push((MS, "accept", "-", "two_pending", two_pending.clone())); - v.push(( + v.push(row(MS, "accept", "-", "two_pending", two_pending.clone())); + v.push(row( MS, "reject", "non-canonical-vec-order", @@ -151,7 +163,7 @@ pub fn decode_vectors() -> Vec { let mut trailing = empty.clone(); trailing.push(0); - v.push(( + v.push(row( MS, "reject", "trailing-bytes", @@ -161,7 +173,7 @@ pub fn decode_vectors() -> Vec { let mut truncated = empty.clone(); truncated.pop(); - v.push(( + v.push(row( MS, "reject", "truncated", @@ -173,7 +185,7 @@ pub fn decode_vectors() -> Vec { // pre-allocate on it, and must not loop toward EOF for a measurable time. let mut huge_count = empty.clone(); huge_count[0..4].copy_from_slice(&u32::MAX.to_le_bytes()); - v.push(( + v.push(row( MS, "reject", "count-exceeds-remaining", @@ -182,22 +194,49 @@ pub fn decode_vectors() -> Vec { )); // --- OperationKindTag -------------------------------------------------- + // + // EVERY tag gets an accept vector, generated from the production vocabulary. + // A hand-picked subset is how `TransposeInterval` shipped encoding to a byte + // its own decoder rejected: the corpus never named it. A new tag now lands in + // the committed file as a new line, and the drift lock forces it into the diff. const TAG: &str = "ops.operation_kind_tag"; - for (name, tag) in [ - ("insert_event", OperationKindTag::InsertEvent), - ("transpose_frozen", OperationKindTag::Transpose), - ("transpose_interval", OperationKindTag::TransposeInterval), - ( - "registered", - OperationKindTag::Registered(OperationKindRegistryId(0x0123_4567_89AB_CDEF)), - ), - ] { - v.push((TAG, "accept", "-", name, tag.to_canonical_bytes())); + for tag in OperationKindTag::PAYLOAD_FREE { + let name = format!("tag_{:02}", tag.discriminant()); + v.push(row(TAG, "accept", "-", name, tag.to_canonical_bytes())); } + v.push(row( + TAG, + "accept", + "-", + "registered", + OperationKindTag::Registered(OperationKindRegistryId(0x0123_4567_89AB_CDEF)) + .to_canonical_bytes(), + )); - v.push((TAG, "reject", "unknown-discriminant", "tag_200", vec![200])); - v.push((TAG, "reject", "truncated", "tag_empty", Vec::new())); - v.push(( + // One past the vocabulary, computed rather than spelled. + let unknown = OperationKindTag::PAYLOAD_FREE + .iter() + .map(OperationKindTag::discriminant) + .max() + .expect("a non-empty vocabulary") + + 1; + v.push(row( + TAG, + "reject", + "unknown-discriminant", + format!("tag_{unknown}_one_past_the_vocabulary"), + vec![unknown], + )); + + v.push(row( + TAG, + "reject", + "unknown-discriminant", + "tag_200", + vec![200], + )); + v.push(row(TAG, "reject", "truncated", "tag_empty", Vec::new())); + v.push(row( TAG, "reject", "trailing-bytes", @@ -208,7 +247,7 @@ pub fn decode_vectors() -> Vec { let mut short_registered = OperationKindTag::Registered(OperationKindRegistryId(1)).to_canonical_bytes(); short_registered.pop(); - v.push(( + v.push(row( TAG, "reject", "truncated", diff --git a/crates/epiphany-testkit/src/vectors.rs b/crates/epiphany-testkit/src/vectors.rs index ad3354b..71e5354 100644 --- a/crates/epiphany-testkit/src/vectors.rs +++ b/crates/epiphany-testkit/src/vectors.rs @@ -2,10 +2,11 @@ //! decode-hardening track). //! //! `spec/vectors/decode_vectors.txt` is a committed, human-diffable list of byte -//! strings and their normative accept/reject verdict. It is what a *second* -//! implementation is checked against — the reference implementation's fuzzers -//! prove its own decoders self-consistent, which says nothing about whether a -//! foreign decoder agrees with the format. +//! strings and their accept/reject verdict, ratified by the Binary Format +//! companion's `req:binfmt:decode-vectors` (§"The Decode Vector Corpus"). It is +//! what a *second* implementation is checked against — the reference +//! implementation's fuzzers prove its own decoders self-consistent, which says +//! nothing about whether a foreign decoder agrees with the format. //! //! Two properties are enforced here: //! @@ -36,11 +37,16 @@ const HEADER: &str = "\ # # # -# `verdict` is `accept` or `reject`, and is the ONLY normative column besides -# the bytes. A conforming decoder must accept every `accept` vector and reject -# every `reject` vector. An accepted value must additionally re-encode to -# exactly the vector's bytes: canonical decode is injective, which is what -# content-addressing rests on. +# NORMATIVE: Binary Format companion, `req:binfmt:decode-vectors` +# (section: The Decode Vector Corpus). A conforming decoder MUST accept every `accept` +# vector for a surface it implements and MUST reject every `reject` vector, and +# a value decoded from an `accept` vector MUST re-encode to exactly its bytes. +# +# Accepting a `reject` vector and then normalizing it IS accepting it, and does +# not satisfy the requirement. Canonical decode is injective: distinct byte +# strings denote distinct values, which is what content-addressing rests on. +# +# `verdict` and the bytes are the only normative columns. # # `class` names why a `reject` vector is rejected. It is informative only — # implementations need not agree on error taxonomy. `-` where not applicable. diff --git a/spec/binary_format.pdf b/spec/binary_format.pdf index 00d3065f5b85975d26ff5bae6d13cf11ccda3ea1..748e573fb0b035a3272d6755d34847dc3348e3db 100644 GIT binary patch delta 49518 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®_dv?To9mETCc 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≶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 JB$cHQ{tq08kYoS= delta 45767 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 diff --git a/spec/binary_format.tex b/spec/binary_format.tex index 476da5b..3224260 100644 --- a/spec/binary_format.tex +++ b/spec/binary_format.tex @@ -235,7 +235,7 @@ {\Large\scshape\color{epiphanyslate}Binary Format}\\[6pt] {\large\itshape\color{epiphanyslate}A companion to the Core Specification}\\[14pt] {\color{epiphanygold}\rule{3in}{0.8pt}}\\[24pt] - {\normalsize\color{epiphanyink}Version 0.8.0 --- Strict CompressionAlgorithm decode (the non-zero None parameter is rejected, not ignored)}\\[4pt] + {\normalsize\color{epiphanyink}Version 0.9.0 --- The decode vector corpus is ratified (the cross-implementation decoder test is no longer deferred)}\\[4pt] {\small\color{epiphanyslate}Normative for the byte layouts it defines} \vfill \end{titlepage} @@ -275,13 +275,16 @@ This document does \emph{not} cover: companion's; \item the Chapter-4 tuning-catalog values (pitch-space and tuning-system registries), which are undelivered Track-C work and have no wire form yet; - \item the required conformance harnesses (the cross-implementation decoder - test and the wire-format fuzzer). Those are \emph{implementation} - deliverables tracked in the Phase-2 process documents, not part of this - document's normative text; Chapter~\ref{ch:goldens} records the golden - anchors that any such harness must reproduce. + \item the wire-format fuzzer, an \emph{implementation} deliverable tracked + in the Phase-2 process documents rather than part of this document's + normative text; Chapter~\ref{ch:goldens} records the golden anchors any + such harness must reproduce. \end{itemize} +It \emph{does} cover the cross-implementation decoder test, which is no longer +deferred: Section~\ref{sec:goldens:decode-vectors} ratifies the literal-byte +vector corpus and the accept/reject verdict a conforming decoder owes it. + \section{Relationship to the Core Specification and the Operation Catalog} \label{sec:about:relationship} @@ -3121,9 +3124,48 @@ Each anchor names its crate file, then the test on a second line. Struct \emph{bodies} in Chapter~\ref{ch:values} are round-trip-locked rather than literal-byte-locked: their byte identity follows from the frozen positional rule plus the literal-byte locks on every discriminant and leaf -they embed. A future cross-implementation decoder test (the deferred -conformance harness) should add literal-byte vectors for the representative -layouts of Section~\ref{sec:values:representative}. +they embed. + +\section{The Decode Vector Corpus} +\label{sec:goldens:decode-vectors} + +The cross-implementation decoder test is \textbf{delivered}, as a corpus of +literal byte strings each paired with the verdict a decoder owes it. The +reference implementation carries it at \texttt{spec/vectors/decode\_vectors.txt} +and regenerates it from a committed generator, so a change to any wire form +moves the file. + +Each line is \texttt{surface\ \ verdict\ \ class\ \ name\ \ hex}. The +\texttt{verdict} is \texttt{accept} or \texttt{reject}. The \texttt{class} +names \emph{why} a rejected vector is rejected and is \textbf{informative +only}: implementations need not agree on an error taxonomy. + +\begin{requirement} + \label{req:binfmt:decode-vectors} + A conforming decoder \MUST{} accept every \texttt{accept} vector for a + surface it implements, and \MUST{} reject every \texttt{reject} vector for + that surface. A value decoded from an \texttt{accept} vector \MUST{} + re-encode to exactly that vector's bytes. + + Accepting a \texttt{reject} vector and then normalizing it is + \emph{accepting} it, and does not satisfy this requirement. Canonical decode + is injective: distinct byte strings denote distinct values, which is what + content-addressing rests on. +\end{requirement} + +\begin{rationale} + The corpus is not a restatement of this document; it is what a second + implementation can be run against. Every rejection class in it is one the + reference implementation shipped a bug in, or one whose check no injectivity + fuzzer can see: a whole-value re-encode guard catches the fields a decoder + \emph{normalizes} and is blind to order-preserving sequence fields, which need + per-site order checks; and a guard on an outer value can \emph{mask} a lenient + inner codec rather than fix it (Push~5). + + A future revision should extend the corpus to the representative struct + layouts of Section~\ref{sec:values:representative}, which remain round-trip + locked rather than literal-byte locked. +\end{rationale} % =========================================================================== \chapter{Revision History} @@ -3239,6 +3281,16 @@ layouts of Section~\ref{sec:values:representative}. having no whole-value re-encode guard, accepted both. Found by the wire-decode fuzzer. Supersedes the core specification's ``ignored on read''; no wire layout changed and no conforming writer is affected. \\ + \today & Golden anchors & 0.9.0 --- Ratifies the decode vector corpus + (Push~5, P4): \texttt{req:binfmt:decode-vectors} and + Section~\ref{sec:goldens:decode-vectors}. The cross-implementation decoder + test moves out of the \sectionsc{About This Companion} exclusion list and out + of the \sectionsc{Golden Anchor Registry}'s ``deferred conformance harness'' + note: literal byte vectors with accept/reject verdicts now exist + (\texttt{spec/vectors/decode\_vectors.txt}), and a conforming decoder owes them + the verdict. Accepting a \texttt{reject} vector and normalizing it is + \emph{accepting} it. The wire-format fuzzer remains an implementation + deliverable. No wire layout changed. \\ \bottomrule \end{longtable} diff --git a/spec/vectors/decode_vectors.txt b/spec/vectors/decode_vectors.txt index c31d4ab..61ad350 100644 --- a/spec/vectors/decode_vectors.txt +++ b/spec/vectors/decode_vectors.txt @@ -9,11 +9,16 @@ # # # -# `verdict` is `accept` or `reject`, and is the ONLY normative column besides -# the bytes. A conforming decoder must accept every `accept` vector and reject -# every `reject` vector. An accepted value must additionally re-encode to -# exactly the vector's bytes: canonical decode is injective, which is what -# content-addressing rests on. +# NORMATIVE: Binary Format companion, `req:binfmt:decode-vectors` +# (section: The Decode Vector Corpus). A conforming decoder MUST accept every `accept` +# vector for a surface it implements and MUST reject every `reject` vector, and +# a value decoded from an `accept` vector MUST re-encode to exactly its bytes. +# +# Accepting a `reject` vector and then normalizing it IS accepting it, and does +# not satisfy the requirement. Canonical decode is injective: distinct byte +# strings denote distinct values, which is what content-addressing rests on. +# +# `verdict` and the bytes are the only normative columns. # # `class` names why a `reject` vector is rejected. It is informative only — # implementations need not agree on error taxonomy. `-` where not applicable. @@ -33,10 +38,38 @@ ops.materialized_state reject truncated empty_state_truncated 000000000000000000 ops.materialized_state reject count-exceeds-remaining effects_count_u32_max ffffffff00000000000000000000000000000000000000000000000000000000 # ops.operation_kind_tag -ops.operation_kind_tag accept - insert_event 00 -ops.operation_kind_tag accept - transpose_frozen 04 -ops.operation_kind_tag accept - transpose_interval 1e +ops.operation_kind_tag accept - tag_00 00 +ops.operation_kind_tag accept - tag_01 01 +ops.operation_kind_tag accept - tag_02 02 +ops.operation_kind_tag accept - tag_03 03 +ops.operation_kind_tag accept - tag_04 04 +ops.operation_kind_tag accept - tag_05 05 +ops.operation_kind_tag accept - tag_06 06 +ops.operation_kind_tag accept - tag_07 07 +ops.operation_kind_tag accept - tag_08 08 +ops.operation_kind_tag accept - tag_09 09 +ops.operation_kind_tag accept - tag_10 0a +ops.operation_kind_tag accept - tag_11 0b +ops.operation_kind_tag accept - tag_12 0c +ops.operation_kind_tag accept - tag_13 0d +ops.operation_kind_tag accept - tag_14 0e +ops.operation_kind_tag accept - tag_15 0f +ops.operation_kind_tag accept - tag_17 11 +ops.operation_kind_tag accept - tag_18 12 +ops.operation_kind_tag accept - tag_19 13 +ops.operation_kind_tag accept - tag_20 14 +ops.operation_kind_tag accept - tag_21 15 +ops.operation_kind_tag accept - tag_22 16 +ops.operation_kind_tag accept - tag_23 17 +ops.operation_kind_tag accept - tag_24 18 +ops.operation_kind_tag accept - tag_25 19 +ops.operation_kind_tag accept - tag_26 1a +ops.operation_kind_tag accept - tag_27 1b +ops.operation_kind_tag accept - tag_28 1c +ops.operation_kind_tag accept - tag_29 1d +ops.operation_kind_tag accept - tag_30 1e ops.operation_kind_tag accept - registered 1000000000000000000123456789abcdef +ops.operation_kind_tag reject unknown-discriminant tag_31_one_past_the_vocabulary 1f ops.operation_kind_tag reject unknown-discriminant tag_200 c8 ops.operation_kind_tag reject truncated tag_empty - ops.operation_kind_tag reject trailing-bytes insert_event_trailing 0000