From 3e91a8302aa6996c2a9c0c9a9081d1deb3d34588 Mon Sep 17 00:00:00 2001 From: Levi Neuwirth Date: Thu, 2 Jul 2026 19:02:07 -0400 Subject: [PATCH] Push 4: Binary Format companion, F1 benches, subquadratic reduction order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The audit's fourth push: the biggest outstanding Phase-2 item plus the performance gate. 793 workspace tests pass; clippy -D warnings, fmt, and rustdoc (deny-warnings) clean; all three spec documents build with zero undefined references. Binary Format companion (spec/binary_format.tex, v0.1.0 — Agent J's deliverable, 43 pages): - Twelve chapters transcribed from the golden-locked implementation: encoding conventions (the three prefix/endianness regimes, a normative no-varint rule, reject-never-normalize decode discipline), identifiers imported from the core spec's Canonical Byte-Layout Reference, primitive value encodings, the whole-Score positional codec ratified as the schema-major-0 wire form, operation wire forms (envelope field order with the normative id-leads property, the OperationPayload 0..=3 and OperationKind 0..=23 tables, effects/conflict/anomaly/MaterializedState vocabulary), the bundle physical layout (64-byte header, 256-byte superblock, chunk preimages and framing, ChunkRef, manifest body order), the operation-index payload, and the extension-blob/edit-barrier byte forms. - Ratifies P12-D1 (req:binfmt:opindex), P12-E1 (req:binfmt:ext-blobs), P12-E2 (req:binfmt:condition-depth, MAX_CONDITION_DEPTH = 64 normative), and P12-E3 (req:binfmt:object-kind-open) — batch rows struck through; discharges the provisional-codec notes in core (P11-4), ops, and bundle (P11-D2/D4/D5) DECISIONS with ratification cross-references. - Pins the frozen-layout schema-evolution keystone: within schema major 0 every positional struct layout is frozen; a field-set change is a schema-major change with migration — formally grounding the data-model-expansion staging decision. Open questions kept honest in-document: SnapshotId derivation, index-refresh threshold, u64/u32 prefix unification at the next major. - Not yet delivered from J's charter: the cross-implementation decoder test and the wire-format fuzzer (follow-up harnesses). F1 benches (crates/epiphany-testkit/benches/, per the F0 decision): - criterion 0.5.1 (workspace dev-dependency; MSRV 1.77 respected with documented transitive pins: clap 4.5.53, half 2.4.1). - reduction bench at 1K/10K/50K envelopes with the Chapter-10 budget (>10,000 envelopes/second cold) written in the bench as a Pass/Xfail gate; bundle benches for the typical-edit commit (<=50 ms; measured ~14.7 ms on real disk after catching that tmpfs neuters fsync) and the open/bootstrap read (<=200 ms; measured ~60 us). - CI: quick budget gates in the conformance job, full gates nightly. Subquadratic canonical_reduction_order (the F-surfaces/K-fixes handshake, closing K's 10K-envelope acceptance gate): - The bench documented the failure (50K at ~1.7K env/s, a 29 s cold reduction; two O(n^2) loops); the fix replaces pair enumeration with threshold/frontier readiness per replica plus explicit-dot dependent lists and a stamp-tuple binary heap — O((n + sum(context)) log n), never materializing covered pairs. - Byte-identical order: same edge relation, same ready predicate, same total order; the old implementation is retained as a test-only oracle with element-for-element order-equality property tests over fuzz sets, adversarial sets, and directed shapes (2,000-envelope full-coverage chains, dot cycles, duplicate-id stamp ties), mutation-tested for sensitivity. - Measured: 1K 155K->674K env/s, 10K 12.5K->257K, 50K 1.7K->87K; all three scale points now pass and the 50K row is promoted from Xfail. Also: fixed nine rustdoc private/unresolved intra-doc links that had accumulated across the pushes (the CI deny-doc-warnings job would have failed on them). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01NEs4aYiu8MXjdYdMxw8PTd --- .github/workflows/ci.yml | 15 + Cargo.lock | 226 ++ Cargo.toml | 7 + crates/epiphany-bundle/DECISIONS.md | 8 + crates/epiphany-core/DECISIONS.md | 8 + crates/epiphany-core/src/prepass.rs | 2 +- crates/epiphany-core/src/tempo.rs | 2 +- crates/epiphany-editor-core/src/lib.rs | 2 +- crates/epiphany-engrave/src/lib.rs | 4 +- crates/epiphany-layout-ir/DECISIONS.md | 6 + crates/epiphany-layout-ir/src/hittest.rs | 2 +- crates/epiphany-ops/DECISIONS.md | 75 + crates/epiphany-ops/src/payload.rs | 4 +- crates/epiphany-ops/src/reduce.rs | 633 ++++- crates/epiphany-ops/src/valuegen.rs | 2 +- crates/epiphany-render-svg/src/lib.rs | 9 +- crates/epiphany-testkit/Cargo.toml | 18 + crates/epiphany-testkit/DECISIONS.md | 92 +- crates/epiphany-testkit/README.md | 34 + crates/epiphany-testkit/benches/bundle.rs | 284 ++ crates/epiphany-testkit/benches/reduction.rs | 195 ++ crates/epiphany-testkit/src/budget.rs | 293 ++ crates/epiphany-testkit/src/corpus.rs | 2 +- crates/epiphany-testkit/src/lib.rs | 5 + spec/PASS12_BATCH.md | 19 +- spec/binary_format.pdf | Bin 0 -> 200616 bytes spec/binary_format.tex | 2525 ++++++++++++++++++ 27 files changed, 4448 insertions(+), 24 deletions(-) create mode 100644 crates/epiphany-testkit/benches/bundle.rs create mode 100644 crates/epiphany-testkit/benches/reduction.rs create mode 100644 crates/epiphany-testkit/src/budget.rs create mode 100644 spec/binary_format.pdf create mode 100644 spec/binary_format.tex diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 307f734..0e8a05c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -105,6 +105,17 @@ jobs: - name: Run conformance suite run: cargo run --release -p epiphany-testkit --example conformance_suite 1 + # The Chapter 10 performance-budget gates (Phase 2 worklist F1), in + # release with reduced sampling (EPIPHANY_BENCH_QUICK): the 1K and 10K + # reduction points and both bundle budgets must pass; known-pending + # points are documented xfails inside the benches ("F surfaces, K + # fixes"). The heaviest (50K) reduction point runs only in the nightly + # soak below. + - name: Performance budget gates (quick) + env: + EPIPHANY_BENCH_QUICK: "1" + run: cargo bench -p epiphany-testkit + # Track A, Agent H's merge gate (Phase 2). A discrete job so a spelling / # decomposition pre-pass regression is attributable to H, not buried in the # workspace test run. Asserts H's PHASE2_QUICKSTART acceptance criterion: the @@ -138,3 +149,7 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Run conformance soak run: cargo run --release -p epiphany-testkit --example conformance_suite 10 + # The full budget-gate run, including the minute-scale 50K reduction + # point (a documented xfail until the O(n²) reducer fix lands). + - name: Performance budget gates (full) + run: cargo bench -p epiphany-testkit diff --git a/Cargo.lock b/Cargo.lock index 72a3b56..49ebbd0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -127,6 +127,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + [[package]] name = "android-activity" version = "0.6.1" @@ -161,6 +170,18 @@ dependencies = [ "libc", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + [[package]] name = "arboard" version = "3.6.1" @@ -583,6 +604,12 @@ dependencies = [ "wayland-client", ] +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cc" version = "1.2.65" @@ -622,6 +649,58 @@ dependencies = [ "libc", ] +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.5.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" + [[package]] name = "clipboard-win" version = "5.4.1" @@ -789,12 +868,52 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools", + "num-traits", + "once_cell", + "oorandom", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "crypto-common" version = "0.1.7" @@ -997,6 +1116,12 @@ dependencies = [ "winit", ] +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + [[package]] name = "emath" version = "0.29.1" @@ -1151,6 +1276,7 @@ dependencies = [ name = "epiphany-testkit" version = "0.0.0" dependencies = [ + "criterion", "epiphany-bundle", "epiphany-core", "epiphany-determinism", @@ -1593,6 +1719,16 @@ dependencies = [ "bitflags 2.13.0", ] +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.15.5" @@ -1792,6 +1928,32 @@ dependencies = [ "hashbrown 0.17.1", ] +[[package]] +name = "is-terminal" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "jni" version = "0.22.4" @@ -2466,6 +2628,12 @@ version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + [[package]] name = "orbclient" version = "0.3.55" @@ -2794,6 +2962,35 @@ dependencies = [ "bitflags 2.13.0", ] +[[package]] +name = "regex" +version = "1.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + [[package]] name = "renderdoc-sys" version = "1.1.0" @@ -2973,6 +3170,19 @@ dependencies = [ "syn 2.0.118", ] +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "serde_repr" version = "0.1.20" @@ -3312,6 +3522,16 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tinyvec" version = "1.11.0" @@ -4541,6 +4761,12 @@ dependencies = [ "syn 2.0.118", ] +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + [[package]] name = "zstd" version = "0.13.3" diff --git a/Cargo.toml b/Cargo.toml index 446ab7d..4c4ae81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,6 +88,13 @@ unicode-normalization = "0.1" # produce compressed fixtures. Default features (legacy formats, dictionary # building) are off — none are needed to decode standard frames. zstd = { version = "0.13", default-features = false } +# Criterion drives the Chapter 10 performance benches (Phase 2 worklist F1) in +# epiphany-testkit/benches (see that crate's DECISIONS.md, F0/F1). Pinned to +# the 0.5 line: its MSRV (1.70) fits the workspace's pinned 1.77, while +# criterion 0.6+ requires 1.80. Default features are off — the plotting stack +# (plotters) and rayon are dead weight for budget gates — keeping only +# `cargo_bench_support` so plain `cargo bench` remains the entry point. +criterion = { version = "0.5", default-features = false, features = ["cargo_bench_support"] } # Determinism-sensitive: never enable fast-math-style codegen on canonical # numerical paths (Appendix D, "Rounding and CPU Behavior"). The default diff --git a/crates/epiphany-bundle/DECISIONS.md b/crates/epiphany-bundle/DECISIONS.md index 893053b..586aec3 100644 --- a/crates/epiphany-bundle/DECISIONS.md +++ b/crates/epiphany-bundle/DECISIONS.md @@ -351,6 +351,14 @@ When that companion lands, reconcile this crate's `header`, `superblock`, round-trip would be the trigger, per the QUICKSTART process notes). This is the file-format analogue of `epiphany-core`'s P11-4. +> **Ratified (2026-07-02):** `spec/binary_format.tex` v0.1.0 Chapter 7 pins +> this crate's header (64-byte table), superblock (256-byte table), chunk +> framing and hash preimages, `ChunkRef`, block framing, the manifest body +> order with its sort/dedup rules, and the operation-index payload (P12-D1, +> `req:binfmt:opindex`) exactly as implemented and golden-locked here. The +> reconciliation trigger never fired: the companion was transcribed from this +> crate. + ### P11-D3 — Blob hashing shape is ambiguous Chapter 8 §"Blobs" says blobs are *"content-addressed identically to chunks diff --git a/crates/epiphany-core/DECISIONS.md b/crates/epiphany-core/DECISIONS.md index 6a1256b..9c881a7 100644 --- a/crates/epiphany-core/DECISIONS.md +++ b/crates/epiphany-core/DECISIONS.md @@ -139,6 +139,14 @@ companion lands, reconcile this crate's `CanonicalEncode`/`CanonicalDecode` and the whole-score `codec` with it (a failing cross-crate round-trip test would be the trigger, per the QUICKSTART process notes). +> **Ratified (2026-07-02):** the Binary Format companion now exists +> (`spec/binary_format.tex`, v0.1.0). Its Chapter 5 ratifies this crate's +> whole-`Score` positional codec, the convention macros, every discriminant +> table, and the `CanonicalValue` seam as the schema-major-0 wire form, with +> the frozen-layout rule (a field-set change is a schema-major change). No +> reconciliation was needed: the companion was transcribed from this codec and +> its golden anchors, so the trigger never fired. + **Phase 2 — Agent K (Operation Catalog): the `CanonicalValue` seam.** Track B's Operation Catalog shifts `epiphany-ops` from identifier-only operation payloads to *value-typed* ones (an `InsertEvent` carrying the real `Event`, a diff --git a/crates/epiphany-core/src/prepass.rs b/crates/epiphany-core/src/prepass.rs index 79a294e..c437832 100644 --- a/crates/epiphany-core/src/prepass.rs +++ b/crates/epiphany-core/src/prepass.rs @@ -1186,7 +1186,7 @@ fn decomposition_source_rank(source: &DecompositionSource) -> usize { /// decompositions only "for events that lack a higher-precedence attachment", /// with the "same precedence machinery" as spelling, minus the axes the /// attachment does not carry (no analysis layers, no `priority` field). Among -/// competing authored attachments the lowest [`decomposition_source_rank`] +/// competing authored attachments the lowest `decomposition_source_rank` /// wins; a remaining tie keeps the first candidate in the score's /// `decomposition_attachments` order, which is canonical (codec-fixed), so the /// resolution is deterministic across replicas. diff --git a/crates/epiphany-core/src/tempo.rs b/crates/epiphany-core/src/tempo.rs index 0689ef7..f8f00e9 100644 --- a/crates/epiphany-core/src/tempo.rs +++ b/crates/epiphany-core/src/tempo.rs @@ -163,7 +163,7 @@ const INVERSION_TOLERANCE_WHOLE_NOTES: f64 = 1e-6; /// The typed absolute residual tolerance of the inverse conversion /// ([`TempoMap::wallclock_to_musical`]): a [`Tolerance`] of class /// [`ToleranceClass::TempoIntegration`] (Appendix D §"Tolerance Classes" — no -/// ad-hoc epsilons), absolute bound [`INVERSION_TOLERANCE_WHOLE_NOTES`] whole +/// ad-hoc epsilons), absolute bound `INVERSION_TOLERANCE_WHOLE_NOTES` whole /// notes, no relative bound, governing validation (it decides whether a /// continued-fraction candidate is accepted; conversion is advisory, never /// canonical state). diff --git a/crates/epiphany-editor-core/src/lib.rs b/crates/epiphany-editor-core/src/lib.rs index 29dc1ae..25c92de 100644 --- a/crates/epiphany-editor-core/src/lib.rs +++ b/crates/epiphany-editor-core/src/lib.rs @@ -1000,7 +1000,7 @@ impl EditorSession { /// replaying the log reconstructs the same atomic unit. This is the substrate for /// intents that must land several primitives together (e.g. a value change with a /// matching respelling); editor-level atomicity (commit only on full success) is - /// inherited from [`Self::commit`]. + /// inherited from the private `commit` path. pub fn apply_transaction( &mut self, label: &str, diff --git a/crates/epiphany-engrave/src/lib.rs b/crates/epiphany-engrave/src/lib.rs index f40ce0e..aa32924 100644 --- a/crates/epiphany-engrave/src/lib.rs +++ b/crates/epiphany-engrave/src/lib.rs @@ -4,7 +4,7 @@ //! Agent I's **engraving constraint solver** (spec **Chapter 9**, "Constraint- //! Solver Interface"): it turns a [`ConstrainedLayoutIR`] into a //! [`ResolvedLayoutIR`] with real geometry. It is the production-side replacement -//! for `epiphany-layout-ir`'s interface-only [`StubSolver`] — the QUICKSTART puts +//! for `epiphany-layout-ir`'s interface-only `StubSolver` — the QUICKSTART puts //! the *interface* (`layout-ir`) and the *algorithm* (`engrave`) in separate //! crates so the core/product boundary stays sharp (`spec/PHASE2_QUICKSTART.md`, //! crate topology). @@ -12,7 +12,7 @@ //! ## Phase status — `Minimal` tier //! //! [`Engraver`] runs a genuine deterministic **horizontal spacing pass** (see -//! [`spacing`]) — placing each glyph-bearing slot left-to-right by a +//! the private `spacing` module) — placing each glyph-bearing slot left-to-right by a //! collision-aware advance (its preferred width floored by the real glyph //! bearings) — and **evaluates the IR's declared constraints** against the //! resolved geometry, routed by [`LayoutConstraint::strength`] (Chapter 9 diff --git a/crates/epiphany-layout-ir/DECISIONS.md b/crates/epiphany-layout-ir/DECISIONS.md index 47c82bb..7065de0 100644 --- a/crates/epiphany-layout-ir/DECISIONS.md +++ b/crates/epiphany-layout-ir/DECISIONS.md @@ -343,6 +343,12 @@ object is covered); the provenance-preservation contract itself is unchanged. declarations and gates `apply`/`apply_transaction` through `EditBarrier::prohibits_edit`. + > **Ratified (2026-07-02):** `spec/binary_format.tex` v0.1.0 Chapter 8 + > ratifies the blob byte form (P12-E1, `req:binfmt:ext-blobs`), pins + > `MAX_CONDITION_DEPTH = 64` as the normative recursion bound (P12-E2, + > `req:binfmt:condition-depth`), and adopts the open-value `ObjectKind` + > decode stance (P12-E3, `req:binfmt:object-kind-open`). + ## Pass 12 candidates (ambiguities for the spec, not resolved in code) 1. **Strength attachment to constraint instances.** Chapter 9 §"Strength Levels" diff --git a/crates/epiphany-layout-ir/src/hittest.rs b/crates/epiphany-layout-ir/src/hittest.rs index 87b81e9..e9de4e9 100644 --- a/crates/epiphany-layout-ir/src/hittest.rs +++ b/crates/epiphany-layout-ir/src/hittest.rs @@ -11,7 +11,7 @@ //! ## Coordinate frame //! //! Shapes are in **staff-space, y-up world** coordinates — the same frame as -//! [`RenderPrimitive::position`] and [`Stroke`] endpoints, *before* any +//! [`RenderPrimitive::position`] and stroke endpoints, *before* any //! renderer's world→screen transform. A GUI maps a screen point to this frame //! with the inverse of the same transform its renderer uses for display (for the //! SVG renderer, the inverse of its single `translate(-min_x, max_y) scale(1,-1)` diff --git a/crates/epiphany-ops/DECISIONS.md b/crates/epiphany-ops/DECISIONS.md index e63d142..dfd0d15 100644 --- a/crates/epiphany-ops/DECISIONS.md +++ b/crates/epiphany-ops/DECISIONS.md @@ -431,6 +431,15 @@ is deterministic and unambiguous but **provisional**: when the Binary Format companion lands, reconcile `encode.rs` and the per-type `CanonicalEncode` impls with it. A failing cross-crate round-trip test is the trigger. +> **Ratified (2026-07-02):** `spec/binary_format.tex` v0.1.0 Chapter 6 pins +> this crate's wire forms exactly as implemented — the envelope field order and +> its normative id-leads property, the `OperationPayload` (0..=3) and +> `OperationKind` (0..=23, append-only) discriminant tables, per-payload +> framing, `OperationKindTag`'s separate space, the 28-byte stamp, the DVV +> layout, and the full effects/conflict/anomaly/`MaterializedState` vocabulary. +> The reconciliation trigger never fired: the companion was transcribed from +> this crate and its golden anchors. + ## Spec-compliance audit follow-up (2026-07, Push 1) Four reduction-semantics fixes closing MUST-level gaps the six-agent spec audit @@ -708,3 +717,69 @@ equivocation fuzz plus the unchanged `run_equivocation_fuzz` gate this). no change to the determinism crate. No encoding changed and no discriminant was appended; `operation_kind_tag_decode_mirrors_encode_exactly` / `operation_kind_tag_decode_rejects_malformed_bytes` pin the contract. + +## Subquadratic `canonical_reduction_order` (2026-07, the F1 → K fix) + +- **The defect (F surfaces, K fixes).** The testkit's F1 bench + (`crates/epiphany-testkit/benches/reduction.rs`, Chapter 10: > 10,000 + envelopes/s cold) documented `canonical_reduction_order` as O(n²) twice + over: a literal double loop over all (predecessor, successor) pairs to + build indegrees, and a full ready-scan per emission. Measured pre-fix: + ~155K / ~12.5K / ~1.7K env/s at 1K / 10K / 50K envelopes (50K ≈ 29 s per + cold reduce — the documented xfail row). +- **The algorithm: term decomposition + monotone thresholds, never pairs.** + Materializing edges is inherently quadratic for the common chain shape + (every DVV floor covers the whole replica prefix, so covered *pairs* are + Θ(n²)); the rewrite therefore never enumerates pairs. Each causal-context + entry becomes one *requirement term* over the present set: + - *Vector floor `(r, n)`* — covers exactly the present envelopes of replica + `r` with counter `<= n` (zero-based floor, P11-C7): a **prefix** of the + replica's lane sorted by `(counter, slice index)`. The term is satisfied + when the lane's emission **frontier** (first unemitted slot, monotone) + passes the prefix; if the floor covers the envelope's own id, only the + self-pair is exempt, so that term instead reads "frontier at own slot and + **second frontier** past the prefix" (both monotone). Terms park in + per-lane `BTreeMap`s keyed by the threshold slot and are drained exactly + once as the frontiers advance. + - *Explicit dot* — covers exactly the present envelopes bearing that id; + satisfied when the id's unemitted multiplicity reaches 0 (1 for a + self-dot, which covers only duplicate-id twins). + An envelope is ready when its unsatisfied-term count reaches zero; ready + envelopes sit in a `BinaryHeap` keyed by `(reduction tuple, slice index)`. + A pre-sorted `(tuple, index)` list with a cursor supplies the malformed- + cycle fallback (heap empty, envelopes remain). Total work is + `O((n + Σ|context|) log n)`. +- **Why the order is byte-identical (the consensus argument).** The order is + *defined* by: edge `p → s` iff `p != s` and `s.context.covers(p.id)`; + ready iff every present covered predecessor emitted; emit the minimum + `(reduction tuple, slice index)` among ready (slice index reproduces + `min_by_key`'s first-minimum rule — reachable only under duplicate-id + tuple ties); if none is ready, the same minimum over all unemitted (cycle + break). The rewrite computes the *same readiness predicate*: each term is + satisfied iff all envelopes it covers are emitted, every covered + predecessor is covered by at least one term, and terms cover only covered + predecessors — so "all terms satisfied" ⇔ "all covered predecessors + emitted", including the exempt self-pair (a floor/dot naming the + envelope's own id) and envelopes covered by both a dot and a floor (the + conjunction needs no per-pair dedup; the redundant term is harmless). + Absent context entries (unknown replicas, floors below every present + counter, absent dots) yield no term, exactly as they yield no edge. Same + edge relation, same ready set, same total order on ready ⇒ the same + emission sequence, element for element. +- **The retained oracle + regression gate.** The pre-fix implementation is + kept verbatim as `canonical_reduction_order_reference` (`#[cfg(test)]`), + and three property tests assert element-for-element *pointer* equality of + both orders (the strictest check — it distinguishes byte-identical twins): + `canonical_order_matches_reference_on_fuzz_sets` (the crate's well-formed + fuzz generator, 250 seeds × 2 slice orders), + `..._on_adversarial_sets` (400 randomized hostile sets: self-covering + floors, dots to present/absent/own ids, duplicate ids with tied stamps, + `SYSTEM_DERIVED` replicas, stamps contradicting the causal edges, empty + contexts), and `..._on_directed_shapes` (a 2,000-envelope full-coverage + chain with descending stamps, self-covering and dot-only chains, dot + 2-/3-cycles, mutual-floor cycles, twin permutations). Mutation-checked: + breaking the self-exemption or the self-dot threshold fails the suite. +- **Measured post-fix (same bench, dev profile 2026-07):** ~674K / ~257K / + ~87K env/s at 1K / 10K / 50K — the 50K row cleared its budget by ~8.7x, + the gate printed its XPASS promotion notice, and the row was flipped to + `Pass` in the same change (see `epiphany-testkit/DECISIONS.md` F1). diff --git a/crates/epiphany-ops/src/payload.rs b/crates/epiphany-ops/src/payload.rs index 88c08c9..ebd5603 100644 --- a/crates/epiphany-ops/src/payload.rs +++ b/crates/epiphany-ops/src/payload.rs @@ -709,7 +709,7 @@ pub(crate) fn resolved_anchor_position(anchor: &TimeAnchor) -> MusicalPosition { impl SetUserSystemBreakOp { /// The anchor's resolved musical position — the canonical LWW bucketing key - /// (see [`resolved_anchor_position`]). + /// (see the private `resolved_anchor_position` helper). pub fn resolved_position(&self) -> MusicalPosition { resolved_anchor_position(&self.anchor) } @@ -1118,7 +1118,7 @@ pub struct SetUserPageBreakOp { impl SetUserPageBreakOp { /// The anchor's resolved musical position — the canonical LWW bucketing key - /// (see [`resolved_anchor_position`]). + /// (see the private `resolved_anchor_position` helper). pub fn resolved_position(&self) -> MusicalPosition { resolved_anchor_position(&self.anchor) } diff --git a/crates/epiphany-ops/src/reduce.rs b/crates/epiphany-ops/src/reduce.rs index db45d83..9e7e8be 100644 --- a/crates/epiphany-ops/src/reduce.rs +++ b/crates/epiphany-ops/src/reduce.rs @@ -28,7 +28,8 @@ //! deferred to the Operation Catalog (§6.11); see `DECISIONS.md` for the exact //! boundary. -use std::collections::{BTreeMap, BTreeSet}; +use std::cmp::Reverse; +use std::collections::{BTreeMap, BTreeSet, BinaryHeap}; use epiphany_core::{ canonical_pitch_bytes, derive_promoted_voice_id, AnchorOffset, AnnotationAnchor, @@ -59,6 +60,7 @@ use crate::payload::{ RespellPitchOp, SetMetadataOp, SetMetricGridOp, SetUserPageBreakOp, TransposeOp, TupletCompensation, }; +use crate::stamp::StampTuple; use crate::support::{ObjectKind, SerializedCanonicalInputs}; use crate::undo::{UndoPolicy, UndoTransactionPayload}; @@ -71,8 +73,297 @@ use crate::undo::{UndoPolicy, UndoTransactionPayload}; /// coverage, choosing the smallest HLC reduction tuple among ready operations. /// A malformed causal cycle has no valid topological order; the smallest HLC /// tuple deterministically breaks the cycle so every replica still converges. +/// +/// ## Subquadratic construction (worklist F1 → K fix) +/// +/// The order is *defined* pairwise: an edge `p → s` exists iff `p != s` and +/// `s.causal_context.covers(p.id)`; an envelope is *ready* when every present +/// covered predecessor has been emitted; the smallest reduction tuple among +/// ready envelopes emits next (slice position breaks the — duplicate-id-only — +/// tuple ties, matching `min_by_key`'s first-minimum rule, which the retained +/// test-only `canonical_reduction_order_reference` oracle implements literally +/// in O(n²)). Materializing the edges is inherently quadratic for the common +/// chain-context shape (every DVV floor covers the full replica prefix), so +/// this implementation never enumerates pairs. It decomposes each context into +/// *requirement terms* whose conjunction is exactly pairwise readiness: +/// +/// * A **vector floor** `(r, n)` covers precisely the present envelopes of +/// replica `r` with counter `<= n` (the zero-based DVV floor, P11-C7) — +/// a *prefix* of the replica's lane sorted by `(counter, slice index)`. +/// The term is satisfied when the lane's emission frontier (the first +/// unemitted lane slot) passes the prefix; a floor that covers the +/// envelope's *own* id exempts only the self-pair, so that term is instead +/// "frontier at own slot and *second* frontier past the prefix". Both +/// frontiers are monotone, so each term is woken exactly once from a +/// `BTreeMap` keyed by the threshold slot. +/// * An **explicit dot** covers precisely the present envelopes bearing that +/// id; the term is satisfied when the id's unemitted multiplicity reaches +/// zero (or one, for a dot naming the envelope's own id). A dot also lying +/// under one of the context's own floors yields a (redundant) second term — +/// harmless, because readiness is the conjunction of terms, not a +/// predecessor count, so no per-pair dedup is needed. +/// +/// Context entries covering no present envelope (absent replicas, floors below +/// every present counter, absent dots) yield no term, exactly as they yield no +/// edge pairwise. Total work is `O((n + Σ context entries) · log n)`. pub fn canonical_reduction_order<'a>( envelopes: &[&'a OperationEnvelope], +) -> Vec<&'a OperationEnvelope> { + let len = envelopes.len(); + let keys: Vec = envelopes + .iter() + .map(|env| env.stamp.reduction_tuple()) + .collect(); + + // Static indexes over the present set: per-replica lanes sorted by + // (counter, slice index), each envelope's (lane, slot) position, and the + // per-id unemitted multiplicity (> 1 only for duplicate ids, e.g. + // equivocation twins fed to this function directly). + let mut lane_of: BTreeMap = BTreeMap::new(); + let mut lanes: Vec = Vec::new(); + let mut position = vec![(0usize, 0usize); len]; + { + let mut sorted: Vec<(ReplicaId, u64, usize)> = envelopes + .iter() + .enumerate() + .map(|(index, env)| (env.id.replica, env.id.counter, index)) + .collect(); + sorted.sort_unstable(); + for (replica, counter, index) in sorted { + let lane_index = *lane_of.entry(replica).or_insert_with(|| { + lanes.push(OrderLane::default()); + lanes.len() - 1 + }); + let lane = &mut lanes[lane_index]; + position[index] = (lane_index, lane.slots.len()); + lane.slots.push(index); + lane.counters.push(counter); + } + for lane in &mut lanes { + // All slots start unemitted: frontier 0, second frontier 1 + // (clamped to the lane length, the "exhausted" sentinel). + lane.second = 1.min(lane.slots.len()); + } + } + let mut id_slots: BTreeMap = BTreeMap::new(); + for env in envelopes { + id_slots.entry(env.id).or_default().unemitted += 1; + } + + // One requirement term per covering context entry; `remaining` counts the + // currently-unsatisfied terms. Terms already satisfied here (they cover + // nothing, or nothing beyond the envelope itself) register no watcher. + let mut remaining = vec![0usize; len]; + for (index, env) in envelopes.iter().enumerate() { + for (&replica, &floor) in &env.causal_context.vector { + let Some(&lane_index) = lane_of.get(&replica) else { + continue; + }; + let lane = &mut lanes[lane_index]; + let prefix = lane.counters.partition_point(|&counter| counter <= floor); + if prefix == 0 { + continue; + } + if env.id.replica == replica && env.id.counter <= floor { + // The floor covers this envelope's own id; only the self-pair + // is exempt. Required: every other prefix slot emitted, i.e. + // frontier at the own slot *and* second frontier past the + // prefix (the own slot stays unemitted until emission). + let own_slot = position[index].1; + if lane.frontier < own_slot { + remaining[index] += 1; + lane.frontier_watchers.entry(own_slot).or_default().push( + FloorWatcher::ExceptSelf { + node: index, + prefix, + }, + ); + } else if lane.second < prefix { + remaining[index] += 1; + lane.second_watchers.entry(prefix).or_default().push(index); + } + } else if lane.frontier < prefix { + remaining[index] += 1; + lane.frontier_watchers + .entry(prefix) + .or_default() + .push(FloorWatcher::Whole { node: index }); + } + } + for dot in env.causal_context.dots() { + let Some(id_slot) = id_slots.get_mut(&dot) else { + continue; // absent id: covers nothing present, no edge + }; + if dot == env.id { + // A dot naming the envelope's own id covers only duplicates. + if id_slot.unemitted > 1 { + remaining[index] += 1; + id_slot.watch_one.push(index); + } + } else { + remaining[index] += 1; + id_slot.watch_zero.push(index); + } + } + } + + // Deterministic Kahn walk. The heap holds every envelope whose terms are + // all satisfied (pushed exactly at the transition; entries for envelopes + // already emitted through cycle-breaking are skipped lazily), keyed by + // (reduction tuple, slice index) — the reference's `min_by_key` order. + let mut heap: BinaryHeap> = (0..len) + .filter(|&index| remaining[index] == 0) + .map(|index| Reverse((keys[index], index))) + .collect(); + let mut by_key: Vec = (0..len).collect(); + by_key.sort_unstable_by_key(|&index| (keys[index], index)); + let mut cycle_cursor = 0usize; + + let mut emitted = vec![false; len]; + let mut ordered = Vec::with_capacity(len); + let mut woken: Vec = Vec::new(); + while ordered.len() < len { + let mut ready = None; + while let Some(Reverse((_, index))) = heap.pop() { + if !emitted[index] { + ready = Some(index); + break; + } + } + let next = match ready { + Some(index) => index, + None => { + // A cycle is malformed, but selecting by the canonical + // tie-breaker keeps reduction deterministic and unlocks the + // forced envelope's dependents. + while emitted[by_key[cycle_cursor]] { + cycle_cursor += 1; + } + by_key[cycle_cursor] + } + }; + emitted[next] = true; + ordered.push(envelopes[next]); + + // Dot wake-ups: the id's unemitted multiplicity dropped by one. + let id_slot = id_slots + .get_mut(&envelopes[next].id) + .expect("every present id has a slot"); + id_slot.unemitted -= 1; + if id_slot.unemitted <= 1 { + woken.append(&mut id_slot.watch_one); + } + if id_slot.unemitted == 0 { + woken.append(&mut id_slot.watch_zero); + } + + // Floor wake-ups: advance the lane frontiers (both point at unemitted + // slots — or the lane length — by invariant, so an emission below the + // second frontier is at one of them) and drain the passed watchers. + let (lane_index, slot) = position[next]; + let lane = &mut lanes[lane_index]; + if slot == lane.frontier { + lane.frontier = lane.second; + lane.second = next_unemitted(&lane.slots, &emitted, lane.frontier + 1); + } else if slot == lane.second { + lane.second = next_unemitted(&lane.slots, &emitted, slot + 1); + } + while let Some(entry) = lane.frontier_watchers.first_entry() { + if *entry.key() > lane.frontier { + break; + } + for watcher in entry.remove() { + match watcher { + FloorWatcher::Whole { node } => woken.push(node), + FloorWatcher::ExceptSelf { node, prefix } => { + if lane.second >= prefix { + woken.push(node); + } else { + lane.second_watchers.entry(prefix).or_default().push(node); + } + } + } + } + } + while let Some(entry) = lane.second_watchers.first_entry() { + if *entry.key() > lane.second { + break; + } + for node in entry.remove() { + woken.push(node); + } + } + + for node in woken.drain(..) { + remaining[node] -= 1; + if remaining[node] == 0 && !emitted[node] { + heap.push(Reverse((keys[node], node))); + } + } + } + ordered +} + +/// One replica's present envelopes in [`canonical_reduction_order`], sorted by +/// `(counter, slice index)`, with the two monotone emission frontiers and the +/// floor-term watchers keyed by the frontier slot they wait for. +#[derive(Default)] +struct OrderLane { + /// Envelope slice indexes, sorted by `(counter, slice index)`. + slots: Vec, + /// The slots' counters (parallel to `slots`, ascending). + counters: Vec, + /// First unemitted slot (== `slots.len()` once exhausted). + frontier: usize, + /// Second unemitted slot (>= `slots.len()` once fewer than two remain). + second: usize, + /// Floor terms waiting for `frontier >= key`. + frontier_watchers: BTreeMap>, + /// Self-exempt floor terms waiting for `second >= key`. + second_watchers: BTreeMap>, +} + +/// One present `OperationId`'s bookkeeping in [`canonical_reduction_order`]: +/// its unemitted multiplicity and the dot terms watching it. +#[derive(Default)] +struct IdSlot { + /// Present envelopes bearing this id that are not yet emitted. + unemitted: usize, + /// Dot terms satisfied when `unemitted` reaches zero. + watch_zero: Vec, + /// Self-dot terms (duplicate ids) satisfied when `unemitted` reaches one. + watch_one: Vec, +} + +/// A floor term parked in [`OrderLane::frontier_watchers`]. +enum FloorWatcher { + /// Satisfied outright when the frontier reaches its key (the prefix end). + Whole { node: usize }, + /// A floor covering the node's own id: when the frontier reaches the + /// node's own slot (its key), the term is satisfied if the second + /// frontier already passed `prefix`, else it re-parks on the second + /// frontier. + ExceptSelf { node: usize, prefix: usize }, +} + +/// The first unemitted slot position at or after `from` (== `slots.len()` when +/// exhausted). Frontier scans only ever move forward, so the total scan work +/// per lane is linear. +fn next_unemitted(slots: &[usize], emitted: &[bool], from: usize) -> usize { + let mut at = from.min(slots.len()); + while at < slots.len() && emitted[slots[at]] { + at += 1; + } + at +} + +/// The pre-F1 O(n²) implementation, retained verbatim as the property-test +/// oracle for [`canonical_reduction_order`]: it materializes every covered +/// `(predecessor, successor)` pair and re-scans the whole set per emission, +/// which *is* the order's pairwise definition, executed literally. +#[cfg(test)] +pub(crate) fn canonical_reduction_order_reference<'a>( + envelopes: &[&'a OperationEnvelope], ) -> Vec<&'a OperationEnvelope> { let len = envelopes.len(); let mut indegree = vec![0usize; len]; @@ -4839,6 +5130,346 @@ mod tests { } } + // --- Subquadratic canonical order vs. the retained O(n²) oracle. -------- + + /// A minimal envelope for pure ordering tests: payload content never + /// affects the canonical reduction order. + fn order_env( + replica: ReplicaId, + counter: u64, + physical: i64, + logical: u32, + ctx: CausalContext, + ) -> OperationEnvelope { + let id = OperationId::new(replica, counter); + OperationEnvelope { + id, + author: AuthorId(1), + stamp: OperationStamp::new( + HybridLogicalClock::new(WallClockTime(physical), logical), + id, + ), + causal_context: ctx, + transaction: None, + payload: OperationPayload::Primitive(OperationKind::DeleteEvent(DeleteEventOp { + event: EventId::new(ReplicaId(7), counter % 5), + tuplet_compensation: TupletCompensation::NotInTuplet, + })), + } + } + + /// Asserts the subquadratic order equals the reference oracle's + /// element-for-element — by slice element identity (pointer equality), the + /// strictest possible check: it distinguishes even byte-identical + /// duplicate envelopes, whose tuple ties both implementations must break + /// by slice position. + fn assert_order_matches_reference(envelopes: &[OperationEnvelope]) { + let refs: Vec<&OperationEnvelope> = envelopes.iter().collect(); + let fast = canonical_reduction_order(&refs); + let oracle = canonical_reduction_order_reference(&refs); + assert_eq!(fast.len(), oracle.len()); + for (at, (a, b)) in fast.iter().zip(&oracle).enumerate() { + assert!( + std::ptr::eq(*a, *b), + "canonical order diverges from the reference at position {at}: \ + {:?} vs {:?} (n = {})", + a.id, + b.id, + envelopes.len() + ); + } + } + + /// In-place Fisher–Yates driven by the seeded generator (slice order is an + /// input to the tuple tie-break, so permutations must be exercised too). + fn shuffle_envelopes( + envelopes: &mut [OperationEnvelope], + rng: &mut epiphany_determinism::fuzz::SplitMix64, + ) { + for i in (1..envelopes.len()).rev() { + let j = (rng.next_u64() % (i as u64 + 1)) as usize; + envelopes.swap(i, j); + } + } + + /// A hostile ordering input the crate's well-formed generators avoid: + /// floors that cover the envelope's own id or absent counters, dots to + /// present / absent / own ids, duplicate ids (byte-identical twins), + /// `SYSTEM_DERIVED` replicas, colliding stamps that contradict the causal + /// edges (so the topological pass and the cycle-breaker both engage), and + /// empty contexts. + fn adversarial_set( + rng: &mut epiphany_determinism::fuzz::SplitMix64, + n: usize, + ) -> Vec { + let replicas = 1 + rng.next_u64() % 4; + let mut next_counter: BTreeMap = BTreeMap::new(); + let mut envs: Vec = Vec::with_capacity(n); + for _ in 0..n { + if !envs.is_empty() && rng.next_u64() % 8 == 0 { + // A duplicate id — and a byte-identical stamp, so the + // reduction tuple genuinely ties. + let victim = envs[(rng.next_u64() % envs.len() as u64) as usize].clone(); + envs.push(victim); + continue; + } + let replica = if rng.next_u64() % 16 == 0 { + ReplicaId::SYSTEM_DERIVED + } else { + ReplicaId(1 + rng.next_u64() % replicas) + }; + let slot = next_counter.entry(replica).or_insert(0); + // Occasionally skip counters so floors assert absent predecessors. + let counter = *slot + rng.next_u64() % 2; + *slot = counter + 1; + let id = OperationId::new(replica, counter); + + let mut ctx = CausalContext::new(); + for _ in 0..rng.next_u64() % 3 { + let target = match rng.next_u64() % 5 { + 0 => replica, // may cover the envelope's own id + 1 => ReplicaId(9), // absent replica + 2 => ReplicaId::SYSTEM_DERIVED, + _ => ReplicaId(1 + rng.next_u64() % replicas), + }; + // May exceed every present counter (covering future authoring + // of that replica — a causal cycle) or fall below all of them. + ctx = ctx.with_seen(target, rng.next_u64() % 8); + } + for _ in 0..rng.next_u64() % 3 { + let dot = if !envs.is_empty() && rng.next_u64() % 2 == 0 { + envs[(rng.next_u64() % envs.len() as u64) as usize].id + } else if rng.next_u64() % 4 == 0 { + id // the envelope's own id + } else { + OperationId::new(ReplicaId(1 + rng.next_u64() % 5), rng.next_u64() % 10) + }; + ctx = ctx.with_dot(dot); + } + + // Tiny stamp ranges force heavy tuple collisions and stamps that + // contradict the causal edges. + envs.push(order_env( + replica, + counter, + (rng.next_u64() % 6) as i64, + (rng.next_u64() % 3) as u32, + ctx, + )); + } + envs + } + + #[test] + fn canonical_order_matches_reference_on_fuzz_sets() { + // The crate's own well-formed generator: multi-replica meshes of + // vector floors, occasional equivocation twins (duplicate ids) and + // HLC-monotonicity anomalies, empty contexts on counter-0 roots. + let mut rng = epiphany_determinism::fuzz::SplitMix64::new(0xF1_0DE2_0001); + for _ in 0..250 { + let n = 1 + (rng.next_u64() % 40) as usize; + let mut envs = crate::fuzz::gen_envelope_set(&mut rng, n); + assert_order_matches_reference(&envs); + shuffle_envelopes(&mut envs, &mut rng); + assert_order_matches_reference(&envs); + } + } + + #[test] + fn canonical_order_matches_reference_on_adversarial_sets() { + let mut rng = epiphany_determinism::fuzz::SplitMix64::new(0xADE5_A71A_0002); + assert_order_matches_reference(&[]); + for iteration in 0..400 { + let n = 1 + (rng.next_u64() % 60) as usize; + let mut envs = adversarial_set(&mut rng, n); + assert_order_matches_reference(&envs); + if iteration % 4 == 0 { + shuffle_envelopes(&mut envs, &mut rng); + assert_order_matches_reference(&envs); + } + } + } + + #[test] + fn canonical_order_matches_reference_on_directed_shapes() { + let r = ReplicaId(1); + + // A 2,000-envelope single-replica chain whose every DVV floor covers + // the full replica prefix — the inherently-quadratic-pairs shape the + // subquadratic construction exists for — with *descending* stamps, so + // the causal edges (not the HLC) decide every single emission. + let full_chain: Vec = (0..2_000) + .map(|c| { + let ctx = if c == 0 { + CausalContext::new() + } else { + CausalContext::new().with_seen(r, c - 1) + }; + order_env(r, c, 2_000 - c as i64, 0, ctx) + }) + .collect(); + assert_order_matches_reference(&full_chain); + + // A self-covering chain: every floor also covers the envelope's own + // id (the exempted self-pair). + let self_chain: Vec = (0..600) + .map(|c| { + order_env( + r, + c, + 600 - c as i64, + 0, + CausalContext::new().with_seen(r, c), + ) + }) + .collect(); + assert_order_matches_reference(&self_chain); + + // A dot-only chain (no vector floors at all). + let dot_chain: Vec = (0..600) + .map(|c| { + let ctx = if c == 0 { + CausalContext::new() + } else { + CausalContext::new().with_dot(OperationId::new(r, c - 1)) + }; + order_env(r, c, 600 - c as i64, 0, ctx) + }) + .collect(); + assert_order_matches_reference(&dot_chain); + + // Malformed dot cycles (2-cycle and 3-cycle) among bystanders with + // empty contexts and identical stamps. + let id = |rep: u64, c: u64| OperationId::new(ReplicaId(rep), c); + let cycles = vec![ + order_env( + ReplicaId(2), + 0, + 5, + 0, + CausalContext::new().with_dot(id(2, 1)), + ), + order_env( + ReplicaId(2), + 1, + 5, + 0, + CausalContext::new().with_dot(id(2, 0)), + ), + order_env( + ReplicaId(3), + 0, + 5, + 0, + CausalContext::new().with_dot(id(3, 2)), + ), + order_env( + ReplicaId(3), + 1, + 5, + 0, + CausalContext::new().with_dot(id(3, 0)), + ), + order_env( + ReplicaId(3), + 2, + 5, + 0, + CausalContext::new().with_dot(id(3, 1)), + ), + order_env(ReplicaId(4), 0, 5, 0, CausalContext::new()), + order_env(ReplicaId(5), 0, 5, 0, CausalContext::new()), + ]; + assert_order_matches_reference(&cycles); + + // Mutual full-coverage floors (a floor cycle where each envelope also + // covers itself), plus coverage of absent ids on an absent replica. + let floor_cycle = vec![ + order_env( + ReplicaId(6), + 0, + 9, + 0, + CausalContext::new().with_seen(ReplicaId(6), 1), + ), + order_env( + ReplicaId(6), + 1, + 8, + 0, + CausalContext::new().with_seen(ReplicaId(6), 1), + ), + order_env( + ReplicaId(6), + 2, + 7, + 0, + CausalContext::new() + .with_seen(ReplicaId(40), 12) + .with_dot(id(41, 3)), + ), + ]; + assert_order_matches_reference(&floor_cycle); + + // Byte-identical duplicate ids (tuple ties broken by slice position) + // in several slice orders, including a dot and a floor onto the + // duplicated id. + let twin = order_env(ReplicaId(2), 3, 1, 0, CausalContext::new()); + let mut twins = vec![ + twin.clone(), + twin.clone(), + order_env( + ReplicaId(2), + 4, + 0, + 0, + CausalContext::new().with_dot(id(2, 3)), + ), + order_env( + ReplicaId(3), + 0, + 0, + 0, + CausalContext::new().with_seen(ReplicaId(2), 3), + ), + // A twin that dots its own id: covers only its duplicate. + order_env( + ReplicaId(2), + 3, + 1, + 0, + CausalContext::new().with_dot(id(2, 3)), + ), + ]; + assert_order_matches_reference(&twins); + twins.reverse(); + assert_order_matches_reference(&twins); + twins.swap(0, 2); + assert_order_matches_reference(&twins); + + // SYSTEM_DERIVED authoring under floors and dots from user replicas. + let sys = ReplicaId::SYSTEM_DERIVED; + let system = vec![ + order_env(sys, 0, 3, 0, CausalContext::new()), + order_env(sys, 1, 2, 0, CausalContext::new().with_seen(sys, 0)), + order_env( + ReplicaId(2), + 0, + 1, + 0, + CausalContext::new().with_seen(sys, 1), + ), + order_env( + ReplicaId(2), + 1, + 0, + 0, + CausalContext::new().with_dot(id(u64::MAX, 0)), + ), + ]; + assert_order_matches_reference(&system); + } + #[test] fn reduction_is_permutation_invariant() { let envs = vec![ diff --git a/crates/epiphany-ops/src/valuegen.rs b/crates/epiphany-ops/src/valuegen.rs index 5ca35cc..5a4bb9a 100644 --- a/crates/epiphany-ops/src/valuegen.rs +++ b/crates/epiphany-ops/src/valuegen.rs @@ -269,7 +269,7 @@ pub fn region(id: RegionId) -> Region { } /// Score metadata with a `nth`-distinct title (M2d) — distinct `nth` give -/// distinct [`ScoreMetadata`] values so a harness can drive concurrent +/// distinct `ScoreMetadata` values so a harness can drive concurrent /// `SetMetadata`s, an advisory LWW field that resolves by canonical order with /// no conflict. pub fn score_metadata(nth: u8) -> epiphany_core::ScoreMetadata { diff --git a/crates/epiphany-render-svg/src/lib.rs b/crates/epiphany-render-svg/src/lib.rs index c9127c5..9374d26 100644 --- a/crates/epiphany-render-svg/src/lib.rs +++ b/crates/epiphany-render-svg/src/lib.rs @@ -3,7 +3,7 @@ //! //! Agent I's **SVG renderer** behind the Epiphany `RenderIR` interface (spec //! **Chapter 7** §"RenderIR"): it turns a -//! [`ResolvedLayoutIR`](epiphany_layout_ir::ResolvedLayoutIR) into well-formed +//! [`ResolvedLayoutIR`] into well-formed //! **SVG 1.1**, drawing each glyph from **genuine Bravura SMuFL** data: inline //! outline ``s by default, or `` set in an `@font-face`-embedded //! subset. It is the visible end of the v0 `Score → layout IR` pipeline: from a @@ -15,7 +15,7 @@ //! the renderer was golden-locked against the **stub solver's** output first, then //! against the real [`epiphany_engrave`](../epiphany_engrave/index.html) solver //! once real notation and re-spacing landed. The renderer consumes any solver's -//! [`ResolvedLayoutIR`](epiphany_layout_ir::ResolvedLayoutIR): it preserves the +//! [`ResolvedLayoutIR`]: it preserves the //! resolved geometry, provenance traces, XML validity, deterministic output, and //! glyph-mode choice without making engraving-semantic decisions. //! @@ -24,8 +24,9 @@ //! The bundled outlines are extracted from the official OFL `Bravura.otf` (see //! `tools/extract_bravura_outlines.py` and `tools/OFL.txt`) in staff-space, //! y-up coordinates. The renderer makes SVG-encoding choices only and never -//! engraving-semantic ones; see [`svg`] for the coordinate system, the -//! provenance-tracing contract, and the diagnostic-not-paper-over rule. +//! engraving-semantic ones; see the private `svg` module for the coordinate +//! system, the provenance-tracing contract, and the diagnostic-not-paper-over +//! rule. //! //! ## Font availability //! diff --git a/crates/epiphany-testkit/Cargo.toml b/crates/epiphany-testkit/Cargo.toml index 79c1f70..51d0243 100644 --- a/crates/epiphany-testkit/Cargo.toml +++ b/crates/epiphany-testkit/Cargo.toml @@ -16,7 +16,25 @@ epiphany-ops.workspace = true # now drives the real crate instead of an in-tree stub. epiphany-layout-ir.workspace = true +# The Chapter 10 performance benches (worklist F1) are the only dev-dependency +# user: the budget-gate logic itself lives in `src/budget.rs` on plain `std`, +# so the library builds without criterion. +[dev-dependencies] +criterion.workspace = true + # Drives the whole suite at scale outside the unit-test timeout — the analogue # of epiphany-determinism's `fuzz_roundtrip` and epiphany-bundle's `fuzz_crash`. [[example]] name = "conformance_suite" + +# The Chapter 10 performance-budget benches (worklist F1; DECISIONS.md F0/F1). +# `harness = false`: each bench owns `main()`, running criterion's measurements +# first and then the budget gate — the assertion layer criterion cannot express +# — exiting nonzero on an unexpected budget miss. +[[bench]] +name = "reduction" +harness = false + +[[bench]] +name = "bundle" +harness = false diff --git a/crates/epiphany-testkit/DECISIONS.md b/crates/epiphany-testkit/DECISIONS.md index 0210eec..3b2b4cc 100644 --- a/crates/epiphany-testkit/DECISIONS.md +++ b/crates/epiphany-testkit/DECISIONS.md @@ -48,7 +48,7 @@ Concretely: `[prepass-harness]` stage in the conformance suite. - **`benches/` lives in this crate** (not per-crate). The Chapter-10 budgets are - workspace-level, and the marquee bench (the reducer's `O(n²)` + workspace-level, and the marquee bench (the reducer's — at the time `O(n²)` — `canonical_reduction_order` at 10K+ envelopes, worklist F1) drives `epiphany-ops` *through* the testkit's envelope generators — exactly what this crate already does. A bench that lived in `epiphany-ops` could not reuse the @@ -70,6 +70,96 @@ mirrors how v0's `convergence`/`roundtrip` modules are shared between **Unblocks:** F1 (benches), F3 (corpus + taxonomy harness — done), F4 (per-agent harness skeletons — H done), F5 (integration skeleton). +## F1 — The Chapter 10 budget benches (`benches/reduction.rs`, `benches/bundle.rs`) + +*Worklist item F1: a criterion bench asserting Chapter-10 budgets at documented +scale points, known-pending points marked xfail with the numeric budget written +in the bench. Home per F0: this crate's `benches/`.* + +**Criterion version: `0.5` (locks to 0.5.1), default features off plus +`cargo_bench_support`.** The 0.5 line's MSRV (1.70) fits the workspace's pinned +`rust-version = "1.77"`; criterion 0.6+ requires 1.80. Disabling default +features drops the plotting stack (`plotters`) and `rayon` — dead weight for +budget gates — while `cargo_bench_support` keeps plain `cargo bench` as the +entry point. Two transitive pins in `Cargo.lock` keep the tree MSRV-clean, +because the resolver (v2) is not MSRV-aware: `clap 4.5.53` (MSRV 1.74; 4.6 +requires 1.85) and `half 2.4.1` (MSRV 1.70; 2.5+ requires 1.81). Re-check those +two if `cargo update` touches the criterion tree. + +**The gate mechanism.** Criterion measures but never asserts, so each bench is +`harness = false` and its `main()` runs criterion's measurements first, then +the budget gate in [`crate::budget`] — a library module (the F0 pattern: shared +logic lives in `src/`, and it deliberately uses no criterion types, so the +library itself takes no new dependency). Every budget row carries an +`Expectation` written in the bench source next to its numeric threshold: + +- `Pass` — must hold today; a miss exits nonzero (the CI tripwire). +- `Xfail(reason)` — documented known-pending miss; the reason names the defect + and owner. A miss prints an expected-failure line; a **pass** prints an XPASS + promotion notice, so a stale marking is loud in both directions. + +Skipped rows (the 50K point in quick mode) print an explicit `skip` line, never +silence. Under `cargo test --benches` (criterion test mode, detected by the +absence of the `--bench` flag `cargo bench` passes) the measurements run once +and the gate is skipped — the gate belongs to `cargo bench`. + +**Sampling calibration (a documented deviation from Chapter 10).** The +conformance methodology — p99 over ≥1000 iterations on the reference hardware +profile — is the reference suite's job, not this gate's: 1000 iterations of the +(pre-fix ~29 s) 50K cold reduction was not a CI shape. The gate takes the +**median of a small per-row iteration count** (reduction: 9/3/1 iterations at +1K/10K/50K; bundle: 40 commit / 25 read; cut to 5/2/skip and 12/8 under +`EPIPHANY_BENCH_QUICK=1`), +cold (no in-gate warm-up — the marquee budget is an explicitly *cold* rate). +Criterion uses flat sampling with `sample_size(10)` for the reduction group; +the 50K point is gate-only (calibrated when a single iteration took ~29 s and +criterion's ≥10-sample loop would have blown the wall-clock budget; ~0.58 s +post-fix). Full `cargo bench -p epiphany-testkit` stays under ~2 minutes of +measurement; quick mode under ~15 seconds. + +**Measured on the dev profile (2026-07, post-K-fix), the table's ground +truth:** + +| row | budget | measured | verdict | +|-----|--------|----------|---------| +| `reduction/1000` | > 10,000 env/s cold | ~674,000 env/s (~1.5 ms) | Pass | +| `reduction/10000` | > 10,000 env/s cold | ~257,000 env/s (~39 ms) | Pass | +| `reduction/50000` | > 10,000 env/s cold | ~87,000 env/s (~0.58 s) | Pass (promoted from Xfail) | +| `bundle/typical_edit_commit` | ≤ 50 ms | ~14.7 ms (real fsync) | Pass | +| `bundle/open_bootstrap_read` | ≤ 200 ms | ~63 µs (moderate corpus) | Pass | + +As F1 first measured it (2026-07, pre-fix), the O(n²) +`canonical_reduction_order` indegree construction was unambiguous in the curve +(~155K / ~12.5K / ~1.7K env/s at 1K/10K/50K — 10x envelopes cost ~120x time), +sinking the 50K row (~29 s per cold reduce, the documented xfail) and leaving +10K only ~25% over budget. Agent K's subquadratic rewrite +(threshold/frontier readiness, byte-identical order — see +`epiphany-ops/DECISIONS.md`) triggered the gate's XPASS promotion notice, and +the 50K row was flipped to Pass in the same change (**F surfaces, K fixes**, +round-tripped). Any future red row is a fresh regression: fix the reducer, do +not re-mark rows xfail without a written decision here. + +**Two honesty notes on the bundle rows.** (1) They run on the build target's +filesystem, *not* `std::env::temp_dir()`: `/tmp` is commonly tmpfs, where fsync +is a near-no-op — measured, the commit row is ~54 µs on tmpfs vs ~14.7 ms on a +real NVMe filesystem, a 270x difference that would have made the 50 ms budget +vacuous. (2) The read budget is spec'd against "a 100-page orchestral score"; +no such corpus generator exists yet, so the row is a moderate-corpus (1K +envelopes + canonical-base snapshot) stand-in with margin to spare, and says so +in its docs. + +**Scope, and the budget rows deliberately not built yet.** F1 covers the three +budgets that are measurable against shipped subsystems: the reduction rate and +the two file-format budgets. The remaining Chapter 10 rows are blocked on +unimplemented or in-flight subsystems and become future benches in this same +`benches/` + gate shape: the interactive keystroke→frame budgets (blocked on +Agent I's engrave/render pipeline maturing past the visible slice), cold +solving of a 100-page score within 2 s p99 and the incremental-propagation +bound (blocked on the real Chapter 9 solver and a 100-page corpus generator — +the latter also unblocks the honest read-row corpus), and the memory ceilings +(blocked on the same corpus). CI runs the gates in the `conformance` job with +`EPIPHANY_BENCH_QUICK=1` (50K skipped) and in the nightly `soak` job in full. + ## F3 — The representative score corpus + eligibility-taxonomy harness (Agent H) *Worklist item F3 — "the most underbuilt dependency; unblocks H entirely."* diff --git a/crates/epiphany-testkit/README.md b/crates/epiphany-testkit/README.md index 02e67a0..f469731 100644 --- a/crates/epiphany-testkit/README.md +++ b/crates/epiphany-testkit/README.md @@ -147,6 +147,40 @@ Per the QUICKSTART, implementation-discovered gaps are batched, not improvised: remaining layout-specific Pass 11 candidates (the `OperationKindTag` variant set and the layout-object id derivation). +## Performance benches (Chapter 10 budgets, worklist F1) + +`benches/` holds the criterion benches for the spec's measurable Chapter 10 +budgets (see `DECISIONS.md` F0 for why they live in this crate, F1 for every +call made). Criterion measures; the **budget gate** (`src/budget.rs`) asserts: +each bench's `main()` ends by re-timing every budget row and exiting nonzero if +a `Pass`-marked row misses its threshold. Known-pending rows are marked +`Xfail(reason)` *in the bench source* next to the numeric budget — a miss is +reported and tolerated, and a pass prints a loud promotion notice so stale +markings cannot linger. This is the "F surfaces, K fixes" handshake, and its +inaugural round has completed: the bench documented the reducer's O(n²) +`canonical_reduction_order` failure at scale, and Agent K's subquadratic +rewrite (see `epiphany-ops/DECISIONS.md`) flipped the xfail row to `Pass`. + +| row | budget (spec Chapter 10) | expectation | +|-----|--------------------------|-------------| +| `reduction/1000` | > 10,000 envelopes/s, cold | Pass (~674K env/s measured) | +| `reduction/10000` | > 10,000 envelopes/s, cold | Pass (~257K env/s measured) | +| `reduction/50000` | > 10,000 envelopes/s, cold | Pass (~87K env/s measured; promoted from Xfail by Agent K's reducer fix — was ~1.7K env/s) | +| `bundle/typical_edit_commit` | ≤ 50 ms (append + manifest + superblock flip, fsync'd) | Pass (~15 ms) | +| `bundle/open_bootstrap_read` | ≤ 200 ms (manifest + bootstrap chunks) | Pass (moderate-corpus stand-in) | + +```sh +# Full run (includes the 50K cold-reduction point, ~0.6 s per iteration): +cargo bench -p epiphany-testkit + +# The reduced CI shape: smaller sampling, 50K point skipped (PR CI runs this): +EPIPHANY_BENCH_QUICK=1 cargo bench -p epiphany-testkit +``` + +The gate is a calibrated median over a few iterations, deliberately not the +spec's p99-over-1000-iterations conformance methodology (that is the reference +suite's job; the deviation is documented in `src/budget.rs`). + ## Running ```sh diff --git a/crates/epiphany-testkit/benches/bundle.rs b/crates/epiphany-testkit/benches/bundle.rs new file mode 100644 index 0000000..80266b3 --- /dev/null +++ b/crates/epiphany-testkit/benches/bundle.rs @@ -0,0 +1,284 @@ +//! The Chapter 10 file-format budgets: typical-edit bundle write and +//! manifest+bootstrap read (Phase 2 worklist F1). +//! +//! The normative budgets (`spec/core_spec.tex`, Chapter 10 §"File Format +//! Performance"): +//! +//! > Bundle write of a typical edit (one or more operation envelopes appended +//! > to the operation-envelope block stream, manifest rewrite, superblock flip) +//! > completes within 50 ms at p99 on the reference hardware profile. +//! > +//! > Bundle read of the manifest and bootstrap chunks (sufficient for first +//! > interactive frame) completes within 200 ms at p99 for a 100-page +//! > orchestral score. +//! +//! Both rows run against a real on-disk bundle (`FileStore`, whose flush is a +//! genuine `fsync`) in a scratch directory under the build's **target dir** — +//! deliberately not `std::env::temp_dir()`, which is commonly tmpfs on Linux, +//! where fsync is a near-no-op and the commit budget would be measured against +//! RAM. The corpus is moderate: 1,000 generated operation envelopes packed +//! into operation blocks plus a canonical `MaterializedState` snapshot wired +//! as the manifest's `canonical_base`. Both +//! are expected to **Pass** today, so a regression fails `cargo bench` loudly. +//! The read row's honesty note: the spec sizes its 200 ms against a 100-page +//! orchestral score; no such corpus generator exists yet, so this row is the +//! moderate-corpus stand-in (recorded in `DECISIONS.md` F1) and the budget is +//! asserted with margin to spare. The OS page cache is warm across iterations +//! (dropping it needs privileges); each iteration's *process-level* state is +//! fresh. +//! +//! The timed sections: +//! +//! * **typical_edit_commit** — on an opened bundle restored to the same base +//! image (restore + open are un-timed setup): one `commit` staging a small +//! envelope block, i.e. block append + manifest rewrite + superblock flip, +//! every write fsync'd. This mirrors `bundle_harness`'s commit driver. +//! * **open_bootstrap_read** — `FileStore::open` + `Bundle::open` (superblock +//! selection + header + manifest decode) + reading the `canonical_base` +//! snapshot and every operation block — the bytes a first interactive frame +//! needs. +//! +//! Criterion measures; the budget gate in `main` asserts (see +//! `epiphany_testkit::budget` for the Pass/Xfail semantics and the documented +//! deviation from Chapter 10's p99-over-1000-iterations conformance +//! methodology). Run: `cargo bench -p epiphany-testkit --bench bundle`; +//! `EPIPHANY_BENCH_QUICK=1` shrinks sampling for PR CI. + +use std::fs; +use std::path::{Path, PathBuf}; +use std::time::Duration; + +use criterion::{BatchSize, Criterion}; +use epiphany_bundle::{ + pack_operation_blocks, Bundle, ChunkKind, CommitContext, DocumentId, FileStore, FileUuid, + FrontierBytes, Manifest, MemStore, ProfileId, ReductionAlgorithmVersion, SchemaVersion, + SnapshotId, SnapshotRef, StagedChunk, +}; +use epiphany_determinism::CanonicalEncode; +use epiphany_ops::{OperationEnvelope, OperationSet}; +use epiphany_testkit::budget::{self, Expectation}; +use epiphany_testkit::{generators, Rng}; + +/// Chapter 10: a typical-edit bundle write completes within 50 ms (p99). +const COMMIT_BUDGET: Duration = Duration::from_millis(50); +/// Chapter 10: manifest + bootstrap read completes within 200 ms (p99). +const READ_BUDGET: Duration = Duration::from_millis(200); + +/// Base-corpus scale: the criterion-5 envelope count, packed into real blocks. +const BASE_ENVELOPES: usize = 1_000; +/// The typical edit: a handful of envelopes appended as one block. +const EDIT_ENVELOPES: usize = 4; + +/// Everything the two rows measure against, built once from a fixed seed. +struct Fixture { + /// The committed base image (blocks + canonical-base snapshot). + base_image: Vec, + /// The typical edit, staged (one small operation block). + edit: Vec, + /// Temp-dir file paths: one per row so commit growth never skews reads. + commit_path: PathBuf, + read_path: PathBuf, +} + +/// The commit-context closure the harness uses: append the new chunks to the +/// previous manifest's `operation_roots`. +fn append_roots(ctx: &CommitContext) -> Manifest { + let mut manifest = ctx.previous_manifest.clone(); + manifest + .operation_roots + .extend(ctx.new_chunks.iter().copied()); + manifest +} + +fn staged_blocks(envelopes: &[OperationEnvelope]) -> Vec { + let payloads: Vec> = envelopes.iter().map(|e| e.to_canonical_bytes()).collect(); + pack_operation_blocks(&payloads) + .into_iter() + .map(StagedChunk::operation_block) + .collect() +} + +/// Builds the moderate base corpus: 1,000 envelopes committed as operation +/// blocks, then their cold reduction committed as a `Snapshot` chunk wired to +/// the manifest's `canonical_base` (the roundtrip harness's snapshot shape). +fn build_fixture(dir: &Path) -> Fixture { + let mut rng = Rng::new(0x00F1_B0DE_0001); + let envelopes = generators::operation_envelopes(&mut rng, BASE_ENVELOPES, 3, 40, 40); + let edit_envelopes = generators::operation_envelopes(&mut rng, EDIT_ENVELOPES, 3, 8, 8); + + let uuid = FileUuid(rng.array16()); + let doc = DocumentId(rng.array16()); + let mut bundle = + Bundle::create(MemStore::new(), uuid, Manifest::empty(doc)).expect("create base bundle"); + bundle + .commit(&staged_blocks(&envelopes), append_roots) + .expect("commit base operation blocks"); + + // The canonical base: the corpus's cold reduction, stored as a snapshot. + let mut set = OperationSet::new(); + set.accept_all(envelopes.iter().cloned()); + let canonical = set.reduce().canonical_bytes(); + let snapshot = StagedChunk { + kind: ChunkKind::Snapshot, + schema_version: SchemaVersion::V0, + payload: canonical, + }; + let frontier = generators::frontier_bytes(&envelopes); + bundle + .commit(&[snapshot], |ctx| { + let mut manifest = ctx.previous_manifest.clone(); + let root = ctx.new_chunks[0]; + let mut sid = [0u8; 16]; + sid.copy_from_slice(&root.hash.as_bytes()[..16]); + manifest.canonical_base = Some(SnapshotRef { + snapshot_id: SnapshotId(sid), + covers_causal_frontier: FrontierBytes::from_bytes(frontier.clone()), + reduction_algorithm_version: ReductionAlgorithmVersion(0), + profile_id: ProfileId::Full, + hash: root.hash, + root, + }); + manifest + }) + .expect("commit canonical-base snapshot"); + + Fixture { + base_image: bundle.into_store().into_bytes(), + edit: staged_blocks(&edit_envelopes), + commit_path: dir.join("commit.epb"), + read_path: dir.join("read.epb"), + } +} + +/// Un-timed setup for the commit row: restore the base image and open it. +fn restore_and_open(path: &Path, image: &[u8]) -> Bundle { + fs::write(path, image).expect("restore base image"); + Bundle::open(FileStore::open(path).expect("open store")).expect("open bundle") +} + +/// The timed commit: block append + manifest rewrite + superblock flip, fsync'd. +fn typical_edit_commit(mut bundle: Bundle, edit: &[StagedChunk]) -> u64 { + bundle + .commit(edit, append_roots) + .expect("typical-edit commit"); + bundle.generation() +} + +/// The timed read: open (superblock selection + manifest decode) + the +/// bootstrap chunks — canonical-base snapshot and every operation block. +fn open_bootstrap_read(path: &Path) -> usize { + let bundle = Bundle::open(FileStore::open(path).expect("open store")).expect("open bundle"); + let manifest = bundle.manifest(); + let mut bytes = 0usize; + let base = manifest + .canonical_base + .as_ref() + .expect("the fixture wires a canonical base"); + bytes += bundle + .read_chunk(&base.root) + .expect("snapshot chunk reads") + .len(); + for root in &manifest.operation_roots { + for envelope in bundle + .read_operation_block(root) + .expect("operation block reads") + { + bytes += envelope.len(); + } + } + bytes +} + +/// The criterion measurement side. +fn criterion_measurements(criterion: &mut Criterion, fixture: &Fixture, quick: bool) { + let mut group = criterion.benchmark_group("bundle"); + group.sample_size(if quick { 10 } else { 30 }); + group.measurement_time(Duration::from_secs(if quick { 1 } else { 4 })); + group.warm_up_time(Duration::from_millis(if quick { 300 } else { 1000 })); + + group.bench_function("typical_edit_commit", |b| { + b.iter_batched( + || restore_and_open(&fixture.commit_path, &fixture.base_image), + |bundle| typical_edit_commit(bundle, &fixture.edit), + BatchSize::PerIteration, + ) + }); + + fs::write(&fixture.read_path, &fixture.base_image).expect("write read-row image"); + group.bench_function("open_bootstrap_read", |b| { + b.iter(|| open_bootstrap_read(&fixture.read_path)) + }); + + group.finish(); +} + +/// The budget-gate side: both rows are expected to **Pass** today. +fn budget_gate(fixture: &Fixture, quick: bool) -> Vec { + let commit_median = budget::median_time( + if quick { 12 } else { 40 }, + || restore_and_open(&fixture.commit_path, &fixture.base_image), + |bundle| typical_edit_commit(bundle, &fixture.edit), + ); + fs::write(&fixture.read_path, &fixture.base_image).expect("write read-row image"); + let read_median = budget::median_time( + if quick { 8 } else { 25 }, + || (), + |()| open_bootstrap_read(&fixture.read_path), + ); + vec![ + budget::latency_gate( + "bundle/typical_edit_commit", + commit_median, + COMMIT_BUDGET, + Expectation::Pass, + ), + budget::latency_gate( + "bundle/open_bootstrap_read", + read_median, + READ_BUDGET, + Expectation::Pass, + ), + ] +} + +/// A scratch directory on the **build target's filesystem** (real disk), not +/// `temp_dir()`: `/tmp` is commonly tmpfs, where the commit row's fsyncs would +/// be free and the 50 ms budget vacuous. Honors `CARGO_TARGET_DIR`. +fn scratch_dir() -> PathBuf { + let target = std::env::var_os("CARGO_TARGET_DIR") + .map(PathBuf::from) + .unwrap_or_else(|| { + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("..") + .join("..") + .join("target") + }); + target.join(format!("f1-bundle-bench-{}", std::process::id())) +} + +fn main() { + // `cargo bench` passes `--bench`; its absence means criterion's test mode + // (`cargo test --benches` / `--all-targets`): run each measurement once, + // skip the gate. + let bench_mode = std::env::args().any(|arg| arg == "--bench"); + let quick = budget::quick_mode(); + + let dir = scratch_dir(); + fs::create_dir_all(&dir).expect("create bench scratch dir"); + let fixture = build_fixture(&dir); + + let mut criterion = Criterion::default().configure_from_args(); + criterion_measurements(&mut criterion, &fixture, quick); + criterion.final_summary(); + + let holds = if bench_mode { + budget::verdict(&budget_gate(&fixture, quick)) + } else { + true + }; + + let _ = fs::remove_dir_all(&dir); + if !holds { + std::process::exit(1); + } +} diff --git a/crates/epiphany-testkit/benches/reduction.rs b/crates/epiphany-testkit/benches/reduction.rs new file mode 100644 index 0000000..749a554 --- /dev/null +++ b/crates/epiphany-testkit/benches/reduction.rs @@ -0,0 +1,195 @@ +//! The Chapter 10 operation-envelope reduction-rate bench + budget gate +//! (Phase 2 worklist F1). +//! +//! The normative budget (`spec/core_spec.tex`, Chapter 10 §"File Format +//! Performance"): +//! +//! > Operation-envelope reduction rate MUST exceed 10,000 envelopes per second +//! > on the reference hardware profile, measured during cold reduction from a +//! > fresh canonical base. +//! +//! Three documented scale points: **1K** (the acceptance suite's criterion-5 +//! scale), **10K**, and **50K** envelopes. The timed section is the cold +//! reduction an opener performs — `OperationSet::new()` + `accept_all` + +//! `reduce()` on a fresh set — with the envelope vector generated once per +//! scale point from a fixed seed and *cloned outside* the timed section. +//! +//! Criterion measures (throughput in envelopes/s); the budget gate in `main` +//! asserts, with the budget table below (`epiphany_testkit::budget` explains +//! the Pass/Xfail semantics and the deliberate deviation from Chapter 10's +//! p99-over-1000-iterations conformance methodology). The defect this bench +//! was written to surface — `canonical_reduction_order`'s literal O(n²) +//! double-loop indegree construction plus its per-emission full ready-scan +//! (`crates/epiphany-ops/src/reduce.rs`) — sank the 50K point decisively +//! (~1.7K env/s ≈ 29 s per cold reduce on the dev profile) and left the 10K +//! point clearing the budget with only ~25% margin. Agent K's subquadratic +//! rewrite (threshold/frontier readiness; see the epiphany-ops DECISIONS +//! entry) closed the loop — **F surfaces, K fixes** +//! (`spec/PHASE2_F_WEEK0_WORKLIST.md` F1) — and the gate's XPASS notice +//! promoted the 50K row to `Pass` (~87K env/s measured, ~8.7x budget). +//! +//! Run: `cargo bench -p epiphany-testkit --bench reduction`. Set +//! `EPIPHANY_BENCH_QUICK=1` for the reduced PR-CI shape (smaller sampling, 50K +//! point skipped). Under `cargo test --benches` criterion runs each measurement +//! once in test mode and the gate is skipped — the gate belongs to `cargo +//! bench`. + +use std::time::Duration; + +use criterion::{BatchSize, BenchmarkId, Criterion, SamplingMode, Throughput}; +use epiphany_ops::{MaterializedState, OperationEnvelope, OperationSet}; +use epiphany_testkit::budget::{self, Expectation}; +use epiphany_testkit::{generators, Rng}; + +/// Chapter 10: the reduction rate MUST exceed 10,000 envelopes per second. +const RATE_BUDGET_ENV_PER_SEC: f64 = 10_000.0; + +/// One documented scale point of THE BUDGET TABLE below. +struct ScalePoint { + /// Envelope count (also the criterion throughput element count). + n_ops: usize, + /// Fixed generator seed — bench inputs are reproducible byte-for-byte. + seed: u64, + /// The documented expectation against `RATE_BUDGET_ENV_PER_SEC`. + expectation: Expectation, + /// Budget-gate timed iterations (full mode, quick mode); `0` skips the + /// row in that mode (printed as an explicit skip, never silent). + gate_iters: (usize, usize), + /// Criterion measurement time (full mode), or `None` to leave the point + /// gate-only (the 50K point: it predates the reducer fix, when a single + /// cold reduction was minute-scale; the budget gate's median covers it). + criterion_time: Option, +} + +/// THE BUDGET TABLE (worklist F1). Budget: > 10,000 envelopes/second, cold. +/// +/// | envelopes | expectation | measured (dev profile, 2026-07, post-K-fix) | why | +/// |-----------|-------------|----------------------------------------------|-----| +/// | 1,000 | Pass | ~674,000 env/s (~1.5 ms) | criterion-5 scale; ~67x margin | +/// | 10,000 | Pass | ~257,000 env/s (~39 ms) | ~26x margin | +/// | 50,000 | Pass | ~87,000 env/s (~0.58 s) | promoted from Xfail by Agent K's subquadratic reducer; full/nightly runs only | +/// +/// Pre-fix (the numbers the F1 xfail table documented): ~155K / ~12.5K / +/// ~1.7K env/s — the O(n²) `canonical_reduction_order` indegree construction, +/// which sank 50K (~29 s per cold reduce) and left 10K only ~25% over budget. +/// Agent K's threshold/frontier rewrite (see the epiphany-ops DECISIONS +/// entry) is byte-identical in order and subquadratic; the gate's XPASS +/// notice triggered the 50K promotion recorded here. +/// +/// If any row starts missing the budget again, that is a fresh regression: +/// fix the reducer, do not re-mark rows Xfail without a written decision. +const SCALE_POINTS: &[ScalePoint] = &[ + ScalePoint { + n_ops: 1_000, + seed: 0x00F1_5EED_0001, + expectation: Expectation::Pass, + gate_iters: (9, 5), + criterion_time: Some(Duration::from_secs(6)), + }, + ScalePoint { + n_ops: 10_000, + seed: 0x00F1_5EED_0002, + expectation: Expectation::Pass, + gate_iters: (3, 2), + criterion_time: Some(Duration::from_secs(20)), + }, + ScalePoint { + n_ops: 50_000, + seed: 0x00F1_5EED_0003, + expectation: Expectation::Pass, + gate_iters: (1, 0), + criterion_time: None, + }, +]; + +/// The scale point's reproducible envelope set — the criterion-5 session shape +/// (3 replicas, 40 events, 40 pitches) at `n_ops` envelopes. +fn envelopes_at(point: &ScalePoint) -> Vec { + let mut rng = Rng::new(point.seed); + generators::operation_envelopes(&mut rng, point.n_ops, 3, 40, 40) +} + +/// The timed section: cold reduction from a fresh canonical base — build a +/// fresh set (acceptance) and reduce it. The envelope clone happens in the +/// caller's un-timed setup. +fn cold_reduce(envelopes: Vec) -> MaterializedState { + let mut set = OperationSet::new(); + set.accept_all(envelopes); + set.reduce() +} + +/// The criterion measurement side (envelopes/s via `Throughput::Elements`). +fn criterion_measurements(criterion: &mut Criterion, quick: bool) { + let mut group = criterion.benchmark_group("reduction_cold"); + // Cold multi-second iterations at 10K: flat sampling, the minimum sample + // count, and per-point measurement times keep `cargo bench` wall-clock sane. + group.sampling_mode(SamplingMode::Flat); + group.sample_size(10); + for point in SCALE_POINTS { + let Some(time) = point.criterion_time else { + continue; // 50K is gate-only; see THE BUDGET TABLE. + }; + if quick && point.n_ops > 1_000 { + continue; // quick mode: the gate still measures 10K, cheaply. + } + let envelopes = envelopes_at(point); + group.throughput(Throughput::Elements(point.n_ops as u64)); + group.measurement_time(if quick { Duration::from_secs(2) } else { time }); + group.warm_up_time(Duration::from_millis(if quick { 500 } else { 1500 })); + group.bench_with_input( + BenchmarkId::from_parameter(point.n_ops), + &envelopes, + |b, envs| b.iter_batched(|| envs.clone(), cold_reduce, BatchSize::PerIteration), + ); + } + group.finish(); +} + +/// The budget-gate side: evaluates THE BUDGET TABLE and returns the rows. +fn budget_gate(quick: bool) -> Vec { + let mut reports = Vec::new(); + for point in SCALE_POINTS { + let iters = if quick { + point.gate_iters.1 + } else { + point.gate_iters.0 + }; + if iters == 0 { + println!( + "skip reduction/{}: heaviest scale point; full/nightly runs only \ + (unset EPIPHANY_BENCH_QUICK)", + point.n_ops + ); + continue; + } + let envelopes = envelopes_at(point); + let median = budget::median_time(iters, || envelopes.clone(), cold_reduce); + reports.push(budget::rate_gate( + format!("reduction/{}", point.n_ops), + point.n_ops as u64, + median, + RATE_BUDGET_ENV_PER_SEC, + point.expectation, + )); + } + reports +} + +fn main() { + // `cargo bench` passes `--bench`; its absence means criterion's test mode + // (`cargo test --benches` / `--all-targets`): run each measurement once, + // skip the gate. + let bench_mode = std::env::args().any(|arg| arg == "--bench"); + let quick = budget::quick_mode(); + + let mut criterion = Criterion::default().configure_from_args(); + criterion_measurements(&mut criterion, quick); + criterion.final_summary(); + + if !bench_mode { + return; + } + if !budget::verdict(&budget_gate(quick)) { + std::process::exit(1); + } +} diff --git a/crates/epiphany-testkit/src/budget.rs b/crates/epiphany-testkit/src/budget.rs new file mode 100644 index 0000000..525f69d --- /dev/null +++ b/crates/epiphany-testkit/src/budget.rs @@ -0,0 +1,293 @@ +//! The Chapter 10 performance-budget gate (Phase 2 worklist F1). +//! +//! The benches in `benches/` (home per `DECISIONS.md` F0) *measure* with +//! criterion; criterion never *asserts*, so each bench binary's `main()` ends +//! by running these gates: a calibrated timing check per budget row, with the +//! numeric threshold written at the call site in the bench source. Every row +//! carries an [`Expectation`]: +//! +//! * [`Expectation::Pass`] — the budget must hold **today**; a miss fails the +//! bench run with a nonzero exit (the CI tripwire). +//! * [`Expectation::Xfail`] — a documented, known-pending miss whose reason +//! names the defect and its owner. A miss prints an expected-failure line +//! and does **not** fail the run; a *pass* prints a promotion notice, +//! because the marking is then stale and must be flipped to `Pass`. +//! +//! This is the "F surfaces, K fixes" handshake (`spec/PHASE2_F_WEEK0_WORKLIST.md` +//! F1): a known-pending scale point stays `Xfail` — budget written in the +//! bench — until the named defect is fixed, at which point the gate itself +//! reports that the row should be promoted. The inaugural round completed: the +//! reducer's `O(n²)` `canonical_reduction_order` sank `reduction/50000` until +//! Agent K's subquadratic rewrite, whose XPASS notice promoted the row. +//! +//! ## Methodology note (a deliberate deviation from Chapter 10) +//! +//! Chapter 10's conformance methodology is **p99 over ≥ 1000 iterations per +//! scenario** on the reference hardware profile. That is the reference suite's +//! job, not this gate's: 1000 iterations of a minute-long 50K-envelope cold +//! reduction would be unusable in CI. The gate instead takes the **median of a +//! small, per-row calibrated iteration count** in a release build — enough to +//! reject flukes while keeping `cargo bench` wall-clock sane. Runs are cold +//! (no in-gate warm-up): the marquee budget is an explicitly *cold* reduction +//! rate, and the criterion measurements that precede the gate have already +//! warmed the allocator and caches for the warm-appropriate rows. Conformance +//! *claims* still require the full Chapter 10 methodology. + +use std::time::{Duration, Instant}; + +/// How a budget row is expected to behave on the current implementation. +#[derive(Copy, Clone, Debug)] +pub enum Expectation { + /// The budget must hold; a miss fails the bench run (nonzero exit). + Pass, + /// A documented known-pending miss; the string names the defect and who + /// fixes it. A miss is reported but tolerated; a pass demands promotion. + Xfail(&'static str), +} + +/// One evaluated budget row. +#[derive(Debug)] +pub struct GateReport { + /// The row label, e.g. `reduction/10000`. + pub label: String, + /// Human-readable `measured vs budget` detail. + pub detail: String, + /// Whether the measurement met the budget. + pub met_budget: bool, + /// The row's documented expectation. + pub expectation: Expectation, +} + +impl GateReport { + /// A `Pass`-marked row that missed its budget — the only outcome that + /// fails the bench run. + pub fn unexpected_failure(&self) -> bool { + !self.met_budget && matches!(self.expectation, Expectation::Pass) + } + + /// An `Xfail`-marked row that met its budget: the marking is stale and the + /// row should be promoted to `Pass`. + pub fn unexpected_pass(&self) -> bool { + self.met_budget && matches!(self.expectation, Expectation::Xfail(_)) + } + + /// The verdict line printed for this row. + pub fn line(&self) -> String { + match (self.met_budget, self.expectation) { + (true, Expectation::Pass) => format!("PASS {}: {}", self.label, self.detail), + (false, Expectation::Pass) => format!( + "FAIL {}: {} — budget missed on a Pass-marked row", + self.label, self.detail + ), + (false, Expectation::Xfail(reason)) => format!( + "XFAIL {}: {} — expected failure: {}", + self.label, self.detail, reason + ), + (true, Expectation::Xfail(reason)) => format!( + "XPASS {}: {} — met the budget despite the xfail marking ({}); \ + PROMOTE this row to Pass", + self.label, self.detail, reason + ), + } + } +} + +/// The median over `iters` timed runs of `op`, with per-run input built by +/// `setup` **outside** the timed section (this is how a cold-reduction row +/// clones its envelope vector without the clone being charged to the budget). +/// The output is dropped outside the timed section too. `iters ≥ 1`. +pub fn median_time( + iters: usize, + mut setup: impl FnMut() -> S, + mut op: impl FnMut(S) -> T, +) -> Duration { + assert!(iters >= 1, "a gate row needs at least one timed iteration"); + let mut samples = Vec::with_capacity(iters); + for _ in 0..iters { + let input = setup(); + let start = Instant::now(); + let out = op(input); + let elapsed = start.elapsed(); + std::hint::black_box(&out); + samples.push(elapsed); + drop(out); + } + samples.sort(); + samples[samples.len() / 2] +} + +/// Evaluates a throughput budget: `elements` per timed run must exceed +/// `budget_per_sec` (the Chapter 10 reduction-rate form, "MUST exceed"). +pub fn rate_gate( + label: impl Into, + elements: u64, + median: Duration, + budget_per_sec: f64, + expectation: Expectation, +) -> GateReport { + let rate = elements as f64 / median.as_secs_f64(); + GateReport { + label: label.into(), + detail: format!( + "{rate:.0} elements/s ({elements} elements, median {median:.2?}); \ + budget > {budget_per_sec:.0}/s" + ), + met_budget: rate > budget_per_sec, + expectation, + } +} + +/// Evaluates a latency budget: the median must come in at or under `budget` +/// (the Chapter 10 file-format form, "completes within"). +pub fn latency_gate( + label: impl Into, + median: Duration, + budget: Duration, + expectation: Expectation, +) -> GateReport { + GateReport { + label: label.into(), + detail: format!("median {median:.2?}; budget <= {budget:.0?}"), + met_budget: median <= budget, + expectation, + } +} + +/// Prints every row's verdict and returns whether the gate holds — i.e. no +/// `Pass`-marked row missed its budget. The bench binary exits nonzero when +/// this returns `false`; `Xfail` misses and `XPASS` promotions never fail the +/// run (the latter print a loud promotion notice instead). +pub fn verdict(reports: &[GateReport]) -> bool { + println!("\n== Chapter 10 budget gate (worklist F1) =="); + for report in reports { + println!("{}", report.line()); + } + let unexpected: Vec<&GateReport> = reports.iter().filter(|r| r.unexpected_failure()).collect(); + let promotions = reports.iter().filter(|r| r.unexpected_pass()).count(); + if promotions > 0 { + println!( + "note: {promotions} xfail row(s) met their budget — promote them to Pass \ + (the marking is stale)." + ); + } + if unexpected.is_empty() { + println!("budget gate: OK ({} row(s))", reports.len()); + true + } else { + println!( + "budget gate: FAILED — {} Pass-marked row(s) missed their budget", + unexpected.len() + ); + false + } +} + +/// Whether the CI-friendly quick mode is on (`EPIPHANY_BENCH_QUICK=1`): +/// reduced criterion sampling, reduced gate iteration counts, and the heaviest +/// scale points (the 50K-envelope reduction row) skipped entirely. PR CI sets +/// it; the nightly soak and local full runs leave it unset. +pub fn quick_mode() -> bool { + std::env::var("EPIPHANY_BENCH_QUICK").is_ok_and(|v| !v.is_empty() && v != "0") +} + +#[cfg(test)] +mod tests { + use super::*; + + fn row(met_budget: bool, expectation: Expectation) -> GateReport { + GateReport { + label: "test/row".to_owned(), + detail: "detail".to_owned(), + met_budget, + expectation, + } + } + + #[test] + fn pass_row_meeting_budget_holds() { + let r = row(true, Expectation::Pass); + assert!(!r.unexpected_failure()); + assert!(!r.unexpected_pass()); + assert!(verdict(&[r])); + } + + #[test] + fn pass_row_missing_budget_fails_the_gate() { + let r = row(false, Expectation::Pass); + assert!(r.unexpected_failure()); + assert!(r.line().starts_with("FAIL")); + assert!(!verdict(&[r])); + } + + #[test] + fn xfail_row_missing_budget_is_tolerated() { + let r = row(false, Expectation::Xfail("documented defect")); + assert!(!r.unexpected_failure()); + assert!(r.line().starts_with("XFAIL")); + assert!(r.line().contains("documented defect")); + assert!(verdict(&[r])); + } + + #[test] + fn xfail_row_meeting_budget_demands_promotion_but_holds() { + let r = row(true, Expectation::Xfail("documented defect")); + assert!(r.unexpected_pass()); + assert!(r.line().starts_with("XPASS")); + assert!(r.line().contains("PROMOTE")); + assert!(verdict(&[r])); + } + + #[test] + fn gates_evaluate_their_thresholds() { + // 100 elements in 1 ms = 100,000/s. + let fast = rate_gate( + "rate/fast", + 100, + Duration::from_millis(1), + 10_000.0, + Expectation::Pass, + ); + assert!(fast.met_budget); + let slow = rate_gate( + "rate/slow", + 100, + Duration::from_millis(100), + 10_000.0, + Expectation::Pass, + ); + assert!(!slow.met_budget); + + let ok = latency_gate( + "lat/ok", + Duration::from_millis(10), + Duration::from_millis(50), + Expectation::Pass, + ); + assert!(ok.met_budget); + let over = latency_gate( + "lat/over", + Duration::from_millis(60), + Duration::from_millis(50), + Expectation::Pass, + ); + assert!(!over.met_budget); + } + + #[test] + fn median_time_takes_the_middle_sample() { + // Deterministic ordering check via a controlled op: the median of an + // odd sample count must be a real observed sample, not an average. + let mut calls = 0u32; + let d = median_time( + 5, + || (), + |()| { + calls += 1; + }, + ); + assert_eq!(calls, 5); + // No timing assertion (flaky); the structural property is that a + // duration was produced at all and the closure ran `iters` times. + let _ = d; + } +} diff --git a/crates/epiphany-testkit/src/corpus.rs b/crates/epiphany-testkit/src/corpus.rs index 2a21bb6..d3a01aa 100644 --- a/crates/epiphany-testkit/src/corpus.rs +++ b/crates/epiphany-testkit/src/corpus.rs @@ -177,7 +177,7 @@ pub struct Fixture { pub tier: Tier, pub build: fn() -> Score, /// Buckets this fixture must drive non-zero (validated per-fixture, and - /// aggregated for corpus coverage). For the [`UNUSUAL_BUCKETS`] this list is + /// aggregated for corpus coverage). For the crate-private `UNUSUAL_BUCKETS` this list is /// also an *exact whitelist*: a fixture that lands an event in a /// loss/deferral bucket it did not declare fails the harness. pub expect: &'static [Bucket], diff --git a/crates/epiphany-testkit/src/lib.rs b/crates/epiphany-testkit/src/lib.rs index d9b5966..f670e20 100644 --- a/crates/epiphany-testkit/src/lib.rs +++ b/crates/epiphany-testkit/src/lib.rs @@ -92,6 +92,11 @@ pub mod rng; +// Phase 2, Agent F (worklist F1): the Chapter 10 performance-budget gate the +// `benches/` targets assert through (Pass / Xfail rows with thresholds written +// in the bench source; see `DECISIONS.md` F0/F1). +pub mod budget; + pub mod fixtures; pub mod generators; pub mod roundtrip; diff --git a/spec/PASS12_BATCH.md b/spec/PASS12_BATCH.md index 2f2e2e8..ea7e65d 100644 --- a/spec/PASS12_BATCH.md +++ b/spec/PASS12_BATCH.md @@ -52,10 +52,10 @@ code instead is the failure mode this batch exists to prevent. | P12-I4 | `epiphany-layout-ir` I | Constraint-strength attachment: Ch9 defines `ConstraintStrength` and says the solver consumes constraints "in normalized form", but neither the normalized form nor Ch7's `LayoutConstraint` provides a channel for an instance to carry strength. Implemented rule: break strength = `BreakKind` (Hard→Required, Soft→Preferred{1.0}); other core families Required; `Registered` conservative Required. Bless the rule or add a strength field. | G / Pass 12 (solver) | | P12-I5 | `epiphany-layout-ir` I | No renderable status exists for "constraints present but not evaluated": every renderable `SolveStatus` is documented as "all hard constraints satisfied", leaving a below-conformance passthrough solver no honest report. Implemented encoding: `SolvedWithWarnings` + `satisfied_hard_constraints == false` + a warning. Sanction it or define a non-evaluating-tier report shape. | G / Pass 12 (solver) | | P12-I6 | `epiphany-layout-ir` I | The spacing pass MUST "build collision constraints" but no per-tier minimum emission set is named. Implemented floor: successive-notehead-column no-collision chains + per-glyph region containment + user-break constraints. A normative Minimal-tier floor would make the acceptance surface testable. | G / Pass 12 (solver) | -| P12-D1 | `epiphany-bundle` D | Operation-index provisional encoding (block-refs + id-sorted entries with u32 block ordinal and u32 in-block offset; golden-locked) awaiting Binary Format companion ratification, together with: the offset's meaning (first content byte within the uncompressed block payload), a normative definition of "stale" (implemented: index block-set ≠ manifest `operation_roots` under full-`ChunkRef` equality), the one-slot-per-id invariant, the load-bearing property that the envelope encoding *leads* with the 16-byte OperationId, and whether the commit-time "grown significantly" SHOULD gets a threshold or stays implementation-defined. | J (Binary Format companion) | -| P12-E1 | `epiphany-layout-ir` E | Provisional canonical byte form for the `EditBarrier`/`BarrierScope`/`BarrierCondition` tree and the two `ExtensionDeclaration` blobs (`push_set` framing, u64 LE lengths; golden-locked). Ratify into the Binary Format companion. | J (Binary Format companion) | -| P12-E2 | `epiphany-layout-ir` E | The spec places no bound on `BarrierCondition` recursion; the decoder needs one against adversarial bytes. `MAX_CONDITION_DEPTH = 64` implemented — ratify a normative bound or bless the constant. | J (Binary Format companion) | -| P12-E3 | `epiphany-layout-ir` E | Barrier `ObjectKind` byte form = the `TypedObjectId` 16-bit discriminant (2 LE bytes) with open-value decode (unknown kinds never match, preserving append-only forward compat). Ratify representation + stance. | J (Binary Format companion) | +| ~~P12-D1~~ **RESOLVED (Binary Format 0.1.0 §7.6, `req:binfmt:opindex`)** | `epiphany-bundle` D | Operation-index provisional encoding (block-refs + id-sorted entries with u32 block ordinal and u32 in-block offset; golden-locked) awaiting Binary Format companion ratification, together with: the offset's meaning (first content byte within the uncompressed block payload), a normative definition of "stale" (implemented: index block-set ≠ manifest `operation_roots` under full-`ChunkRef` equality), the one-slot-per-id invariant, the load-bearing property that the envelope encoding *leads* with the 16-byte OperationId, and whether the commit-time "grown significantly" SHOULD gets a threshold or stays implementation-defined. Ratified as-implemented; refresh threshold pinned implementation-defined (open question retained in the companion). | ✅ done | +| ~~P12-E1~~ **RESOLVED (Binary Format 0.1.0 §8.1, `req:binfmt:ext-blobs`)** | `epiphany-layout-ir` E | Provisional canonical byte form for the `EditBarrier`/`BarrierScope`/`BarrierCondition` tree and the two `ExtensionDeclaration` blobs (`push_set` framing, u64 LE lengths; golden-locked). Ratified as-implemented. | ✅ done | +| ~~P12-E2~~ **RESOLVED (Binary Format 0.1.0 §8.2, `req:binfmt:condition-depth`)** | `epiphany-layout-ir` E | The spec places no bound on `BarrierCondition` recursion; the decoder needs one against adversarial bytes. `MAX_CONDITION_DEPTH = 64` implemented — the companion pins 64 as the normative bound (decoders MUST reject deeper; writers MUST NOT emit deeper). | ✅ done | +| ~~P12-E3~~ **RESOLVED (Binary Format 0.1.0 §8.1, `req:binfmt:object-kind-open`)** | `epiphany-layout-ir` E | Barrier `ObjectKind` byte form = the `TypedObjectId` 16-bit discriminant (2 LE bytes) with open-value decode (unknown kinds never match, preserving append-only forward compat). Representation and open-value stance ratified. | ✅ done | | P12-E4 | `epiphany-editor-core` E | Barrier matching for operations with no graph target (`SetMetadata`, `DeclareTransaction` — implemented: score-wide barriers only) and for opaque `Registered` operations (implemented: fully conservative match) is unspecified. | G (Ch. 8) | | P12-E5 | `epiphany-editor-core` E | The unsafe-edit tombstone MUST has no defined mechanism: the manifest-side form (drop declaration + preserved roots? an explicit tombstone record?), interaction with `required = true`, and whether crossing immediately deactivates the extension's remaining barriers (implemented: yes, recorded via `extensions_requiring_tombstone()` for the next bundle write). | G (Ch. 8) | @@ -65,7 +65,10 @@ Agent I (Track A) has contributed P12-I1..I6. Track B's Agent K has contributed P12-K1..K7; H has contributed P12-H1..H7 (H6/H7 from the 2026-07 spec-compliance audit follow-up, alongside K3/K4). The 2026-07 Push-3 wiring work added C1..C4 (re-anchoring), D1 (bundle operation index), and E1..E5 -(edit barriers). Agent J (Binary Format companion) has not yet contributed; -when it does, append rows — the batch is already open, so it joins directly -(no new threshold). Note the P12-D1/E1/E2/E3 rows are *inputs* to J's -companion rather than G-dispositions. +(edit barriers). Agent J's Binary Format companion now exists +(`spec/binary_format.tex`, v0.1.0): it ratified the P12-D1/E1/E2/E3 inputs +(struck through above) and discharged the crates' provisional-codec notes +(core P11-4, ops "provisional canonical encoding", bundle P11-D2/D4/D5). Its +three open questions (SnapshotId derivation, index-refresh threshold, u64/u32 +prefix unification at the next schema major) live in the companion itself, not +as batch rows. diff --git a/spec/binary_format.pdf b/spec/binary_format.pdf new file mode 100644 index 0000000000000000000000000000000000000000..cb415b60f2b906e829eb0b8d3c392ba6106b90a4 GIT binary patch literal 200616 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.] A presence byte: \texttt{0} = absent (no further + bytes), \texttt{1} = present, followed by \texttt{T}'s encoding. A + presence byte greater than~1 is a decode error. + \item[Sequences, sets, maps.] A \texttt{u32} little-endian element count, + then each element (for maps: key then value). Set- and map-valued fields + are emitted in canonical iteration order --- ascending by the key's + canonical byte form --- and decoders reject out-of-order or duplicated + elements wherever the field is a set or map (as opposed to an + order-significant list). + \item[Free text.] A \texttt{u32} little-endian byte length, then the raw + UTF-8 bytes. Free-text fields (e.g.\ a score title) are \textbf{never} + NFC-folded by the codec: $\mathrm{decode}(\mathrm{encode}(x)) = x$ is the + round-trip identity, and folding would break it. By contrast, + \emph{catalog identifiers} (pitch-space ids, tuning-system ids, and the + other \texttt{catalog\_id} newtypes) are NFC-normalized \emph{at + construction}, so their stored form is already NFC; the codec encodes the + stored string verbatim. Operation-layer text fields (the transaction + label, conflict field paths) are NFC-normalized at encode time + (Chapter~\ref{ch:ops}). + \item[Structs.] Positional, unframed concatenation of the fields' encodings + in declaration order. No field tags, no per-field lengths, no padding, no + alignment. (This is the layout the frozen-layout rule, + Requirement~\ref{req:binfmt:frozen-layout}, freezes.) + \item[Tagged unions.] A single discriminant byte, then the selected + variant's payload encoded positionally. Two documented exceptions: + \texttt{TypedObjectId} uses a \emph{16-bit big-endian} discriminant + (core requirement \texttt{req:graph:typed-object-id-discriminants}; + Chapter~\ref{ch:ids}), and the bundle's \texttt{ProfileId} uses a + \texttt{u32} little-endian discriminant (core requirement + \texttt{req:format:profileid-discriminants}; Chapter~\ref{ch:bundle}). + \item[Determinism-canonical leaves.] Where a composite codec embeds a value + whose canonical byte form is owned by the determinism layer or the + identifier layer (a graph identifier, \texttt{ContentHash}, + \texttt{CanonicalF64}, \texttt{RationalTime}, a wall-clock integer), the + core value codec frames it as a \texttt{u32} little-endian length prefix + followed by the leaf's own canonical bytes --- even when the leaf is + fixed-width. The leaf's bytes are then self-describing under its own + decoder. (The operation layer instead embeds fixed-width leaves + \emph{raw}, unprefixed; Chapter~\ref{ch:ops} states this explicitly.) +\end{description} + +\begin{requirement} +\label{req:binfmt:no-varint} +\textbf{No varint.} Schema major~0 defines \emph{no} variable-length integer +encoding. Every integer field in every layout in this document is +fixed-width. The core specification's ``varint conventions'' language +(Chapter~8, \sectionsc{Binary Format Companion}) is hereby discharged as +\emph{none}: an encoder \MUSTNOT{} emit, and a decoder \MUSTNOT{} accept, any +LEB128-style or otherwise variable-width integer under schema major~0. +Variable width in this format comes only from explicit \texttt{u32}/% +\texttt{u64} length prefixes and from \texttt{RationalTime}'s length-prefixed +big-integer magnitudes (Chapter~\ref{ch:primitives}). +\end{requirement} + +\begin{requirement} +\label{req:binfmt:trailing-bytes} +\textbf{Trailing bytes.} Every top-level decode entry point --- a +whole-\texttt{Score} value, a per-value \texttt{CanonicalValue} decode, an +\texttt{OperationKindTag}, a \texttt{MaterializedState}, a manifest payload, +an operation-index payload, a block payload, an extension-declaration blob, a +fixed-width primitive --- \MUST{} reject input with bytes remaining after the +complete value has been decoded. Trailing bytes are a decode error, never +ignored padding. +\end{requirement} + +% =========================================================================== +\chapter{Identifiers and Derivations} +\label{ch:ids} + +This chapter is an \emph{import-by-citation} of the core specification's +\sectionsc{Canonical Byte-Layout Reference} appendix (\texttt{app:bytes}): +that appendix and its golden anchors govern every table in this chapter, and +the tables here are compact restatements for self-containedness, not a second +source of truth. All layouts in this chapter are regime (c): big-endian, +fixed width. + +\section{The 128-Bit Identifier Family} +\label{sec:ids:family} + +\begin{description} + \item[\texttt{ReplicaId}.] 8 bytes, big-endian \texttt{u64}. The reserved + system namespace is \texttt{ReplicaId::SYSTEM\ub DERIVED} = + \texttt{0xFFFF\ub FFFF\ub FFFF\ub FFFF}; user-authored replicas + \MUSTNOT{} use it. + \item[Typed graph identifiers.] Every typed 128-bit graph identifier + (\texttt{EventId}, \texttt{PitchId}, \texttt{VoiceId}, + \texttt{RegionId}, \texttt{StaffInstanceId}, \texttt{TransactionId}, + \ldots{} --- the \texttt{graph\_id} family) packs the 64-bit replica + into the high half and the counter into the low half, and encodes as + exactly 16~bytes: replica big-endian (8) \cat{} counter big-endian (8). + Numeric order, canonical byte order, and Appendix-D iteration order + coincide. + \item[\texttt{OperationId}.] The same 16-byte form: replica big-endian (8) + \cat{} counter big-endian (8). Ordering is $(\mathit{replica}, + \mathit{counter})$ lexicographic, which equals byte order. + \item[Registry and author identifiers (operation layer).] The opaque + 128-bit registry newtypes (\texttt{OperationKind\allowbreak RegistryId}, + \texttt{ConflictKind\allowbreak RegistryId}, + \texttt{Resolution\allowbreak RegistryId}, + \texttt{RepairKind\allowbreak RegistryId}, + \texttt{ReanchorReason\allowbreak RegistryId}, + \texttt{ReplicaAnomaly\allowbreak RegistryId}, + \texttt{IntegrityAnomaly\allowbreak RegistryId}, + \texttt{Extension\allowbreak PreconditionId}, + \texttt{PreconditionFailure\allowbreak RegistryId}) and \texttt{AuthorId} + all encode as 16 big-endian bytes. +\end{description} + +\section{\texttt{TypedObjectId}} +\label{sec:ids:typed-object-id} + +Canonical form: a \textbf{16-bit big-endian discriminant} \cat{} the variant +payload (core requirement \texttt{req:graph:typed-object-id-discriminants}). +Non-\texttt{Registered} variants carry one 16-byte identifier, for a total of +\textbf{18~bytes}; \texttt{Registered} carries the +\texttt{ObjectKindRegistryId} (16 big-endian bytes) \cat{} the extension's +own raw \texttt{u128} (16 big-endian bytes), for a total of \textbf{34~bytes}. +An unknown discriminant is a decode error. + +\begingroup\small +\begin{longtable}{p{0.5in} p{1.6in} p{0.5in} p{1.6in}} + \toprule + \textbf{Disc} & \textbf{Variant} & \textbf{Disc} & \textbf{Variant} \\ + \midrule + \endhead + \tablenums{0} & \texttt{Event} & \tablenums{14} & \texttt{Spanner} \\ + \tablenums{1} & \texttt{Pitch} & \tablenums{15} & \texttt{Marker} \\ + \tablenums{2} & \texttt{Voice} & \tablenums{16} & \texttt{AnalyticalAnnotation} \\ + \tablenums{3} & \texttt{Staff} & \tablenums{17} & \texttt{Comment} \\ + \tablenums{4} & \texttt{StaffInstance} & \tablenums{18} & \texttt{GraphicObject} \\ + \tablenums{5} & \texttt{StaffGroup} & \tablenums{19} & \texttt{GraphicGesture} \\ + \tablenums{6} & \texttt{Region} & \tablenums{20} & \texttt{TimeSignature} \\ + \tablenums{7} & \texttt{Instrument} & \tablenums{21} & \texttt{AnalysisLayer} \\ + \tablenums{8} & \texttt{PartDefinition} & \tablenums{22} & \texttt{Tuplet} \\ + \tablenums{9} & \texttt{Measure} & \tablenums{23} & \texttt{RepeatStructure} \\ + \tablenums{10} & \texttt{BarlineAlignmentGroup} & \tablenums{24} & \texttt{LyricLine} \\ + \tablenums{11} & \texttt{Slur} & \tablenums{25} & \texttt{ChordSymbol} \\ + \tablenums{12} & \texttt{Tie} & \tablenums{26} & \texttt{View} \\ + \tablenums{13} & \texttt{Beam} & \tablenums{27} & \texttt{Registered} \\ + \bottomrule +\end{longtable} +\endgroup + +\section{System-Derived Counters and Digest Truncations} +\label{sec:ids:derivations} + +All content derivation uses BLAKE3-256 over a domain-separated preimage: the +8-byte domain tag is always the first bytes hashed. Two truncations recur, +both taking the digest's \emph{leading} bytes big-endian: + +\begin{itemize} + \item $\mathrm{trunc64}(d) = \mathtt{u64::from\_be\_bytes}(d[0..8])$ --- + the counter of a system-derived identifier; + \item $\mathrm{trunc128}(d) = \mathtt{u128::from\_be\_bytes}(d[0..16])$ --- + content-derived 128-bit identifiers. +\end{itemize} + +The system-derived counter function is +$\mathrm{trunc64}(\mathrm{BLAKE3}(\mathit{tag} \cat \mathit{inputs}))$; the +resulting identifier is +$\texttt{from\_parts}(\texttt{ReplicaId::SYSTEM\_DERIVED}, \mathit{counter})$. +Only a system domain tag (prefix \texttt{MUSCS}) may seed it. The ratified +instances (governed by \texttt{app:bytes} and the cited requirements): + +\begingroup\small +\begin{longtable}{p{1.35in} p{0.7in} p{3.5in}} + \toprule + \textbf{Identifier} & \textbf{Tag} & \textbf{Canonical inputs} \\ + \midrule + \endhead + Promoted \texttt{VoiceId} & \texttt{MUSCSVCE} & + 64-byte preimage: \texttt{staff\_instance} (16 BE) \cat{} + \texttt{original\_voice} (16 BE) \cat{} \texttt{winning\_op} (16 BE) + \cat{} \texttt{losing\_op} (16 BE). Core \sectionsc{System-Promoted + Voices}. \\ + System \texttt{PitchId} & \texttt{MUSCSPCH} & + The pitch's intrinsic canonical bytes (core requirement + \texttt{req:graph:system-derived-pitch-id}). \\ + \texttt{IntegrityAnomalyId} & \texttt{MUSCSANM} & + The anomaly kind's canonical bytes (Chapter~\ref{ch:ops}; core + requirement \texttt{req:graph:integrity-anomaly-id}). \\ + \bottomrule +\end{longtable} +\endgroup + +The 128-bit content-derived identifiers: + +\begingroup\small +\begin{longtable}{p{1.1in} p{0.75in} p{3.7in}} + \toprule + \textbf{Identifier} & \textbf{Tag} & \textbf{Preimage after the tag} \\ + \midrule + \endhead + \texttt{ConflictId} & \texttt{MUSCCONF} & + \texttt{kind.canonical\_bytes()} \cat{} causing operations (each 16 BE, + sorted by canonical bytes) \cat{} affected objects (each + \texttt{TypedObjectId} canonical bytes, sorted); $\mathrm{trunc128}$. + Wire form of the id itself: 16 big-endian bytes. \\ + \texttt{ManifestId} & \texttt{MUSCMNIF} & + \texttt{document\_id} (16) \cat{} \texttt{generation} (\texttt{u64} LE) + \cat{} manifest body bytes (body excludes the \texttt{manifest\_id} + field); $\mathrm{trunc128}$. Restated normatively in + Chapter~\ref{ch:bundle} (core requirement + \texttt{req:format:manifest-id}). Note the \emph{on-disk} field encodes + little-endian (Chapter~\ref{ch:bundle}). \\ + \texttt{EnvelopeHash} & \texttt{MUSCENVH} & + The envelope's complete canonical bytes; the full 32-byte digest (no + truncation). Chapter~\ref{ch:ops}. \\ + \texttt{LayoutObjectId} & \texttt{MUSCLOID} & + Non-canonical; three preimage shapes, Chapter~\ref{ch:noncanon} + (core requirement \texttt{req:layoutir:object-id-derivation}). \\ + \texttt{BlobId} & \texttt{MUSCBLOB} & + The blob payload, bare (\texttt{req:format:blob-hash-shape}); full + 32-byte digest. Chapter~\ref{ch:primitives}. \\ + \bottomrule +\end{longtable} +\endgroup + +\section{The Domain-Tag Registry} +\label{sec:ids:tags} + +Every domain tag is exactly 8 printable-ASCII bytes beginning \texttt{MUSC}; +the vocabulary is closed (governed by \texttt{app:bytes}, +\sectionsc{Domain-tag registry}). Extension system tags \MUST{} begin +\texttt{MUSCS}, be exactly 8 bytes, and collide with neither the built-ins +nor the file magics. + +\begingroup\small +\begin{longtable}{p{1.05in} p{1.55in} p{3.0in}} + \toprule + \textbf{Tag} & \textbf{Name} & \textbf{Use} \\ + \midrule + \endhead + \texttt{MUSCCHNK} & chunk & non-manifest chunk hash preimages \\ + \texttt{MUSCMANI} & manifest & manifest chunk hash preimages \\ + \texttt{MUSCBLOB} & blob & \texttt{BlobId} (bare $\mathit{tag} \cat \mathit{payload}$) \\ + \texttt{MUSCCONF} & conflict & \texttt{ConflictId} derivation \\ + \texttt{MUSCENVH} & envelope & \texttt{EnvelopeHash} \\ + \texttt{MUSCFNTM} & font metrics & glyph-catalog metrics hash (non-canonical) \\ + \texttt{MUSCMNIF} & manifest id & \texttt{ManifestId} derivation \\ + \texttt{MUSCSVCE} & system voice & promoted-voice counters \\ + \texttt{MUSCSPCH} & system pitch & system-derived pitch counters \\ + \texttt{MUSCSANM} & system anomaly & \texttt{IntegrityAnomalyId} \\ + \texttt{MUSCLOID} & layout object id & \texttt{LayoutObjectId} (non-canonical) \\ + \midrule + \texttt{MUSCBND\textbackslash0} & bundle magic & file magic, \emph{not} a hash tag (note the trailing NUL) \\ + \texttt{MUSCSUPR} & superblock magic & slot magic, \emph{not} a hash tag \\ + \bottomrule +\end{longtable} +\endgroup + +\section{\texttt{SnapshotId}} +\label{sec:ids:snapshot-id} + +The core specification's support-type identity table says \emph{``the Binary +Format companion defines the exact derivation''} of \texttt{SnapshotId}. v0 +has no snapshot producer --- pruning and canonical-base creation are deferred +--- so there is nothing to derive \emph{from} yet. + +\begin{requirement} +\label{req:binfmt:snapshot-id-opaque} +In schema major~0, \texttt{SnapshotId} is an \textbf{opaque 16-byte +identifier}: 16 raw bytes on the wire (Chapter~\ref{ch:primitives}), with no +normative derivation function. Readers \MUST{} treat two +\texttt{SnapshotId}s as equal iff their 16 bytes are equal and \MUSTNOT{} +attempt to derive or verify a snapshot id from snapshot content. +\end{requirement} + +\begin{openquestion} +The \texttt{SnapshotId} derivation (presumably a content derivation in the +\texttt{trunc128} family, over the snapshot's canonical payload and its +covering frontier) is deferred together with the pruning/garbage-collection +track that will produce the first snapshots. It must be pinned before any +writer emits a \texttt{canonical\_base}; until then the opaque reading above +is complete. +\end{openquestion} + +% =========================================================================== +\chapter{Primitive Value Encodings} +\label{ch:primitives} + +The leaf encodings owned by the determinism layer and the small fixed +identifier types. These byte forms are what the framings of +Chapters~\ref{ch:values}--\ref{ch:bundle} embed. + +\begingroup\small +\begin{longtable}{>{\raggedright\arraybackslash}p{1.7in} p{0.5in} p{3.45in}} + \toprule + \textbf{Type} & \textbf{Width} & \textbf{Encoding} \\ + \midrule + \endhead + \texttt{CanonicalF64} & 8 & + IEEE-754 binary64, little-endian. $-0.0$ is canonicalized to $+0.0$ at + construction, so the negative-zero bit pattern never appears in canonical + bytes. Decode rejects NaN and $\pm\infty$ (non-finite floats are + corruption). \\ + \texttt{QuantizedCoord} & 8 & + \texttt{i64} little-endian, in units of $1/1024$ staff space + (\texttt{STAFF\_SPACE\_GRID} = 1024). Construction from a float rounds + ties-to-even and rejects non-finite or out-of-range input. \\ + \texttt{ContentHash} & 32 & Raw BLAKE3-256 digest bytes. \\ + \texttt{ChunkId} & 32 & Raw digest bytes (a \texttt{ContentHash} newtype). \\ + \texttt{DomainTag} & 8 & + The raw ASCII tag bytes. Decode validates against the closed vocabulary + of Section~\ref{sec:ids:tags}; foreign bytes are a decode error. \\ + \texttt{WallClockTime} & 8 & + \texttt{i64} little-endian, nanoseconds. Floating-point wall-clock time + is forbidden in stored data. \\ + \texttt{WallClockDuration} & 8 & \texttt{i64} little-endian, nanoseconds. \\ + \texttt{SchemaVersion} & 4 & + \texttt{major} \texttt{u16} LE \cat{} \texttt{minor} \texttt{u16} LE. \\ + \texttt{SemVer} & 12 & + \texttt{major} \texttt{u32} LE \cat{} \texttt{minor} \texttt{u32} LE + \cat{} \texttt{patch} \texttt{u32} LE. Canonical \emph{ordering} of + \texttt{SemVer}-keyed collections is \textbf{numeric} on + $(\mathit{major},\mathit{minor},\mathit{patch})$, never byte-lexicographic + on the little-endian encoding (which would order 256.0.0 before 1.0.0). \\ + \texttt{Reduction\allowbreak AlgorithmVersion} & 4 & \texttt{u32} + little-endian. \\ + \texttt{FileUuid}, \texttt{DocumentId}, \texttt{LineageId}, + \texttt{SnapshotId}, \texttt{ExtensionId}, \texttt{ProfileRegistryId} & 16 & + 16 raw opaque bytes each. No internal structure is interpreted; + equality is byte equality. \\ + \texttt{BlobId} & 32 & + Raw digest bytes: $\mathrm{BLAKE3}(\texttt{MUSCBLOB} \cat + \mathit{payload})$, the only bare $\mathit{tag} \cat \mathit{payload}$ + content hash in the format (core requirement + \texttt{req:format:blob-hash-shape}). \\ + \texttt{FrontierBytes} & var & + \texttt{u32} LE length \cat{} opaque bytes (an ops-computed causal + frontier the bundle carries verbatim). \\ + \bottomrule +\end{longtable} +\endgroup + +\section{\texttt{RationalTime}} +\label{sec:primitives:rationaltime} + +Restating core requirement \texttt{req:format:rationaltime-encoding}, which +governs. \texttt{RationalTime} is an arbitrary-precision rational, always +stored \emph{reduced} (equal rationals encode identically; the sign lives on +the numerator; the denominator is strictly positive). Its canonical byte +form: + +\begin{center} +\begin{tabular}{l l} + \toprule + \textbf{Field} & \textbf{Encoding} \\ + \midrule + sign & 1 byte: \tablenums{0} = zero, \tablenums{1} = positive, + \tablenums{2} = negative \\ + numerator & \texttt{u32} LE magnitude byte length \cat{} big-endian + magnitude bytes \\ + denominator & \texttt{u32} LE magnitude byte length \cat{} big-endian + magnitude bytes \\ + \bottomrule +\end{tabular} +\end{center} + +Decode rejects a sign byte greater than~2, a zero denominator, and trailing +bytes. \texttt{MusicalPosition} and \texttt{MusicalDuration} are newtypes +whose canonical bytes are exactly their inner \texttt{RationalTime}'s. +Wall-clock integers deliberately do \emph{not} use this form: they are the +fixed-width little-endian integers of the table above, matching +\texttt{QuantizedCoord}'s convention. + +% =========================================================================== +\chapter{Graph Value Layouts} +\label{ch:values} + +This chapter defines the schema-major-0 wire form of every value reachable +from a \texttt{Score} --- the whole-document composite codec. The core +specification's \texttt{DECISIONS} record (P11-4) held this codec +\emph{provisional} pending this companion; +Requirement~\ref{req:binfmt:score-envelope} and +Requirement~\ref{req:binfmt:frozen-layout} \textbf{ratify} it: the reference +implementation's layout, as specified here, \emph{is} the schema-major-0 wire +form, and P11-4's provisional status is discharged. + +All layouts in this chapter are regime (a): little-endian, \texttt{u32} +prefixes. + +\section{The \texttt{Score} Envelope} +\label{sec:values:score} + +\begin{requirement} +\label{req:binfmt:score-envelope} +The canonical bytes of a \texttt{Score} are the bare positional +concatenation of its nineteen fields' encodings, in exactly this order: + +\begin{enumerate} + \item \texttt{metadata} + \item \texttt{canvas} + \item \texttt{instruments} + \item \texttt{staves} + \item \texttt{staff\_groups} + \item \texttt{parts} + \item \texttt{cross\_cutting} + \item \texttt{time\_signatures} + \item \texttt{tuning\_context} + \item \texttt{tempo\_map} + \item \texttt{events} + \item \texttt{spelling\_attachments} + \item \texttt{decomposition\_attachments} + \item \texttt{spelling\_precedence} + \item \texttt{analysis\_layers} + \item \texttt{views} + \item \texttt{identity} + \item \texttt{tombstoned\_pitches} + \item \texttt{tombstoned\_events} +\end{enumerate} + +There is \textbf{no magic} and \textbf{no version prefix} at the value +level: format identification lives in the bundle's fixed header +(Chapter~\ref{ch:bundle}) and versioning lives at the chunk layer +(\texttt{SchemaVersion} in every \texttt{ChunkRef} and superblock; +Chapter~\ref{ch:evolution}). Decoders \MUST{} reject trailing bytes after +the nineteenth field. +\end{requirement} + +\section{Composition Rules as Normative Encoding Facts} +\label{sec:values:composition} + +The reference codec is built from a small set of conventions; each is a +normative statement about the bytes, not an implementation detail: + +\begin{description} + \item[Positional structs.] Every struct in this chapter encodes as its + fields in declaration order, unframed + (Section~\ref{sec:conventions:primitives}). Zero-field structs encode as + zero bytes. + \item[C-style enums.] A fieldless enum is a single discriminant byte + (tables in Section~\ref{sec:values:discriminants}). + \item[Tagged unions.] A discriminant byte, then the variant's fields + positionally. + \item[Leaf framing.] The determinism-canonical leaf types --- + \texttt{ReplicaId}, \texttt{OperationId}, every embedded typed graph + identifier (\texttt{EventId}, \texttt{PitchId}, \texttt{VoiceId}, + \texttt{StaffId}, \texttt{StaffInstanceId}, \texttt{StaffGroupId}, + \texttt{RegionId}, \texttt{InstrumentId}, \texttt{PartDefinitionId}, + \texttt{MeasureId}, \texttt{BarlineAlignmentGroupId}, \texttt{SlurId}, + \texttt{TieId}, \texttt{BeamId}, \texttt{SpannerId}, \texttt{TupletId}, + \texttt{MarkerId}, \texttt{AnalyticalAnnotationId}, \texttt{CommentId}, + \texttt{RepeatStructureId}, \texttt{LyricLineId}, \texttt{ChordSymbolId}, + \texttt{GraphicObjectId}, \texttt{GraphicGestureId}, + \texttt{TimeSignatureId}, \texttt{AnalysisLayerId}, \texttt{ViewId}) --- + plus \texttt{ContentHash}, \texttt{CanonicalF64}, \texttt{RationalTime}, + \texttt{MusicalPosition}, \texttt{MusicalDuration}, + \texttt{WallClockTime}, and \texttt{WallClockDuration}, are each emitted + as \texttt{u32} LE length \cat{} the leaf's canonical bytes + (Chapters~\ref{ch:ids} and \ref{ch:primitives}). An embedded 16-byte + identifier therefore occupies 20 bytes inside a \texttt{Score}. Decode + runs the leaf's own validating decoder over the framed region. + \item[Catalog identifiers.] The \texttt{catalog\_id} newtypes + (\texttt{PitchSpaceId}, \texttt{TuningSystemId}, \texttt{AccidentalId}, + registry-name ids, \ldots) encode as their stored NFC string under the + String rule (\texttt{u32} LE length \cat{} UTF-8). + \item[\texttt{EventArena}.] \texttt{u32} LE event count, then each + \texttt{Event} in ascending-\texttt{EventId} order (identity travels + inside each event; the arena adds no per-event framing). + \item[Validated reconstruction.] Types with checked constructors decode + through them: \texttt{TupletRatio} rejects degenerate ratios, + \texttt{KeySignature} encodes its \texttt{fifths()} as \texttt{i8} and + rejects out-of-range values, \texttt{TimeSignature} re-validates that + beat groups sum to the measure duration, \texttt{NonZeroU16} rejects + zero, \texttt{EventOrderingDAG} rejects cyclic edge maps, + \texttt{ReferencePitch}, \texttt{Tempo}, and + \texttt{SpellingPrecedence} re-validate their invariants. Structurally + well-formed bytes that fail a type invariant are a decode error + (reject-never-normalize). +\end{description} + +\section{Discriminant Tables} +\label{sec:values:discriminants} + +The complete discriminant assignment for schema major~0. Every table is +governed by Requirement~\ref{req:binfmt:frozen-layout}: an unknown +discriminant is a decode error; changes are gated by +Chapter~\ref{ch:evolution}. + +\subsection{C-style enums (one byte, no payload)} + +\begingroup\small +\begin{longtable}{p{1.9in} p{3.7in}} + \toprule + \textbf{Type} & \textbf{Discriminants} \\ + \midrule + \endhead + \texttt{MeasurePosition} & \tablenums{0} Start, \tablenums{1} End \\ + \texttt{RegionEdge} & \tablenums{0} Start, \tablenums{1} End \\ + \texttt{CmnNominal} & \tablenums{0} C, \tablenums{1} D, \tablenums{2} E, + \tablenums{3} F, \tablenums{4} G, \tablenums{5} A, \tablenums{6} B \\ + \texttt{SpellingSourceKind} & \tablenums{0} UserChosen, + \tablenums{1} Imported, \tablenums{2} Propagated, \tablenums{3} Inferred, + \tablenums{4} Analytical \\ + \texttt{TempoShape} & \tablenums{0} Constant, \tablenums{1} Linear, + \tablenums{2} Exponential, \tablenums{3} Curve \\ + \texttt{StemDirection} & \tablenums{0} Up, \tablenums{1} Down \\ + \texttt{MeasureNumberVisibility} & \tablenums{0} Auto, + \tablenums{1} Always, \tablenums{2} Never \\ + \texttt{Aleatoric\allowbreak AnchoringDiscipline} & \tablenums{0} Musical, + \tablenums{1} WallClock, \tablenums{2} EitherPerEvent, + \tablenums{3} FreelyMixed \\ + \texttt{NoteValue} & \tablenums{0} Whole, \tablenums{1} Half, + \tablenums{2} Quarter, \tablenums{3} Eighth, \tablenums{4} Sixteenth, + \tablenums{5} ThirtySecond, \tablenums{6} SixtyFourth \\ + \texttt{ClefShape} & \tablenums{0} G, \tablenums{1} F, \tablenums{2} C, + \tablenums{3} Percussion \\ + \bottomrule +\end{longtable} +\endgroup + +\subsection{Tagged unions (one byte, then the variant payload)} + +\begingroup\small +\begin{longtable}{p{1.9in} p{3.7in}} + \toprule + \textbf{Type} & \textbf{Discriminants} \\ + \midrule + \endhead + \texttt{AnchorOffset} & \tablenums{0} Musical, \tablenums{1} WallClock, + \tablenums{2} Zero \\ + \texttt{TimeAnchor} & \tablenums{0} Event, \tablenums{1} Measure, + \tablenums{2} Region, \tablenums{3} WallClock + (Section~\ref{sec:values:representative}) \\ + \texttt{EventPosition} & \tablenums{0} Musical, \tablenums{1} WallClock \\ + \texttt{ConcreteDuration} & \tablenums{0} Musical, \tablenums{1} WallClock \\ + \texttt{EventDuration} & \tablenums{0} Musical, \tablenums{1} WallClock, + \tablenums{2} Indeterminate \\ + \texttt{TimeBounds} & \tablenums{0} MusicalRange, + \tablenums{1} WallClockRange, \tablenums{2} Unbounded \\ + \texttt{PitchSpacePosition} & \tablenums{0} Cmn, \tablenums{1} Integer, + \tablenums{2} JiVector, \tablenums{3} Registered \\ + \texttt{TuningReference} & \tablenums{0} Inherit, \tablenums{1} Explicit \\ + \texttt{AcousticRealization} & \tablenums{0} Implicit, + \tablenums{1} CentsOffset, \tablenums{2} AbsoluteHz \\ + \texttt{SpellingNominal} & \tablenums{0} Cmn, \tablenums{1} Integer, + \tablenums{2} Registered \\ + \texttt{SpellingSource} & \tablenums{0} UserChosen, \tablenums{1} Inferred, + \tablenums{2} Imported, \tablenums{3} Propagated, + \tablenums{4} Analytical \\ + \texttt{SpellingScope} & \tablenums{0} Pitch, \tablenums{1} Range \\ + \texttt{SpellingDirective} & \tablenums{0} Explicit, \tablenums{1} Rule \\ + \texttt{VoiceSelector} & \tablenums{0} All, \tablenums{1} Voices \\ + \texttt{GraceKind} & \tablenums{0} Acciaccatura, \tablenums{1} Appoggiatura, + \tablenums{2} Unmeasured, \tablenums{3} MeasuredFraction \\ + \texttt{IndeterminacyKind} & \tablenums{0} Pitch, \tablenums{1} Duration, + \tablenums{2} Choice, \tablenums{3} Compound \\ + \texttt{TrajectoryEndpoint} & \tablenums{0} EventPitch, + \tablenums{1} ExplicitPitch \\ + \texttt{TrajectoryShape} & \tablenums{0} Linear, \tablenums{1} Exponential, + \tablenums{2} Curve, \tablenums{3} Stepwise \\ + \texttt{Event} & \tablenums{0} Pitched, \tablenums{1} Unpitched, + \tablenums{2} Rest, \tablenums{3} Indeterminate, \tablenums{4} Trajectory, + \tablenums{5} Graphic, \tablenums{6} Cue + (Section~\ref{sec:values:representative}) \\ + \texttt{RegionTimeModel} & \tablenums{0} Metric, \tablenums{1} Proportional, + \tablenums{2} Aleatoric \\ + \texttt{RegionContent} & \tablenums{0} StaffBased, \tablenums{1} FreeGraphic, + \tablenums{2} Hybrid \\ + \texttt{VoiceOrigin} & \tablenums{0} UserDeclared, \tablenums{1} Imported, + \tablenums{2} SystemPromoted \\ + \texttt{StaffGroupKind} & \tablenums{0} GrandStaff, \tablenums{1} Bracket, + \tablenums{2} SubBracket, \tablenums{3} Choral, \tablenums{4} Registered \\ + \texttt{TieClass} & \tablenums{0} Standard, \tablenums{1} Editorial, + \tablenums{2} CrossVoice, \tablenums{3} LaissezVibrer, + \tablenums{4} Registered \\ + \texttt{AnnotationAnchor} & \tablenums{0} Event, \tablenums{1} Range, + \tablenums{2} Region \\ + \texttt{GestureAnchoring} & \tablenums{0} Events, \tablenums{1} Range, + \tablenums{2} Free \\ + \texttt{DecompositionSource} & \tablenums{0} UserChosen, + \tablenums{1} Inferred, \tablenums{2} Imported, \tablenums{3} Propagated \\ + \texttt{TimeSignatureDisplay} & \tablenums{0} Standard, + \tablenums{1} Compound, \tablenums{2} Irrational, + \tablenums{3} MixedDenominators, \tablenums{4} None, + \tablenums{5} Symbolic \\ + \bottomrule +\end{longtable} +\endgroup + +\begin{requirement} +\label{req:binfmt:spelling-source-order} +\textbf{The \texttt{SpellingSource} / \texttt{SpellingSourceKind} trap.} +These two vocabularies name the same five provenance concepts but assign +them \emph{different} discriminants: \texttt{SpellingSourceKind} (the +C-style precedence-list element) is \tablenums{0}~UserChosen, +\tablenums{1}~Imported, \tablenums{2}~Propagated, \tablenums{3}~Inferred, +\tablenums{4}~Analytical, while \texttt{SpellingSource} (the payload-carrying +attachment provenance) is \tablenums{0}~UserChosen, \tablenums{1}~Inferred, +\tablenums{2}~Imported, \tablenums{3}~Propagated, \tablenums{4}~Analytical. +The orders differ (\texttt{Inferred} is 3 in one and 1 in the other), both +are golden-locked, and an implementation \MUSTNOT{} share one discriminant +function between them. +\end{requirement} + +\section{Representative Complete Layouts} +\label{sec:values:representative} + +The following layouts are spelled byte-by-byte both as worked examples of the +composition rules and as normative fact. Recall that inside this chapter's +codec every leaf is framed (\texttt{u32} LE length \cat{} bytes), so an +embedded 16-byte identifier occupies $4+16=20$ bytes. + +\subsection{\texttt{RationalTime}} +As a leaf inside a composite: \texttt{u32} LE length \cat{} the canonical +form of Section~\ref{sec:primitives:rationaltime} (sign \cat{} +length-prefixed big-endian numerator magnitude \cat{} length-prefixed +big-endian denominator magnitude). + +\subsection{\texttt{TimeAnchor}} +One discriminant byte, then: +\begin{description} + \item[\tablenums{0} Event] \texttt{id} (\texttt{EventId} leaf, 20) \cat{} + \texttt{offset} (\texttt{AnchorOffset}: tag byte, then for Musical a + \texttt{MusicalDuration} leaf, for WallClock a + \texttt{WallClockDuration} leaf ($4+8=12$), for Zero nothing). + \item[\tablenums{1} Measure] \texttt{id} (\texttt{MeasureId} leaf, 20) + \cat{} \texttt{position} (\texttt{MeasurePosition}, 1) \cat{} + \texttt{offset} (\texttt{AnchorOffset}). + \item[\tablenums{2} Region] \texttt{id} (\texttt{RegionId} leaf, 20) \cat{} + \texttt{edge} (\texttt{RegionEdge}, 1) \cat{} \texttt{offset} + (\texttt{AnchorOffset}). + \item[\tablenums{3} WallClock] \texttt{time} (\texttt{WallClockTime} leaf, + 12). +\end{description} + +\subsection{\texttt{Pitch}} +Positional struct: \texttt{scale\_position} \cat{} \texttt{acoustic}. +\begin{itemize} + \item \texttt{ScalePosition} = \texttt{space} (\texttt{PitchSpaceId}: NFC + string, \texttt{u32} LE length \cat{} UTF-8) \cat{} \texttt{position} + (\texttt{PitchSpacePosition}: tag byte, then Cmn = \texttt{nominal} + (\texttt{CmnNominal}, 1) \cat{} \texttt{alteration} (\texttt{i8}, 1) + \cat{} \texttt{octave} (\texttt{i8}, 1); Integer = + \texttt{space\_size} (\texttt{u16} LE, 2) \cat{} \texttt{index} + (\texttt{i32} LE, 4); JiVector = \texttt{u32} LE count \cat{} that many + \texttt{i32} LE components; Registered = a catalog-id string). + \item \texttt{AcousticPitch} = \texttt{tuning} (\texttt{TuningReference}: + tag byte; Explicit carries a \texttt{TuningSystemId} catalog-id string) + \cat{} \texttt{realization} (\texttt{AcousticRealization}: tag byte; + CentsOffset and AbsoluteHz each carry a \texttt{CanonicalF64} leaf, + $4+8=12$). +\end{itemize} + +\subsection{\texttt{Event}} +One discriminant byte (\tablenums{0}--\tablenums{6}), then the variant struct +positionally. All seven variants share the prefix \texttt{id} +(\texttt{EventId} leaf) \cat{} \texttt{voice} (\texttt{VoiceId} leaf) \cat{} +\texttt{position} (\texttt{EventPosition}) \cat{} \texttt{duration} +(\texttt{EventDuration}); the remaining fields, in order: + +\begingroup\small +\begin{longtable}{p{0.35in} p{1.35in} p{3.8in}} + \toprule + \textbf{Disc} & \textbf{Variant} & \textbf{Fields after the common prefix} \\ + \midrule + \endhead + \tablenums{0} & \texttt{Pitched} & + \texttt{pitches} \cat{} \texttt{articulations} \cat{} \texttt{dynamic} + \cat{} \texttt{ornaments} \cat{} \texttt{stem} \cat{} \texttt{grace} \\ + \tablenums{1} & \texttt{Unpitched} & + \texttt{staff\_position} \cat{} \texttt{instrument\_member} \cat{} + \texttt{articulations} \cat{} \texttt{dynamic} \cat{} \texttt{stem} + \cat{} \texttt{grace} \\ + \tablenums{2} & \texttt{Rest} & + \texttt{vertical\_position} \cat{} \texttt{visible} \\ + \tablenums{3} & \texttt{Indeterminate} & + \texttt{indeterminacy} \cat{} \texttt{hints} \\ + \tablenums{4} & \texttt{Trajectory} & + \texttt{start} \cat{} \texttt{end} \cat{} \texttt{shape} \cat{} + \texttt{display} \\ + \tablenums{5} & \texttt{Graphic} & + \texttt{graphics} \cat{} \texttt{playback\_bindings} \\ + \tablenums{6} & \texttt{Cue} & + \texttt{source} \cat{} \texttt{rendering} \\ + \bottomrule +\end{longtable} +\endgroup + +Each field encodes under this chapter's rules for its type (vectors are +\texttt{u32}-counted, options carry a presence byte, embedded identifiers are +leaves, unions carry their tag byte). + +\subsection{\texttt{Slur}} +Positional struct of three leaves: \texttt{id} (\texttt{SlurId} leaf, 20) +\cat{} \texttt{start\_event} (\texttt{EventId} leaf, 20) \cat{} +\texttt{end\_event} (\texttt{EventId} leaf, 20) --- 60 bytes total. + +\section{The \texttt{CanonicalValue} Seam} +\label{sec:values:canonical-value} + +The public per-value codec --- the seam between this document and the +Operation Catalog's value-typed payloads (Operation Catalog, +\sectionsc{Value-Typed Payloads}, requirement +\texttt{req:catalog:value-encoding}) --- is defined for exactly these +eighteen types: + +\begin{quote} +\texttt{Event}, \texttt{Rest}, \texttt{Pitch}, \texttt{IdentifiedPitch}, +\texttt{PitchSpelling}, \texttt{Tie}, \texttt{Slur}, \texttt{Beam}, +\texttt{Spanner}, \texttt{RegionTimeModel}, \texttt{TimeAnchor}, +\texttt{Region}, \texttt{StaffInstance}, \texttt{Voice}, +\texttt{DecompositionAttachment}, \texttt{SpellingSourceKind}, +\texttt{ScoreMetadata}, \texttt{MetricGrid}. +\end{quote} + +The seam introduces \textbf{no new bytes}: a value's stand-alone canonical +bytes are byte-for-byte the bytes the whole-\texttt{Score} codec embeds for +that value. Stand-alone decode applies the same validation and rejects +trailing bytes. + +\section{The Frozen-Layout Rule} +\label{sec:values:frozen} + +\begin{requirement} +\label{req:binfmt:frozen-layout} +\textbf{Frozen positional layouts (the schema-evolution keystone).} Within +schema major~0, every positional struct layout in this chapter is +\textbf{frozen}: there is no field-addition mechanism at the value level --- +no per-field framing, no optional-field encoding, no trailing-field +tolerance. Any change to any struct's field \emph{set} or field \emph{order} +is a schema-\textsc{major} change and requires a documented migration in this +document's revision history (Chapter~\ref{ch:evolution}). + +Appending a \emph{new variant} to an \textbf{open} discriminant vocabulary is +a schema-\textsc{minor} change under the rules of +Chapter~\ref{ch:evolution}. At the value layer, the open vocabularies are +those with a \texttt{Registered} escape variant --- +\texttt{PitchSpacePosition}, \texttt{SpellingNominal}, +\texttt{StaffGroupKind}, \texttt{TieClass} --- through which extensions +attach without any wire change at all; every \emph{other} union in +Section~\ref{sec:values:discriminants} (including \texttt{Event}, +\texttt{TimeAnchor}, \texttt{TimeSignatureDisplay}) is closed in v0 and may +grow only by an append ratified in a revision of this document. + +This rule ratifies the project's staging decision that data-model payload +expansion --- \texttt{SlurKind}, beam geometry, voltas, instrument bodies, +score-metadata growth, and their kin --- lands as a coordinated +schema-\textsc{major} revision of this document, not as ad-hoc field +insertion. +\end{requirement} + +% =========================================================================== +\chapter{Operation Wire Forms} +\label{ch:ops} + +This chapter pins the operation layer: envelopes, payloads, stamps, causal +contexts, effects, and materialized state. It \textbf{ratifies} the +encodings the ops crate's \texttt{DECISIONS} record held as ``provisional +canonical encoding'' (mirroring core P11-4); that provisional status is +discharged. + +Regime (a) applies, with one composition difference from +Chapter~\ref{ch:values}: the operation layer embeds \emph{fixed-width} +canonical leaves (identifiers, hashes, \texttt{ConflictId}) \textbf{raw}, +without a length prefix (\texttt{push\_canon}); only variable-width parts +carry \texttt{u32} LE length prefixes (\texttt{push\_lp\_bytes}). Sequences +(\texttt{push\_seq}) are a \texttt{u32} LE count, then each element +individually length-prefixed (\texttt{u32} LE), regardless of element width. +Text (\texttt{push\_str}) is NFC-normalized at encode time, then +length-prefixed UTF-8. Embedded graph values are the +\texttt{CanonicalValue} bytes of Section~\ref{sec:values:canonical-value}, +framed by a \texttt{u32} LE length prefix (Operation Catalog requirement +\texttt{req:catalog:value-encoding}). + +\section{The Operation Envelope} +\label{sec:ops:envelope} + +\begin{requirement} +\label{req:binfmt:envelope} +An \texttt{OperationEnvelope}'s canonical bytes are, in order: + +\begin{center} +\begin{tabular}{p{1.35in} p{3.9in}} + \toprule + \textbf{Field} & \textbf{Encoding} \\ + \midrule + \texttt{id} & \texttt{OperationId}, 16 big-endian bytes, raw \\ + \texttt{author} & \texttt{AuthorId}, 16 big-endian bytes, raw \\ + \texttt{stamp} & \texttt{OperationStamp}, 28 bytes + (Section~\ref{sec:ops:stamp}) \\ + \texttt{causal\_context} & \texttt{CausalContext} + (Section~\ref{sec:ops:causal}) \\ + \texttt{transaction} & option tag byte (\tablenums{0} absent / + \tablenums{1} present), then \texttt{TransactionId} 16 BE if present \\ + \texttt{payload} & \texttt{OperationPayload} + (Section~\ref{sec:ops:payload}) \\ + \bottomrule +\end{tabular} +\end{center} + +\textbf{Id-leads property.} The envelope's first 16 bytes \emph{are} the +\texttt{OperationId}'s canonical bytes. This is load-bearing: the operation +index (Chapter~\ref{ch:bundle}, Section~\ref{sec:bundle:opindex}) keys its +entries on those leading 16 bytes without decoding envelopes, and the +sanctioned partial read (\emph{peek}) of an envelope is exactly its leading +16 bytes. Any future envelope revision \MUST{} preserve id-leads or revise +the operation index in the same schema-major step. +\end{requirement} + +$\texttt{EnvelopeHash} = \mathrm{BLAKE3}(\texttt{MUSCENVH} \cat +\mathit{envelope\ canonical\ bytes})$ --- the full 32-byte digest. + +Envelopes are \textbf{encode-only} at this layer, deliberately: once +committed, an envelope is stored and transported as opaque bytes and is +never reconstructed into typed form by the storage layer; the peek above is +the only sanctioned partial read. (Reducers decode payloads they authored or +received through the ops layer's own typed surface; the wire contract is +that stored envelope bytes are preserved verbatim, since +\texttt{EnvelopeHash} commits to them.) + +\section{\texttt{OperationPayload} and the Meta-Operations} +\label{sec:ops:payload} + +\texttt{OperationPayload}: one discriminant byte, then the variant. + +\begin{center} +\small +\begin{tabular}{p{0.35in} p{1.55in} p{3.3in}} + \toprule + \textbf{Disc} & \textbf{Variant} & \textbf{Payload} \\ + \midrule + \tablenums{0} & \texttt{Primitive} & an \texttt{OperationKind} + (Section~\ref{sec:ops:kinds}) \\ + \tablenums{1} & \texttt{ResolveConflict} & \texttt{target} + (\texttt{ConflictId}, 16 BE) \cat{} \texttt{action} + (\texttt{ResolutionAction}) \\ + \tablenums{2} & \texttt{UndoTransaction} & \texttt{target} + (\texttt{TransactionId}, 16 BE) \cat{} \texttt{policy} + (\texttt{UndoPolicy}, 1 byte) \\ + \tablenums{3} & \texttt{ResolveEquivocation} & \texttt{target} + (\texttt{OperationId}, 16 BE) \cat{} \texttt{chosen} + (\texttt{EnvelopeHash}, 32) \\ + \bottomrule +\end{tabular} +\end{center} + +Discriminants \tablenums{0}--\tablenums{2} are the ratified v1 values; +\tablenums{3} was appended by the catalog's \sectionsc{ResolveEquivocation +(meta-operation)} entry. The vocabulary is append-only: new meta-operations +take $\geq 4$. + +\texttt{UndoPolicy} is one byte: \tablenums{0} StrictInverse, +\tablenums{1} BestEffort, \tablenums{2} Cascade. +\texttt{ResolutionAction} is one byte then an optional payload +(\texttt{app:bytes}, core requirement +\texttt{req:semops:\allowbreak resolution-action-discriminants}): \tablenums{0} +AcceptLoser, \tablenums{1} KeepWinner, \tablenums{2} Override +(\cat{} \texttt{OperationId} 16 BE), \tablenums{3} Reanchor (\cat{} +\texttt{TypedObjectId}), \tablenums{4} Dismiss, \tablenums{5} Registered +(\cat{} \texttt{ResolutionRegistryId} 16 BE). + +\section{\texttt{OperationKind}: the Primitive Wire Discriminants} +\label{sec:ops:kinds} + +\begin{requirement} +\label{req:binfmt:kind-discriminants} +The \texttt{OperationKind} wire discriminant is one byte, golden-locked to +the table below. The vocabulary is \textbf{append-only}: new primitive kinds +take discriminants past \tablenums{23}; the assignments below never change. +\end{requirement} + +Each row also pins the payload's byte layout; the field \emph{set and order} +is the Operation Catalog's (the cited section governs semantics). +``$\mathrm{lp}(T)$'' means the \texttt{u32}-LE-length-prefixed +\texttt{CanonicalValue} bytes of a \texttt{T} +(Section~\ref{sec:values:canonical-value}); bare identifiers are raw 16 +big-endian bytes; ``$\mathrm{seq}^{\uparrow}$'' is a \texttt{push\_seq} +sequence sorted ascending by canonical bytes. + +\begingroup\footnotesize +\begin{longtable}{p{0.32in} >{\raggedright\arraybackslash}p{1.5in} >{\raggedright\arraybackslash}p{2.35in} >{\raggedright\arraybackslash}p{1.35in}} + \toprule + \textbf{Disc} & \textbf{Kind} & \textbf{Payload layout} & + \textbf{Catalog section} \\ + \midrule + \endhead + \tablenums{0} & \texttt{InsertEvent} & + \texttt{staff\_instance} (16) \cat{} $\mathrm{lp}$(\texttt{Event}) & + \sectionsc{InsertEvent} \\ + \tablenums{1} & \texttt{DeleteEvent} & + \texttt{event} (16) \cat{} \texttt{TupletCompensation} & + \sectionsc{DeleteEvent} \\ + \tablenums{2} & \texttt{RespellPitch} & + \texttt{pitch} (16) \cat{} $\mathrm{lp}$(\texttt{PitchSpelling}) & + \sectionsc{RespellPitch} \\ + \tablenums{3} & \texttt{CreateCrossCutting} & + \texttt{CrossCuttingValue} & + \sectionsc{CreateCrossCutting} \\ + \tablenums{4} & \texttt{ChangeRegionTimeModel} & + \texttt{region} (16) \cat{} $\mathrm{lp}$(\texttt{RegionTimeModel}) + \cat{} $\mathrm{seq}^{\uparrow}$(\texttt{EventId}) \cat{} + \texttt{PositionRemapping} & + \sectionsc{ChangeRegion\allowbreak TimeModel} \\ + \tablenums{5} & \texttt{SetUserSystemBreak} & + \texttt{region} (16) \cat{} $\mathrm{lp}$(\texttt{TimeAnchor}) \cat{} + \texttt{present} (bool, 1) & + \sectionsc{SetUserSystemBreak} \\ + \tablenums{6} & \texttt{DeclareTransaction} & + \texttt{id} (16) \cat{} \texttt{label} (NFC string) \cat{} option tag + \cat{} \texttt{TransactionCategory} if present & + \sectionsc{DeclareTransaction} \\ + \tablenums{7} & \texttt{Registered} & + \texttt{OperationKindRegistryId} (16) \cat{} + $\mathrm{lp}$(opaque bytes) & + \sectionsc{K1 --- Framework Slots} \\ + \tablenums{8} & \texttt{ModifyEvent} & + $\mathrm{lp}$(\texttt{Event}) & + \sectionsc{ModifyEvent} \\ + \tablenums{9} & \texttt{Transpose} & + $\mathrm{seq}^{\uparrow}$(\texttt{PitchId}) \cat{} + \texttt{chromatic\_steps} (\texttt{i32} LE, 4) & + \sectionsc{Transpose} \\ + \tablenums{10} & \texttt{InsertIdentifiedPitch} & + \texttt{event} (16) \cat{} $\mathrm{lp}$(\texttt{IdentifiedPitch}) & + \sectionsc{Identified-Pitch Operations} \\ + \tablenums{11} & \texttt{DeleteIdentifiedPitch} & + \texttt{pitch} (16) & + \sectionsc{Identified-Pitch Operations} \\ + \tablenums{12} & \texttt{ModifyIdentifiedPitch} & + \texttt{pitch} (16) \cat{} $\mathrm{lp}$(\texttt{Pitch}) & + \sectionsc{Identified-Pitch Operations} \\ + \tablenums{13} & \texttt{DeleteCrossCutting} & + \texttt{structure} (\texttt{TypedObjectId}, 18/34) & + \sectionsc{DeleteCrossCutting} \\ + \tablenums{14} & \texttt{ModifyCrossCutting} & + \texttt{CrossCuttingValue} & + \sectionsc{ModifyCrossCutting} \\ + \tablenums{15} & \texttt{CreateRegion} & + $\mathrm{lp}$(\texttt{Region}) & + \sectionsc{Structural Containers} \\ + \tablenums{16} & \texttt{DeleteRegion} & + \texttt{region} (16) & + \sectionsc{Structural Containers} \\ + \tablenums{17} & \texttt{CreateStaffInstance} & + \texttt{region} (16) \cat{} $\mathrm{lp}$(\texttt{StaffInstance}) & + \sectionsc{Structural Containers} \\ + \tablenums{18} & \texttt{DeleteStaffInstance} & + \texttt{staff\_instance} (16) & + \sectionsc{Structural Containers} \\ + \tablenums{19} & \texttt{CreateVoice} & + \texttt{staff\_instance} (16) \cat{} $\mathrm{lp}$(\texttt{Voice}) & + \sectionsc{Structural Containers} \\ + \tablenums{20} & \texttt{DeleteVoice} & + \texttt{voice} (16) & + \sectionsc{Structural Containers} \\ + \tablenums{21} & \texttt{SetMetadata} & + $\mathrm{lp}$(\texttt{ScoreMetadata}) & + \sectionsc{Score Settings} \\ + \tablenums{22} & \texttt{SetMetricGrid} & + \texttt{region} (16) \cat{} option tag (\tablenums{0}/\tablenums{1}) + \cat{} $\mathrm{lp}$(\texttt{MetricGrid}) if present & + \sectionsc{Score Settings} \\ + \tablenums{23} & \texttt{SetUserPageBreak} & + \texttt{region} (16) \cat{} $\mathrm{lp}$(\texttt{TimeAnchor}) \cat{} + \texttt{present} (bool, 1) & + \sectionsc{Score Settings} \\ + \bottomrule +\end{longtable} +\endgroup + +Sub-vocabularies used above (one discriminant byte, then the listed +payload): + +\begin{description} + \item[\texttt{TupletCompensation}.] \tablenums{0} NotInTuplet (empty); + \tablenums{1} ReplaceWithRest \cat{} $\mathrm{lp}$(\texttt{Rest}); + \tablenums{2} RewriteTuplets \cat{} + $\mathrm{seq}^{\uparrow}$(\texttt{TupletId}); + \tablenums{3} CascadeDeleteTuplets \cat{} + $\mathrm{seq}^{\uparrow}$(\texttt{TupletId}). + \item[\texttt{CrossCuttingValue}.] \tablenums{0} Tie, \tablenums{1} Slur, + \tablenums{2} Beam, \tablenums{3} Spanner; in every case the tag is + followed by $\mathrm{lp}$(the typed structure's \texttt{CanonicalValue} + bytes). + \item[\texttt{PositionRemapping}.] \tablenums{0} PreserveTime (empty); + \tablenums{1} Reassign \cat{} \texttt{u32} LE entry count \cat{} + entries, each \texttt{EventId} (16, raw) \cat{} + $\mathrm{lp}$(\texttt{MusicalPosition}), ascending by \texttt{EventId}. + \item[\texttt{TransactionCategory}.] \tablenums{0} NoteEntry, + \tablenums{1} Structural, \tablenums{2} Layout, \tablenums{3} Import, + \tablenums{4} Registered \cat{} \texttt{OperationKindRegistryId} (16 BE) + --- governed by \texttt{app:bytes} (core requirement + \texttt{req:semops:transaction-category}). +\end{description} + +\texttt{OperationKind} is encode-only at the storage boundary, like the +envelope that carries it. + +\section{\texttt{OperationKindTag}: a Separate Discriminant Space} +\label{sec:ops:kind-tag} + +\begin{requirement} +\label{req:binfmt:kind-tag} +\texttt{OperationKindTag} --- the payload-free projection of an operation +kind, stored by edit barriers +(Chapter~\ref{ch:barriers}) --- has its \textbf{own} discriminant space, +assigned independently of Section~\ref{sec:ops:kinds}, with both encode and +validating decode. One byte; only \texttt{Registered} carries a payload (its +\texttt{OperationKindRegistryId}, 16 big-endian bytes, total 17). Unknown +discriminants and wrong lengths are decode errors. Append-only past +\tablenums{23}. +\end{requirement} + +\begingroup\small +\begin{longtable}{p{0.5in} p{2.0in} p{0.5in} p{2.0in}} + \toprule + \textbf{Disc} & \textbf{Tag} & \textbf{Disc} & \textbf{Tag} \\ + \midrule + \endhead + \tablenums{0} & \texttt{InsertEvent} & \tablenums{12} & \texttt{DeleteStaffInstance} \\ + \tablenums{1} & \texttt{DeleteEvent} & \tablenums{13} & \texttt{SetUserSystemBreak} \\ + \tablenums{2} & \texttt{ModifyEvent} & \tablenums{14} & \texttt{SetUserPageBreak} \\ + \tablenums{3} & \texttt{RespellPitch} & \tablenums{15} & \texttt{DeclareTransaction} \\ + \tablenums{4} & \texttt{Transpose} & \tablenums{16} & \texttt{Registered} \\ + \tablenums{5} & \texttt{CreateCrossCutting} & \tablenums{17} & \texttt{InsertIdentifiedPitch} \\ + \tablenums{6} & \texttt{DeleteCrossCutting} & \tablenums{18} & \texttt{DeleteIdentifiedPitch} \\ + \tablenums{7} & \texttt{ModifyCrossCutting} & \tablenums{19} & \texttt{ModifyIdentifiedPitch} \\ + \tablenums{8} & \texttt{ChangeRegionTimeModel} & \tablenums{20} & \texttt{CreateVoice} \\ + \tablenums{9} & \texttt{InsertRegion} & \tablenums{21} & \texttt{DeleteVoice} \\ + \tablenums{10} & \texttt{DeleteRegion} & \tablenums{22} & \texttt{SetMetadata} \\ + \tablenums{11} & \texttt{InsertStaffInstance} & \tablenums{23} & \texttt{SetMetricGrid} \\ + \bottomrule +\end{longtable} +\endgroup + +\textbf{Naming mapping.} The kind-to-tag projection renames two pairs: +\texttt{OperationKind::\allowbreak CreateRegion} projects to +\texttt{OperationKindTag::\allowbreak InsertRegion}, and +\texttt{OperationKind::\allowbreak CreateStaffInstance} projects to +\texttt{OperationKindTag::\allowbreak InsertStaffInstance}. The mismatch is +intentional +(the tag space predates the M2c naming) and is pinned here so barrier +authors target the right tag. + +\section{Stamps and Causal Contexts} +\label{sec:ops:stamp} + +\texttt{HybridLogicalClock}: \texttt{physical\_time} (\texttt{WallClockTime}, +\texttt{i64} LE, 8) \cat{} \texttt{logical\_counter} (\texttt{u32} LE, 4). +\texttt{OperationStamp}: \texttt{hlc} (12) \cat{} \texttt{id} +(\texttt{OperationId}, 16 BE) --- \textbf{28 bytes} total, fixed width. The +canonical reduction tuple orders stamps as $(\mathit{physical\_time}, +\mathit{logical\_counter}, \mathit{replica}, \mathit{counter})$, ascending; +the replica comparison equals big-endian byte order. + +\label{sec:ops:causal} +\texttt{CausalContext} (dotted version vector): + +\begin{center} +\begin{tabular}{p{0.7in} p{4.55in}} + \toprule + \textbf{Field} & \textbf{Encoding} \\ + \midrule + vector & \texttt{u32} LE entry count \cat{} entries, each + \texttt{replica} (8 BE) \cat{} \texttt{counter} (\texttt{u64} LE, 8), + ascending by replica \\ + dots & \texttt{u32} LE count \cat{} \texttt{OperationId}s (16 BE each), + ascending \\ + \bottomrule +\end{tabular} +\end{center} + +The vector is \emph{zero-based-floor} (P11-C7): an entry $(r, c)$ covers +counters $0..=c$ of replica $r$; absence of a replica covers nothing. + +\section{Effects, Conflicts, Anomalies, and Materialized State} +\label{sec:ops:effects} + +These types are canonical \emph{materialized} facts: they appear in +\texttt{MaterializedState}'s canonical bytes, so their discriminants and +layouts are normative wire facts even though they are never stored inside +envelopes. All decode validation is performed by the ops layer's validating +decoder; unknown discriminants, bad lengths, non-canonical orders, and +trailing bytes are decode errors. + +\begingroup\footnotesize +\begin{longtable}{>{\raggedright\arraybackslash}p{1.6in} p{4.1in}} + \toprule + \textbf{Type} & \textbf{Layout (tag byte, then payload)} \\ + \midrule + \endhead + \texttt{OperationEffect} & + \tablenums{0} Applied (empty); + \tablenums{1} AppliedWithRepair \cat{} seq(\texttt{RepairRecord}); + \tablenums{2} Conflicted \cat{} \texttt{ConflictId} (16 BE); + \tablenums{3} TombstonedTarget \cat{} \texttt{TypedObjectId}; + \tablenums{4} NoOp \cat{} \texttt{NoOpReason}. \\ + \texttt{NoOpReason} & + \tablenums{0} TargetTombstoned; \tablenums{1} AlreadyApplied; + \tablenums{2} SupersededByLaterOperation \cat{} \texttt{OperationId} + (16 BE); \tablenums{3} PreconditionFailedUnderReduction \cat{} + \texttt{PreconditionFailureReason}; \tablenums{4} TransactionConflict. \\ + \texttt{Precondition\allowbreak FailureReason} & + \tablenums{0} TargetMissing; \tablenums{1} TargetTombstoned; + \tablenums{2} WrongRegionTimeModel; + \tablenums{3} TupletCompensationInvalid; + \tablenums{4} EventDurationInvalid; \tablenums{5} PositionOutsideRegion; + \tablenums{6} PitchSpaceMismatch; \tablenums{7} VoiceMissing; + \tablenums{8} ExtensionPrecondition \cat{} id (16 BE); + \tablenums{9} Registered \cat{} id (16 BE); + \tablenums{10} ContainerNotEmpty. \\ + \texttt{RepairRecord} & + (struct) \texttt{kind} (\texttt{RepairKind}) \cat{} \texttt{target} + (\texttt{TypedObjectId}). \\ + \texttt{RepairKind} & + \tablenums{0} Reanchored \cat{} \texttt{from} (\texttt{TypedObjectId}) + \cat{} \texttt{to} (\texttt{TypedObjectId}) \cat{} + \texttt{ReanchorReason}; + \tablenums{1} SpannerTruncated \cat{} seq(\texttt{TypedObjectId}); + \tablenums{2} Orphaned; \tablenums{3} CascadeDeleted; + \tablenums{4} AttachmentTombstoned; + \tablenums{5} VoicePromoted \cat{} \texttt{from} (\texttt{VoiceId}, + 16 BE) \cat{} \texttt{to} (\texttt{VoiceId}, 16 BE); + \tablenums{6} TupletCompensated \cat{} \texttt{TupletCompensationKind}; + \tablenums{7} Registered \cat{} id (16 BE). \\ + \texttt{ReanchorReason} & + \tablenums{0} SameVoiceNearer; \tablenums{1} SameStaffInstanceNearer; + \tablenums{2} SameStaffNearer; \tablenums{3} SameRegionNearer; + \tablenums{4} ExplicitFallback; + \tablenums{5} DeclaredByExtension \cat{} id (16 BE). \\ + \texttt{TupletCompensationKind} & + \tablenums{0} ReplaceWithRest; \tablenums{1} RewriteTuplets; + \tablenums{2} CascadeDeleteTuplets. (No payload; distinct from the + payload-carrying \texttt{TupletCompensation} of + Section~\ref{sec:ops:kinds}.) \\ + \texttt{PendingReason} & + tag \cat{} blocker (\texttt{OperationId}, 16 BE) in every variant: + \tablenums{0} MissingCausalPredecessor; \tablenums{1} + DependsOnEquivocated; \tablenums{2} DependsOnExcluded; + \tablenums{3} DependsOnPending; \tablenums{4} HaltedBySystemCollision. \\ + \texttt{ConflictKind} & + \tablenums{0} StructuralFieldCollision \cat{} \texttt{winner} (16 BE) + \cat{} \texttt{loser} (16 BE) \cat{} \texttt{FieldPath} (NFC string); + \tablenums{1} TransactionConflict \cat{} \texttt{transaction} (16 BE) + \cat{} $\mathrm{seq}^{\uparrow}$(\texttt{OperationId}); + \tablenums{2} TombstonedTarget \cat{} \texttt{TypedObjectId} \cat{} + \texttt{OperationId} (16 BE); + \tablenums{3} ReanchorFailure \cat{} \texttt{original\_referent} + (\texttt{TypedObjectId}) \cat{} \texttt{referencing\_object} + (\texttt{TypedObjectId}); + \tablenums{4} TimeModelMigrationFailure \cat{} \texttt{region} (16 BE) + \cat{} $\mathrm{seq}^{\uparrow}$(\texttt{TypedObjectId}); + \tablenums{5} ExtensionConflict \cat{} \texttt{kind\_id} (16 BE) \cat{} + $\mathrm{lp}$(opaque details). \\ + \texttt{ConflictResolutionState} & + \tablenums{0} Unresolved; \tablenums{1} Resolved \cat{} \texttt{by} + (16 BE) \cat{} \texttt{ResolutionAction}; \tablenums{2} Dismissed \cat{} + \texttt{by} (16 BE). \\ + \texttt{ConflictRecord} & + (struct) \texttt{id} (\texttt{ConflictId}, 16 BE) \cat{} + seq(\texttt{caused\_by}: \texttt{OperationId}, stored sorted) \cat{} + \texttt{kind} \cat{} seq(\texttt{affected\_objects}: + \texttt{TypedObjectId}, stored sorted) \cat{} + \texttt{resolution\_state}. \\ + \texttt{IntegrityAnomaly} & + (struct) \texttt{id} (\texttt{IntegrityAnomalyId}, 16 BE) \cat{} + \texttt{kind}. \\ + \texttt{IntegrityAnomalyKind} & + \tablenums{0} SystemIdentifierCollision \cat{} \texttt{ObjectKind} + \cat{} \texttt{colliding\_counter} (\texttt{u64} LE) \cat{} the two + input-set blobs, each $\mathrm{lp}$(bytes), emitted lo${}\leq{}$hi by + byte comparison; + \tablenums{1} OperationSlotEquivocated \cat{} \texttt{OperationId} + (16 BE); + \tablenums{2} ReplicaStreamQuarantined \cat{} \texttt{replica} (8 BE) + \cat{} \texttt{first\_bad\_counter} (\texttt{u64} LE); + \tablenums{3} Registered \cat{} id (16 BE). \\ + \texttt{AnomalousReplicaSegment} & + (struct) \texttt{replica} (8 BE) \cat{} \texttt{first\_bad\_counter} + (\texttt{u64} LE) \cat{} \texttt{ReplicaAnomalyReason} + (\tablenums{0} HlcMonotonicityViolation \cat{} two + \texttt{OperationId}s; \tablenums{1} Registered \cat{} id 16 BE) + \cat{} seq(\texttt{excluded}: \texttt{OperationId}, ascending counter). \\ + \texttt{FieldPath} & + an NFC string (\texttt{u32} LE length \cat{} UTF-8). \\ + \texttt{ObjectState} & + \tablenums{0} Live (empty); \tablenums{1} Tombstoned \cat{} + \texttt{deleted\_by} (\texttt{OperationId}, 16 BE) \cat{} + \texttt{minted\_by} (\texttt{OperationId}, 16 BE). \\ + \texttt{ObjectKind} (ops) & + \tablenums{0} Voice; \tablenums{1} Pitch; \tablenums{2} Registered + \cat{} \texttt{OperationKindRegistryId} (16 BE) --- governed by + \texttt{app:bytes} (core requirement + \texttt{req:graph:object-kind-vocab}). Distinct from the barrier layer's + 2-byte \texttt{ObjectKind} (Chapter~\ref{ch:barriers}). \\ + \bottomrule +\end{longtable} +\endgroup + +\subsection{\texttt{MaterializedState}} +\label{sec:ops:materialized} + +The canonical bytes of a reduction's materialized state are eight sections, +concatenated; every section is \texttt{u32}-LE-counted (the conflict +registry carries its own count) and in the stated normative order, so the +bytes are identical across any permutation of the input operation set: + +\begin{enumerate} + \item \textbf{effects} --- count, then per entry \texttt{OperationId} + (16 BE, raw) \cat{} $\mathrm{lp}$(\texttt{OperationEffect}); in + canonical reduction order; + \item \textbf{conflict registry} --- a seq of + $\mathrm{lp}$(\texttt{ConflictRecord}), ascending \texttt{ConflictId}; + \item \textbf{anomalies} --- count, then each + $\mathrm{lp}$(\texttt{IntegrityAnomaly}), ascending + \texttt{IntegrityAnomalyId}; + \item \textbf{objects} --- count, then per entry \texttt{TypedObjectId} + (raw) \cat{} \texttt{ObjectState}, ascending \texttt{TypedObjectId}; + \item \textbf{spellings} --- count, then per entry \texttt{PitchId} + (16 BE, raw) \cat{} $\mathrm{lp}$(\texttt{PitchSpelling}), ascending + \texttt{PitchId}; + \item \textbf{breaks} --- count, then per entry \texttt{RegionId} + (16 BE, raw) \cat{} \texttt{MusicalPosition} (raw \texttt{RationalTime} + form, self-describing, \emph{not} leaf-framed) \cat{} \texttt{present} + (bool, 1); ascending $(\mathit{region}, \mathit{position})$; + \item \textbf{page breaks} --- same shape and order as breaks; + \item \textbf{pending} --- count, then per entry \texttt{OperationId} + (16 BE, raw) \cat{} \texttt{PendingReason}, ascending + \texttt{OperationId}. +\end{enumerate} + +Decode is fully validating (orders, tags, lengths, trailing bytes) and +rejects non-canonical input. + +\section{v0 Payloads Have No Wire Form} +\label{sec:ops:v0} + +The prototype's v0 identifier-projection payload types are an +\textbf{in-memory migration guard only}: they carry no canonical encoding, +and no v0 wire form was ever shipped. The v0${\to}$v1 migration is +\emph{semantic} --- typed value reconstruction, specified in the Operation +Catalog's \sectionsc{v0 $\rightarrow$ v1 Payload Migration} chapter --- not a +byte-level translation, and nothing in this document defines bytes for a v0 +payload. + +% =========================================================================== +\chapter{Bundle Physical Layout} +\label{ch:bundle} + +The physical file: the fixed prelude, chunks, blocks, the manifest, and the +operation index. This chapter \textbf{ratifies} the bundle crate's +provisional encodings (its \texttt{DECISIONS} entries P11-D2, P11-D4, and +P11-D5 pending-companion status is discharged) and the operation-index +byte form (P12-D1). Structural \emph{semantics} --- superblock selection, +commit protocol, recovery, retention --- are core specification Chapter~8; +this chapter pins bytes only. Regime (a) applies except where a table says +otherwise. + +\section{The Fixed Header (64 bytes)} +\label{sec:bundle:header} + +Offset 0 of every bundle. Written at creation, never rewritten within a +format major version. All integers little-endian. + +\begingroup\small +\begin{longtable}{p{0.8in} p{1.7in} p{3.1in}} + \toprule + \textbf{Range} & \textbf{Field} & \textbf{Value / rule} \\ + \midrule + \endhead + \tablenums{0..8} & magic & \texttt{MUSCBND\textbackslash0} (8 bytes, ASCII, + trailing NUL) \\ + \tablenums{8..10} & \texttt{format\_major} (\texttt{u16}) & \tablenums{0} + in this version; readers reject other values \\ + \tablenums{10..12} & \texttt{format\_minor} (\texttt{u16}) & \tablenums{1} + written in this version \\ + \tablenums{12..16} & \texttt{header\_length} (\texttt{u32}) & + \tablenums{64}; readers reject other values \\ + \tablenums{16..24} & \texttt{superblock\_a\_offset} (\texttt{u64}) & + \tablenums{64}; readers reject other values \\ + \tablenums{24..32} & \texttt{superblock\_b\_offset} (\texttt{u64}) & + \tablenums{320}; readers reject other values \\ + \tablenums{32..48} & \texttt{file\_uuid} & 16 opaque bytes \\ + \tablenums{48..60} & reserved & written zero; ignored on read \\ + \tablenums{60..64} & \texttt{header\_crc} & CRC-32C of bytes + \tablenums{0..60}, \texttt{u32} LE \\ + \bottomrule +\end{longtable} +\endgroup + +Readers \MUST{} verify the magic and the CRC before consulting any other part +of the file. + +\section{The Superblock Slots (256 bytes each)} +\label{sec:bundle:superblock} + +Two slots, at offsets 64 (A) and 320 (B); the only mutable on-disk objects. +Selection \emph{semantics} (highest valid committed generation, the +equal-generation rule, torn-write fallback) are core Chapter~8, +\sectionsc{Superblock Selection}; the bytes: + +\begingroup\small +\begin{longtable}{p{0.9in} p{2.15in} p{2.55in}} + \toprule + \textbf{Range} & \textbf{Field} & \textbf{Encoding} \\ + \midrule + \endhead + \tablenums{0..8} & magic & \texttt{MUSCSUPR} (8 ASCII bytes) \\ + \tablenums{8..16} & \texttt{generation} & \texttt{u64} LE \\ + \tablenums{16..24} & \texttt{manifest\_offset} & \texttt{u64} LE \\ + \tablenums{24..32} & \texttt{manifest\_length} & \texttt{u64} LE (also the + uncompressed length; the manifest is mandatorily uncompressed) \\ + \tablenums{32..64} & \texttt{manifest\_hash} & 32 raw digest bytes \\ + \tablenums{64..68} & \texttt{manifest\_schema\_version} & + \texttt{SchemaVersion} (\texttt{u16} LE \cat{} \texttt{u16} LE) \\ + \tablenums{68..72} & \texttt{reduction\_algorithm\_version} & + \texttt{u32} LE \\ + \tablenums{72..92} & \texttt{profile\_id} & 20 bytes: \texttt{u32} LE + discriminant (\tablenums{0} Full, \tablenums{1} ReadOnly, + \tablenums{2} Lite, \tablenums{3} Custom) \cat{} + \texttt{ProfileRegistryId} (16 raw bytes; writers \MUST{} emit zero + unless Custom, readers ignore it unless Custom). Core requirement + \texttt{req:format:profileid-discriminants}. \\ + \tablenums{92..100} & \texttt{commit\_state} & two \texttt{u32} LE words: + Committed $= (\tablenums{0}, \tablenums{0})$; any tag + ${}\neq \tablenums{0}$ decodes as Reserved(value) and the slot is + invalid for ordinary selection. Writers in this version \MUST{} produce + only Committed. \\ + \tablenums{100..108} & \texttt{commit\_timestamp} & \texttt{i64} LE + nanoseconds; advisory --- selection never consults it \\ + \tablenums{108..252} & reserved & written zero; ignored on read \\ + \tablenums{252..256} & \texttt{superblock\_crc} & CRC-32C of bytes + \tablenums{0..252}, \texttt{u32} LE \\ + \bottomrule +\end{longtable} +\endgroup + +\section{Chunks} +\label{sec:bundle:chunks} + +The bundle body begins at +$\texttt{BODY\_START} = 320 + 256 = \tablenums{576}$. A chunk's on-disk form +is its raw (possibly compressed) payload bytes at a byte offset --- +\textbf{no per-chunk length prefix, magic, or trailer on disk}; the offset, +lengths, compression, and hash live in the referencing \texttt{ChunkRef}. A +chunk reference whose offset is below \texttt{BODY\_START} is malformed. + +\textbf{Content hash preimage} (core Chapter~8, \sectionsc{Domain-Separated +Preimages}; governs identity): +\[ + \mathrm{BLAKE3}\bigl(\mathit{domain} \cat \mathit{kind}\,(1) \cat + \mathit{schema}\,(4) \cat \mathit{uncompressed\_length}\, + (\texttt{u64}\ \mathrm{LE}) \cat \mathit{payload}\bigr) +\] +where $\mathit{domain}$ is \texttt{MUSCMANI} for \texttt{Manifest} chunks and +\texttt{MUSCCHNK} otherwise. Compression is \emph{not} in the preimage. +Blob chunks are addressed by the bare \texttt{BlobId} form instead +(Chapter~\ref{ch:primitives}). + +\textbf{\texttt{ChunkKind}} is a single byte, a \textbf{closed} vocabulary +(no \texttt{Registered} variant; core requirement +\texttt{req:format:chunkkind-discriminants}): \tablenums{0} +OperationEnvelopeBlock, \tablenums{1} OperationIndex, \tablenums{2} +Snapshot, \tablenums{3} Blob, \tablenums{4} ExtensionData, \tablenums{5} +TextProjection, \tablenums{6} LayoutCache, \tablenums{7} IntegrityIndex, +\tablenums{8} Manifest. + +\textbf{\texttt{CompressionAlgorithm}} is a fixed two bytes, discriminant +\cat{} parameter: None $= (\tablenums{0},\tablenums{0})$; +Zstd$\{$level$\}$ $= (\tablenums{1}, \mathit{level})$; Reserved$(v)$ $= +(\tablenums{2}, v)$. \texttt{None} is \emph{not} a bare tag --- its zero +parameter byte is always present. + +\textbf{Read rules.} Writers in this format version emit \texttt{None} only; +\emph{reading} zstd at any level is a conformance \MUST{}. A zstd payload is +decompressed into a buffer sized \emph{exactly} by the declared +\texttt{uncompressed\_length} (checked against the reader's resource policy +before allocation): a stream that would exceed the declaration, ends short of +it, or carries trailing garbage is corruption. After decompression the +content hash is verified over the uncompressed bytes, and +$\mathit{id} = \mathit{hash}$ is checked. A chunk whose declared schema +major differs from the reader's supported major is rejected +(Chapter~\ref{ch:evolution}). \texttt{Reserved} compression is rejected. +The \textbf{manifest chunk is mandatorily uncompressed}: a compressed +manifest reference is rejected before any bytes are read. The reference +reader bounds any single chunk at 256\,MiB +(\texttt{MAX\_CHUNK\_BYTES}); the bound is reader policy, not a wire fact. + +\subsection{\texttt{ChunkRef} (95 bytes)} +\label{sec:bundle:chunkref} + +\begingroup\small +\begin{longtable}{p{0.9in} p{1.9in} p{2.8in}} + \toprule + \textbf{Range} & \textbf{Field} & \textbf{Encoding} \\ + \midrule + \endhead + \tablenums{0..32} & \texttt{id} & 32 raw digest bytes \\ + \tablenums{32..33} & \texttt{kind} & \texttt{ChunkKind} byte \\ + \tablenums{33..37} & \texttt{schema\_version} & \texttt{u16} LE \cat{} + \texttt{u16} LE \\ + \tablenums{37..45} & \texttt{offset} & \texttt{u64} LE \\ + \tablenums{45..53} & \texttt{compressed\_length} & \texttt{u64} LE \\ + \tablenums{53..61} & \texttt{uncompressed\_length} & \texttt{u64} LE \\ + \tablenums{61..63} & \texttt{compression} & 2 bytes \\ + \tablenums{63..95} & \texttt{hash} & 32 raw digest bytes (restates + \texttt{id}) \\ + \bottomrule +\end{longtable} +\endgroup + +The canonical sort key for chunk-reference collections is +$(\mathit{kind\ discriminant}, \mathit{hash}, \mathit{offset})$, ascending +--- the Appendix-D chunk-reference order. Every set-valued +\texttt{ChunkRef} field in this chapter is sorted by it and deduplicated +before encoding. + +\section{Operation-Envelope Block Payloads} +\label{sec:bundle:blocks} + +The uncompressed payload of an \texttt{OperationEnvelopeBlock} chunk: + +\begin{center} +\texttt{u32} LE envelope count \cat{} per envelope +\{\texttt{u32} LE byte length \cat{} envelope bytes\} +\end{center} + +Envelope bytes are opaque to the bundle (their internal form is +Chapter~\ref{ch:ops}). Each envelope's offset --- the byte offset of its +\emph{first content byte} within the uncompressed block payload, with its +length prefix at $\mathit{offset}-4$ --- is deterministically recoverable +from this framing alone; it is the coordinate the operation index records. +Writers \SHOULD{} begin a new block rather than let an uncompressed payload +exceed 1\,MiB (an individual envelope larger than that occupies its own +block); readers \MUST{} accept blocks up to the active profile's bound +(default 64\,MiB). Block boundaries are storage artifacts: the envelope set +is the union across blocks. + +\section{The Manifest} +\label{sec:bundle:manifest} + +On-disk manifest chunk payload: + +\begin{center} +\texttt{manifest\_id} (16 bytes, \texttt{u128} \emph{little-endian}) \cat{} +\emph{body} +\end{center} + +(The little-endian on-disk field is a deliberate, golden-locked quirk: the +\emph{derivation} truncates big-endian like every content-derived id, but +the bundle codec serializes the resulting \texttt{u128} under its +little-endian integer rule.) + +\begin{requirement} +\label{req:binfmt:manifest-id} +Restating core requirement \texttt{req:format:manifest-id}, which governs: +\[ + \texttt{ManifestId} = \mathrm{trunc128}\bigl(\mathrm{BLAKE3}( + \texttt{MUSCMNIF} \cat \mathit{document\_id} \cat + \mathit{generation} \cat \mathit{body}\bigr)\bigr) +\] +with $\mathit{document\_id}$ as its 16 raw bytes, $\mathit{generation}$ as +\texttt{u64} little-endian, and $\mathit{body}$ the complete manifest body +below (which itself opens with \texttt{document\_id} and +\texttt{generation} --- the double commitment is intentional and locked). +Writers re-derive the id from the body at encode time; decoders verify it. +\end{requirement} + +\textbf{The body} is a positional struct of thirteen fields: + +\begingroup\small +\begin{longtable}{p{0.3in} p{1.9in} p{3.45in}} + \toprule + \textbf{\#} & \textbf{Field} & \textbf{Encoding and canonical order} \\ + \midrule + \endhead + \tablenums{1} & \texttt{document\_id} & 16 raw bytes \\ + \tablenums{2} & \texttt{lineage\_id} & option tag \cat{} 16 raw bytes if + present \\ + \tablenums{3} & \texttt{generation} & \texttt{u64} LE \\ + \tablenums{4} & \texttt{operation\_roots} & \texttt{u32} LE count \cat{} + \texttt{ChunkRef}s, sorted by the canonical chunk-reference key, + deduplicated \\ + \tablenums{5} & \texttt{operation\_block\_summaries} & \texttt{u32} LE + count \cat{} entries \{\texttt{chunk\_id} (32) \cat{} + \texttt{OperationBlockSummary}\}, ascending \texttt{chunk\_id} \\ + \tablenums{6} & \texttt{operation\_index\_root} & option tag \cat{} + \texttt{ChunkRef} \\ + \tablenums{7} & \texttt{canonical\_base} & option tag \cat{} + \texttt{SnapshotRef} \\ + \tablenums{8} & \texttt{acceleration\_snapshots} & \texttt{u32} LE count + \cat{} \texttt{SnapshotRef}s, sorted ascending by their full encoded + bytes, deduplicated \\ + \tablenums{9} & \texttt{blob\_roots} & \texttt{u32} LE count \cat{} + \texttt{BlobRef}s, sorted ascending by encoded bytes, deduplicated \\ + \tablenums{10} & \texttt{profile\_declarations} & \texttt{u32} LE count + \cat{} \texttt{ProfileDeclaration}s, sorted by the key + $(\texttt{profile\_id}, \texttt{version})$ with \texttt{SemVer} compared + \emph{numerically}, deduplicated \\ + \tablenums{11} & \texttt{extension\_declarations} & \texttt{u32} LE count + \cat{} \texttt{ExtensionDeclaration}s, sorted by + $(\texttt{extension\_id}, \texttt{version})$, \texttt{SemVer} numeric, + deduplicated \\ + \tablenums{12} & \texttt{text\_projection\_root} & option tag \cat{} + \texttt{ChunkRef} \\ + \tablenums{13} & \texttt{integrity\_root} & option tag \cat{} + \texttt{ChunkRef} \\ + \bottomrule +\end{longtable} +\endgroup + +Sub-records, positionally: + +\begin{description} + \item[\texttt{OperationBlockSummary}] = \texttt{dvv\_summary} + (\texttt{FrontierBytes}: \texttt{u32}-LE-prefixed opaque bytes) \cat{} + \texttt{min\_stamp} (\texttt{u32}-LE-prefixed opaque stamp bytes) \cat{} + \texttt{max\_stamp} (same). The contents are ops-computed + (Chapter~\ref{ch:ops}); the bundle carries them verbatim. + \item[\texttt{SnapshotRef}] = \texttt{snapshot\_id} (16 raw) \cat{} + \texttt{covers\_causal\_frontier} (\texttt{FrontierBytes}) \cat{} + \texttt{reduction\_algorithm\_version} (\texttt{u32} LE) \cat{} + \texttt{profile\_id} (20 bytes, as in the superblock) \cat{} + \texttt{root} (\texttt{ChunkRef}, 95) \cat{} \texttt{hash} (32 raw). + \item[\texttt{BlobRef}] = \texttt{blob\_id} (32 raw) \cat{} + \texttt{media\_type} (\texttt{u32}-LE-prefixed ASCII; decode validates a + well-formed RFC~6838 \texttt{type/subtype} restricted name) \cat{} + \texttt{offset} (\texttt{u64} LE) \cat{} \texttt{compressed\_length} + (\texttt{u64} LE) \cat{} \texttt{uncompressed\_length} (\texttt{u64} LE) + \cat{} \texttt{compression} (2) \cat{} \texttt{hash} (32 raw) \cat{} + option tag \cat{} \texttt{declared\_max\_uncompressed\_length} + (\texttt{u64} LE) if present. + \item[\texttt{ProfileDeclaration}] = \texttt{profile\_id} (20) \cat{} + \texttt{version} (\texttt{SemVer}, 12) \cat{} \texttt{constraints} + (\texttt{ProfileConstraints} = + \texttt{max\_uncompressed\_block\_size} (\texttt{u64} LE) \cat{} + \texttt{RetentionPolicy}). \texttt{RetentionPolicy} = + \texttt{retain\_previous\_manifests} (\texttt{u32} LE) \cat{} option tag + \cat{} \texttt{retain\_duration} (\texttt{i64} LE) if present \cat{} + \texttt{retain\_named\_checkpoints} (bool, 1). + \item[\texttt{ExtensionDeclaration}] = \texttt{extension\_id} (16 raw) + \cat{} \texttt{version} (\texttt{SemVer}, 12) \cat{} \texttt{required} + (bool, 1) \cat{} \texttt{u32} LE count \cat{} + \texttt{preserved\_chunk\_roots} (\texttt{ChunkRef}s, canonical order, + deduplicated) \cat{} \texttt{affected\_object\_kinds} + (\texttt{u32}-LE-prefixed opaque blob) \cat{} \texttt{edit\_barriers} + (\texttt{u32}-LE-prefixed opaque blob). The two blobs' internal form is + Chapter~\ref{ch:barriers}; the bundle preserves them verbatim. +\end{description} + +\begin{requirement} +\label{req:binfmt:manifest-canonical} +\textbf{Reject non-canonical manifests.} A decoder \MUST{} accept a manifest +payload only if re-encoding the decoded manifest reproduces the input +byte-for-byte. This single check subsumes: the stored \texttt{manifest\_id} +matching the body-derived id, every set-valued vector being in its canonical +order with no duplicates, and every optional field using presence byte +\tablenums{0}/\tablenums{1}. Unsorted, duplicated, or wrongly-identified +manifest bytes are malformed --- never re-sorted or repaired. +\end{requirement} + +\section{The Operation Index} +\label{sec:bundle:opindex} + +\begin{requirement} +\label{req:binfmt:opindex} +\textbf{Operation-index payload (ratifies P12-D1).} The uncompressed payload +of an \texttt{OperationIndex} chunk is: + +\begin{center} +\texttt{u32} LE \texttt{block\_count} \cat{} that many \texttt{ChunkRef}s +(95 bytes each, strictly ascending canonical order) \cat{} +\texttt{u32} LE \texttt{entry\_count} \cat{} that many entries, each +\{\texttt{id} (16 raw operation-id bytes) \cat{} \texttt{block} +(\texttt{u32} LE ordinal into the block vector) \cat{} \texttt{offset} +(\texttt{u32} LE)\}, strictly ascending by \texttt{id} bytes. +\end{center} + +The empty index is exactly 8 zero bytes. \texttt{offset} is the byte offset +of the envelope's \emph{first content byte} within the uncompressed payload +of the named block (the envelope's \texttt{u32} length prefix sits at +$\mathit{offset}-4$) --- well-defined by the id-leads property +(Requirement~\ref{req:binfmt:envelope}) and the block framing +(Section~\ref{sec:bundle:blocks}). + +\textbf{One slot per id.} Strict ascent makes duplicate ids unrepresentable: +an index payload containing two entries with equal id bytes is malformed. +Equivocation candidates (multiple envelopes claiming one +\texttt{OperationId}) live \emph{inside} the operation set's slot model +(core Chapter~6), never as duplicate index rows. + +\textbf{Staleness.} An index \emph{covers} a manifest iff its block vector +equals the manifest's deduplicated, canonically sorted +\texttt{operation\_roots} under \textbf{full \texttt{ChunkRef} equality} --- +every field, not just the content hash, since the index hands out its stored +references for reading. A reader that finds the index stale \MUST{} reject +it and rebuild from the blocks. + +A rejected or stale index is \textbf{never bundle corruption}: the index is +a non-canonical accelerator, and rebuild-from-blocks is always sound. + +Decoders \MUST{} reject: unsorted or duplicated blocks or entry ids, a block +reference whose kind is not \texttt{OperationEnvelopeBlock}, an entry whose +block ordinal is out of range, and trailing bytes. +\end{requirement} + +The core specification's commit-time \SHOULD{} --- refresh the index when +the operation log has ``grown significantly'' since it was built --- has an +\textbf{implementation-defined} threshold in v0: this document deliberately +does not pin a number, and conforming writers may use any policy (including +always or never refreshing at commit), because the index is non-canonical. + +\begin{openquestion} +Whether to pin a normative refresh threshold (e.g.\ a block-count or +byte-size ratio) or leave it permanently implementation-defined. Leaving it +open costs only lookup performance on stale-index bundles; pinning it too +early would constrain writers for no interoperability gain. Revisit when a +second writer implementation exists. +\end{openquestion} + +% =========================================================================== +\chapter{Extension Declaration Blobs and Edit Barriers} +\label{ch:barriers} + +The two opaque blobs a manifest \texttt{ExtensionDeclaration} carries --- +\texttt{affected\_object\_kinds} and \texttt{edit\_barriers} --- have their +internal byte form pinned here. This chapter \textbf{ratifies} P12-E1 +(the blob and barrier-tree byte form), P12-E2 (the recursion bound), and +P12-E3 (the barrier \texttt{ObjectKind} representation). Barrier +\emph{semantics} --- scope matching, prohibited-edit evaluation, +conservative treatment of unknown extensions --- are core Chapter~8 +(\sectionsc{Forward Compatibility and Edit Barriers}); this chapter pins +bytes only. + +These layouts are \textbf{regime (b)}: all counts and length prefixes are +\texttt{u64} little-endian --- a deliberate, golden-locked divergence from +the \texttt{u32} regime (Section~\ref{sec:conventions:regimes}). + +\section{Framing} +\label{sec:barriers:framing} + +\begin{description} + \item[element] $\mathrm{elem}(x)$ = \texttt{u64} LE byte length \cat{} + $x$'s canonical bytes. + \item[set] $\mathrm{set}(xs)$ = elements' canonical byte strings, sorted + ascending byte-lexicographic and \emph{deduplicated}; then \texttt{u64} + LE element count \cat{} each element as $\mathrm{elem}$. Order and + repetition in the source collection cannot affect the bytes; decoders + reject unsorted or duplicated elements. + \item[list] $\mathrm{list}(xs)$ = \texttt{u64} LE count \cat{} each + element as $\mathrm{elem}$, order-significant (used only for condition + subtrees). +\end{description} + +\begin{requirement} +\label{req:binfmt:ext-blobs} +\textbf{The two blobs (ratifies P12-E1).} The +\texttt{affected\_object\_kinds} blob is $\mathrm{set}$ of barrier +\texttt{ObjectKind} elements; the \texttt{edit\_barriers} blob is +$\mathrm{set}$ of \texttt{EditBarrier} elements. Both decode under +reject-never-normalize with trailing bytes forbidden. +\end{requirement} + +\begin{requirement} +\label{req:binfmt:object-kind-open} +\textbf{Barrier \texttt{ObjectKind} (ratifies P12-E3).} A barrier +\texttt{ObjectKind} is the \texttt{TypedObjectId} discriminant of +Section~\ref{sec:ids:typed-object-id}, encoded as \textbf{2 little-endian +bytes}. Decode is \textbf{open-value}: every \texttt{u16} decodes +successfully --- an unknown kind (a future core kind or an +extension-registered kind) is a \emph{value}, not a decode branch, and +simply never matches any object the reader knows. This is the format's +forward-compatibility stance for barrier kinds: unknown kinds are preserved +and re-emitted verbatim, never dropped or rejected. +\end{requirement} + +\section{\texttt{EditBarrier}} +\label{sec:barriers:barrier} + +An \texttt{EditBarrier}'s canonical bytes, positionally: + +\begin{center} +\texttt{scope} \cat{} $\mathrm{set}$(\texttt{affected\_object\_kinds}: +\texttt{ObjectKind}) \cat{} +$\mathrm{set}$(\texttt{prohibited\_operation\_kinds}: +\texttt{OperationKindTag}, Section~\ref{sec:ops:kind-tag}) \cat{} +\texttt{condition} +\end{center} + +\texttt{BarrierScope}: one discriminant byte, then the payload: + +\begingroup\small +\begin{longtable}{p{0.35in} p{1.35in} p{3.8in}} + \toprule + \textbf{Disc} & \textbf{Variant} & \textbf{Payload} \\ + \midrule + \endhead + \tablenums{0} & \texttt{WholeScore} & (none) \\ + \tablenums{1} & \texttt{Region} & \texttt{RegionId}, 16 big-endian bytes \\ + \tablenums{2} & \texttt{StaffInstance} & \texttt{StaffInstanceId}, 16 BE \\ + \tablenums{3} & \texttt{AnalysisLayer} & \texttt{AnalysisLayerId}, 16 BE \\ + \tablenums{4} & \texttt{ObjectSet} & $\mathrm{set}$ of + \texttt{TypedObjectId} canonical bytes (18/34 each) \\ + \tablenums{5} & \texttt{PitchSpace} & \texttt{u64} LE byte length \cat{} + the pitch-space id's NFC UTF-8 bytes; decoders reject non-NFC input \\ + \tablenums{6} & \texttt{TuningContext} & (none) \\ + \tablenums{7} & \texttt{Registered} & \texttt{BarrierScopeRegistryId}, + \texttt{u128} \emph{little-endian} (16 bytes) \\ + \bottomrule +\end{longtable} +\endgroup + +\texttt{BarrierCondition}: one discriminant byte, then the payload; the tree +is recursive: + +\begingroup\small +\begin{longtable}{p{0.35in} p{1.85in} p{3.3in}} + \toprule + \textbf{Disc} & \textbf{Variant} & \textbf{Payload} \\ + \midrule + \endhead + \tablenums{0} & \texttt{Always} & (none) \\ + \tablenums{1} & \texttt{ObjectExists} & \texttt{TypedObjectId} \\ + \tablenums{2} & \texttt{ObjectHasExtensionData} & \texttt{object} + (\texttt{TypedObjectId}) \cat{} \texttt{extension} + (\texttt{ExtensionRef}, \texttt{u128} LE, 16) \\ + \tablenums{3} & \texttt{All} & $\mathrm{list}$ of conditions \\ + \tablenums{4} & \texttt{Any} & $\mathrm{list}$ of conditions \\ + \tablenums{5} & \texttt{Not} & one $\mathrm{elem}$-framed condition \\ + \tablenums{6} & \texttt{Registered} & + \texttt{BarrierConditionRegistryId}, \texttt{u128} LE (16) \\ + \bottomrule +\end{longtable} +\endgroup + +Note the endianness: the barrier layer's registry identifiers +(\texttt{BarrierScopeRegistryId}, \texttt{BarrierConditionRegistryId}, +\texttt{ExtensionRef}) encode \texttt{u128} \emph{little-endian}, unlike the +big-endian identifier family of Chapter~\ref{ch:ids}. This is part of the +golden-locked regime-(b) surface. + +\begin{requirement} +\label{req:binfmt:condition-depth} +\textbf{Recursion bound (ratifies P12-E2).} +$\texttt{MAX\_CONDITION\_DEPTH} = \tablenums{64}$ is the normative bound on +\texttt{BarrierCondition} nesting. Decoders \MUST{} reject a condition tree +nested deeper than 64 levels of \texttt{All}/\texttt{Any}/\texttt{Not}; +writers \MUSTNOT{} emit one. The bound exists so adversarial bytes cannot +drive unbounded recursion; real barriers are depth 1--2. +\end{requirement} + +% =========================================================================== +\chapter{Schema Evolution} +\label{ch:evolution} + +The core specification delegates schema evolution to this document (core +Chapter~8, \sectionsc{Schema Versioning}: \emph{``Schema evolution is +governed by the Binary Format companion specification, which defines the +wire encoding for each schema version''}). This chapter defines the wire +rules for schema major~0. + +\section{The Chunk-Level Gate} +\label{sec:evolution:gate} + +Every chunk declares a \texttt{SchemaVersion} (major, minor) in its +\texttt{ChunkRef} and the superblock declares the manifest's. The gate: + +\begin{itemize} + \item \textbf{Major} = incompatible. A reader \MUST{} reject a chunk whose + schema major it does not support. The current major is~\tablenums{0}. + \item \textbf{Minor} = additive. v0 readers verify the major only; the + minor is a \emph{record}, not a gate --- but it is a mandatory record: + a writer \MUST{} raise the chunk schema minor when it emits any + discriminant appended after the minor it otherwise declares, so that a + decode failure on an unknown appended discriminant is attributable to a + version skew rather than corruption. +\end{itemize} + +\section{What ``Additive'' Means Here} +\label{sec:evolution:additive} + +Under the frozen-layout rule (Requirement~\ref{req:binfmt:frozen-layout}), +positional struct layouts admit \emph{no} additive change: there is no +optional-field or trailing-field mechanism at the value level. In +particular, and stated honestly: \textbf{the manifest body cannot grow a +fourteenth field within major~0}. The manifest is a positional struct whose +decoder rejects trailing bytes, so manifest-body extension is +major-gated in v0 exactly like every other struct. + +The \emph{only} minor-additive mechanism in schema major~0 is +\textbf{appending discriminants to open vocabularies}: + +\begin{itemize} + \item \texttt{OperationKind}: append at ${\geq}\,\tablenums{24}$ + (Requirement~\ref{req:binfmt:kind-discriminants}); + \item \texttt{OperationKindTag}: append at ${\geq}\,\tablenums{24}$ + (Requirement~\ref{req:binfmt:kind-tag}); + \item \texttt{OperationPayload}: append at ${\geq}\,\tablenums{4}$ + (Section~\ref{sec:ops:payload}); + \item the value-layer unions enumerated as closed in + Requirement~\ref{req:binfmt:frozen-layout} may gain appended variants + only through a ratified revision of this document, also minor-additive. +\end{itemize} + +\texttt{ChunkKind} is \textbf{closed} --- it has no \texttt{Registered} +variant and no append story inside major~0, because its discriminant enters +every chunk's hash preimage; a new chunk kind is a format-major event. + +Separately, many vocabularies carry a \texttt{Registered} \emph{escape +variant} (\texttt{RepairKind}, \texttt{ReanchorReason}, +\texttt{PreconditionFailureReason}, \texttt{IntegrityAnomalyKind}, +\texttt{ReplicaAnomalyReason}, \texttt{TransactionCategory}, +\texttt{ResolutionAction}, \texttt{ConflictKind} via +\texttt{ExtensionConflict}, \texttt{BarrierScope}/\texttt{BarrierCondition}, +\texttt{TieClass}, \texttt{StaffGroupKind}, \texttt{PitchSpacePosition}, +\texttt{SpellingNominal}, \texttt{TypedObjectId}, and the barrier +\texttt{ObjectKind}'s open value space). Extension through an escape variant +is \textbf{not} a schema change at all: the wire form is already defined. + +\section{Migration Discipline} +\label{sec:evolution:migration} + +A schema-\textsc{major} bump \MUST{} ship with a migration documented in +this document's revision history (Chapter~\ref{ch:history}): what changed, +byte-for-byte, and the deterministic translation from the old form. The +precedent is the v0${\to}$v1 operation-payload migration, which lives in the +Operation Catalog (\sectionsc{v0 $\rightarrow$ v1 Payload Migration}) +because it was semantic rather than byte-level +(Section~\ref{sec:ops:v0}); byte-level migrations belong here. + +\begin{openquestion} +Whether the \texttt{u64}/\texttt{u32} length-prefix divergence between +regimes (a) and (b) (Section~\ref{sec:conventions:regimes}) gets unified at +the next schema major. Unification would simplify decoders and cost one +coordinated re-lock of the barrier-blob and resolved-layout goldens; +leaving it is free but permanent. Decide when the first major bump is +scheduled for other reasons --- the divergence alone does not justify one. +\end{openquestion} + +% =========================================================================== +\chapter{Non-Canonical Pinned Encodings} +\label{ch:noncanon} + +\textbf{Non-canonical} means: never part of document identity. Nothing in +this chapter enters a content hash that canonical state depends on, and all +of it can be discarded and rebuilt without changing the document. The +encodings are pinned for \emph{reproducibility} --- byte-equal conformance +claims and cache correctness --- not for durability. + +\section{\texttt{LayoutObjectId} (\texttt{MUSCLOID})} +\label{sec:noncanon:muscloid} + +Governed by core requirement \texttt{req:layoutir:object-id-derivation}. +$\texttt{LayoutObjectId} = \mathrm{trunc128}(\mathrm{BLAKE3}( +\texttt{MUSCLOID} \cat \mathit{inputs}))$, with three preimage shapes: + +\begin{description} + \item[stable] $\mathit{inputs}$ = the source + \texttt{TypedObjectId}'s canonical bytes. + \item[manifestation] $\mathit{inputs}$ = source canonical bytes \cat{} + \texttt{RegionId} canonical bytes (16 BE) --- distinct regions give one + source distinct manifestation ids. + \item[synthesized] $\mathit{inputs}$ = source canonical bytes \cat{} + five \texttt{u64} LE words: the \texttt{SynthesisKind} discriminant, + the registry id's high and low 64 bits (zero unless + \texttt{Registered}), and the instance key's high and low 64 bits. +\end{description} + +\texttt{SynthesisKind} discriminants: \tablenums{0} CancellationAccidental, +\tablenums{1} KeySignatureNatural, \tablenums{2} GeneratedRest, +\tablenums{3} EngravedBreak, \tablenums{4} MultimeasureRest, +\tablenums{5} Cautionary, \tablenums{6} Registered. + +\section{\texttt{ResolvedLayoutIR} Canonical Output} +\label{sec:noncanon:resolved} + +The resolved layout's canonical bytes are the \textbf{byte-equal conformance +surface} of core Chapter~7: two conforming engravers given the same score, +profile, and glyph catalog must produce identical bytes. The encoding is +regime (b) --- \texttt{u64} LE counts and length prefixes --- with every +geometric coordinate quantized to the $1/1024$ staff-space grid as a +\texttt{QuantizedCoord} (8 LE bytes; Chapter~\ref{ch:primitives}); +a non-finite or out-of-range coordinate is a determinism violation and +\MUST{} be rejected, never normalized. The top-level section order is: +source score version \cat{} pages \cat{} glyphs \cat{} strokes \cat{} +engraving decisions \cat{} glyph-catalog identity; within each section, +elements carry their provenance (built on \texttt{MUSCLOID} ids) and their +quantized geometry. The full leaf grammar is pinned by the reference +implementation's golden and round-trip anchors (Chapter~\ref{ch:goldens}) +rather than restated field-by-field here, because the surface is +non-canonical and evolves with the engraving feature set. + +\section{Layout Caches and Font Metrics} +\label{sec:noncanon:caches} + +\texttt{LayoutCache} chunks (\texttt{ChunkKind} \tablenums{6}) hold cached +layout artifacts; they are \textbf{always discardable}, and a reader +\MUSTNOT{} treat a missing, stale, or undecodable layout cache as bundle +corruption. The glyph-metrics identity hash is domain-separated under +\texttt{MUSCFNTM} (a reserved built-in, non-canonical tag): it names the +metrics a layout was computed against, so caches and conformance runs can +detect font drift; it never enters canonical state. + +% =========================================================================== +\chapter{Golden Anchor Registry} +\label{ch:goldens} + +The conformance contract binding this document to the reference +implementation. Three lock classes: + +\begin{description} + \item[literal-byte] the test asserts exact expected bytes or exact + discriminant literals --- the strongest lock; + \item[round-trip] the test asserts $\mathrm{decode} \circ \mathrm{encode} = + \mathrm{id}$ and re-encode byte-stability over a corpus; + \item[canonical-equality] the test asserts that semantically equal values + encode identically (order-independence, reduction identities). +\end{description} + +The first block restates the anchors already recorded in the core +specification's \texttt{app:bytes} \sectionsc{Reference-implementation +locks} table (which governs them); the second block adds the anchors this +document introduces, which \texttt{app:bytes} predates. + +Each anchor names its crate file, then the test on a second line. + +\begingroup\footnotesize +\begin{longtable}{>{\raggedright\arraybackslash}p{1.5in} >{\raggedright\arraybackslash}p{3.0in} p{1.0in}} + \toprule + \textbf{Layout} & \textbf{Anchor} & \textbf{Class} \\ + \midrule + \endhead + \multicolumn{3}{l}{\emph{Imported from \texttt{app:bytes}:}} \\ + \addlinespace[2pt] + \texttt{TypedObjectId} & + \texttt{epiphany-core/src/ids.rs}\newline + \texttt{::typed\ub object\ub id\ub byte\ub form\ub is\ub locked} & + literal-byte \\ + Promoted \texttt{VoiceId} & + \texttt{epiphany-core/src/graph.rs}\newline + \texttt{::promoted\ub voice\ub id\ub byte\ub form\ub is\ub locked} & + literal-byte \\ + System \texttt{PitchId} & + \texttt{epiphany-core/src/pitch.rs}\newline + \texttt{::system\ub pitch\ub id\ub byte\ub form\ub is\ub locked} & + literal-byte \\ + \texttt{IntegrityAnomalyId} & + \texttt{epiphany-ops/src/anomaly.rs}\newline + \texttt{::integrity\ub anomaly\ub id\ub byte\ub form\ub is\ub locked} & + literal-byte \\ + \texttt{ObjectKind} (ops) & + \texttt{epiphany-ops/src/support.rs}\newline + \texttt{::object\ub kind\ub discriminants\ub are\ub golden} & + literal-byte \\ + \texttt{ChunkKind} & + \texttt{epiphany-bundle/src/chunk.rs}\newline + \texttt{::chunk\ub kind\ub discriminants\ub are\ub golden} & + literal-byte \\ + \texttt{Compression\allowbreak Algorithm} & + \texttt{epiphany-bundle/src/chunk.rs}\newline + \texttt{::compression\ub algorithm\ub encoding\ub is\ub golden} & + literal-byte \\ + \texttt{ProfileId} & + \texttt{epiphany-bundle/src/superblock.rs}\newline + \texttt{::profile\ub id\ub discriminants\ub are\ub golden} & + literal-byte \\ + \texttt{ManifestId} & + \texttt{epiphany-bundle/src/ids.rs}\newline + \texttt{::manifest\ub id\ub is\ub content\ub derived\ub and\ub deterministic} & + canonical-equality \\ + \texttt{TransactionCategory} & + \texttt{epiphany-ops/src/payload.rs}\newline + \texttt{::transaction\ub category\ub discriminants\ub are\ub golden} & + literal-byte \\ + \texttt{ResolutionAction} & + \texttt{epiphany-ops/src/conflict.rs}\newline + \texttt{::resolution\ub action\ub discriminants\ub are\ub golden} & + literal-byte \\ + \texttt{BlobId} & + \texttt{epiphany-determinism/src/hash.rs}\newline + \texttt{ContentHash::of\ub blob} tests & + round-trip \\ + \texttt{RationalTime} & + \texttt{epiphany-core/src/time.rs}\newline + \texttt{::equal\ub rationals\ub encode\ub identically} & + canonical-equality \\ + \texttt{MUSCLOID} derivation & + \texttt{epiphany-layout-ir/src/provenance.rs}\newline + \texttt{::stable\ub id\ub uses\ub the\ub ratified\ub muscloid\ub derivation} & + literal-byte \\ + Domain-tag spellings & + \texttt{epiphany-determinism/src/domain.rs}\newline + \texttt{::exact\ub tag\ub spellings\ub match\ub spec} & + literal-byte \\ + \addlinespace[4pt] + \multicolumn{3}{l}{\emph{Added by this document:}} \\ + \addlinespace[2pt] + \texttt{OperationKind} discriminants (\S\ref{sec:ops:kinds}) & + \texttt{epiphany-ops/src/payload.rs}\newline + \texttt{::operation\ub kind\ub wire\ub discriminants\ub are\ub golden} & + literal-byte \\ + \texttt{OperationPayload} discriminants (\S\ref{sec:ops:payload}) & + \texttt{epiphany-ops/src/payload.rs}\newline + \texttt{::operation\ub payload\ub discriminants\ub are\ub golden} & + literal-byte \\ + \texttt{OperationKindTag} (\S\ref{sec:ops:kind-tag}) & + \texttt{epiphany-ops/src/payload.rs}\newline + \texttt{::operation\ub kind\ub tag\ub decode\ub mirrors\ub encode\ub exactly} & + round-trip \\ + \texttt{ResolveEquivocation} payload (\S\ref{sec:ops:payload}) & + \texttt{epiphany-ops/src/payload.rs}\newline + \texttt{::resolve\ub equivocation\ub payload\ub encodes\ub target\ub then\ub hash} & + literal-byte \\ + \texttt{OperationStamp} (\S\ref{sec:ops:stamp}) & + \texttt{epiphany-ops/src/stamp.rs}\newline + \texttt{::stamp\ub encode\ub is\ub stable} & + literal-byte \\ + \texttt{CausalContext} (\S\ref{sec:ops:causal}) & + \texttt{epiphany-ops/src/causal.rs}\newline + \texttt{::canonical\ub encoding\ub is\ub build\ub order\ub independent} & + canonical-equality \\ + \texttt{MaterializedState} (\S\ref{sec:ops:materialized}) & + \texttt{epiphany-ops/src/decode.rs}\newline + \texttt{::reduced\ub states\ub decode\ub and\ub reencode} & + round-trip \\ + Operation-index payload (\S\ref{sec:bundle:opindex}) & + \texttt{epiphany-bundle/src/opindex.rs}\newline + \texttt{::payload\ub encoding\ub is\ub golden} & + literal-byte \\ + Fixed header (\S\ref{sec:bundle:header}) & + \texttt{epiphany-bundle/src/header.rs}\newline + \texttt{::header\ub round\ub trips} & + round-trip \\ + Superblock (\S\ref{sec:bundle:superblock}) & + \texttt{epiphany-bundle/src/superblock.rs}\newline + \texttt{::superblock\ub round\ub trips\ub through\ub 256\ub bytes} & + round-trip \\ + Chunk hash preimage (\S\ref{sec:bundle:chunks}) & + \texttt{epiphany-bundle/src/chunk.rs}\newline + \texttt{::hash\ub preimage\ub matches\ub the\ub spec\ub layout} & + literal-byte \\ + \texttt{ChunkRef} (\S\ref{sec:bundle:chunkref}) & + \texttt{epiphany-bundle/src/chunk.rs}\newline + \texttt{::chunk\ub ref\ub round\ub trips} & + round-trip \\ + Manifest body (\S\ref{sec:bundle:manifest}) & + \texttt{epiphany-bundle/src/manifest.rs}\newline + \texttt{::re\ub encode\ub is\ub byte\ub identical}, + \texttt{::manifest\ub round\ub trips}, + \texttt{::duplicate\ub roots\ub collapse\ub on\ub encode}, + \texttt{::semver\ub orders\ub numerically\ub not\ub byte\ub wise} & + round-trip + canonical-equality \\ + Barrier kinds blob (\S\ref{sec:barriers:framing}) & + \texttt{epiphany-layout-ir/src/barrier.rs}\newline + \texttt{::affected\ub object\ub kinds\ub blob\ub bytes\ub are\ub golden} & + literal-byte \\ + Barriers blob (\S\ref{sec:barriers:barrier}) & + \texttt{epiphany-layout-ir/src/barrier.rs}\newline + \texttt{::edit\ub barriers\ub blob\ub bytes\ub are\ub golden} & + literal-byte \\ + Barrier variants (\S\ref{sec:barriers:barrier}) & + \texttt{epiphany-layout-ir/src/barrier.rs}\newline + \texttt{::every\ub scope\ub and\ub condition\ub variant\ub round\ub trips\ub byte\ub identically} & + round-trip \\ + Whole-\texttt{Score} codec (\S\ref{sec:values:score}) & + \texttt{epiphany-core/src/codec.rs}\newline + \texttt{::generator\ub scores\ub round\ub trip}, + \texttt{::trailing\ub and\ub truncated\ub bytes\ub are\ub rejected} & + round-trip \\ + \texttt{CanonicalValue} seam (\S\ref{sec:values:canonical-value}) & + \texttt{epiphany-core/src/codec.rs}\newline + \texttt{::value\ub types\ub round\ub trip\ub over\ub generator\ub corpus} & + round-trip \\ + \bottomrule +\end{longtable} +\endgroup + +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}. + +% =========================================================================== +\chapter{Revision History} +\label{ch:history} + +\begin{longtable}{p{2cm} p{2.5cm} p{9cm}} + \toprule + \textbf{Date} & \textbf{Section} & \textbf{Change} \\ + \midrule + \endhead + \today & All & 0.1.0 --- Initial companion: ratifies the previously + provisional whole-\texttt{Score} value codec (core P11-4), operation-layer + wire forms (ops), bundle physical layout (bundle P11-D2/D4/D5), + operation-index payload (P12-D1), and extension-blob/edit-barrier byte + forms (P12-E1/E2/E3); pins the no-varint rule, the frozen-positional + schema-evolution keystone, and the id-leads envelope property; + \texttt{SnapshotId} derivation deferred (open question). \\ + \bottomrule +\end{longtable} + +\end{document}