epiphany/crates/epiphany-determinism
Levi Neuwirth e2d389330d P12-I2: wire the ratified MUSCLOID layout-object id derivation
The spec's domain-tag registry reserves a non-canonical MUSCLOID layout tag for
LayoutObjectId derivation (req:layoutir:object-id-derivation, Pass-11 item 2.6),
but it was never realized in code: layout-ir minted provisional, untagged ids and
synthesized objects borrowed MUSCCONF. This wires the ratified derivation.

  - epiphany-determinism: add the reserved built-in DomainTag::LAYOUT_OBJECT_ID
    (`MUSCLOID`), non-canonical/layout-namespace like FONT_METRICS (following the
    SYSTEM_ANOMALY Pass-11 precedent of adding a reserved tag). The tag-enumeration
    tests now derive from BUILTINS so they cannot drift; the spelling is locked and
    from_bytes resolves it as a non-system builtin.
  - layout-ir provenance.rs: all three LayoutObjectId derivations route through
    MUSCLOID exactly per the requirement -- single keyed on source.canonical_bytes(),
    multiply-manifested on (source, region), synthesized on (source, synthesis_kind,
    instance_key); synthesized no longer borrows MUSCCONF. A reference-lock test
    pins the derivation and proves it is genuinely domain-separated; another asserts
    the three keying schemes do not collide (safe by the discriminant-led,
    fixed-width canonical_bytes).
  - layout-ir engraving.rs: EngravingDecisionId borrowed MUSCCONF for the same
    reason; moved it onto MUSCLOID too, keeping its `engraving-decision` prefix so it
    cannot alias a layout-object id within the namespace.

Layout ids are non-canonical (never document state, in no content hash), so this
changed id *values* but no durable or interchanged artifact: the only golden churn
is the data-prov hex in the four render goldens (every changed line is a data-prov;
geometry/structure byte-identical).

Spec/status sync: core_spec.tex descriptive notes (the requirement tail, the
domain-tag registry row, the registry intro, and the revision-history entry) now
say the reference implementation wires MUSCLOID as of P12-I2; MUSCLOID is moved out
of the "deferred to the companions" (not-ratified/provisional) list and given a
non-canonical anchor paragraph after the reference-implementation-locks table.
PASS12_BATCH.md marks P12-I2 resolved; PASS11_RATIFICATION_LOG.md keeps the
historical row with a "superseded by P12-I2" note; layout-ir/DECISIONS.md updates
the ratified-block note, the id bullet, and the open candidate (now RESOLVED).

Full gate green: build, fmt, clippy, 587 tests, conformance scale 1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 12:46:19 -04:00
..
examples A B C D F 2026-06-19 12:42:31 -04:00
src P12-I2: wire the ratified MUSCLOID layout-object id derivation 2026-06-27 12:46:19 -04:00
tests A B C D F 2026-06-19 12:42:31 -04:00
Cargo.toml A B C D F 2026-06-19 12:42:31 -04:00
README.md A B C D F 2026-06-19 12:42:31 -04:00

README.md

epiphany-determinism

The reproducibility-contract primitives for Epiphany, implementing the normative requirements of Appendix D (Determinism Contract) of the core specification (spec/core_spec.pdf). This is Agent A's crate per spec/QUICKSTART.md: the smallest scope, landing first, with every other crate depending on it.

Canonical document state must be independent of platform, CPU, locale, thread scheduling, hash-map iteration order, floating-point environment, compression settings, and wall-clock timing. — Appendix D, Thesis

Everything in this crate exists to make that hold by construction. It is pure value types and pure functions: no async, no I/O, no platform calls. It is the strict single-threaded baseline that every parallel or accelerated implementation must reproduce bit-for-bit.

What's here

Area Items Spec
Spatial grid QuantizedCoord (1/1024 staff space, round-ties-to-even) App. D §"Quantized Layout Coordinates"; Ch. 7 §7.2
Content addressing ContentHash, ChunkId, blake3_256, trunc64, trunc128, Preimage, derive_system_counter Ch. 8 §"Content Hashing"; Ch. 56 derivations
Domain tags DomainTag (closed vocabulary) + MUSC* constants, SystemDomainTag, bundle/superblock magic Ch. 8 §"Domain-Separated Preimages"; Ch. 5 §"System-Derived"
Tolerances Tolerance, ToleranceClass (the five classes), ToleranceGovernance App. D §"Tolerance Classes"
Float hygiene CanonicalF64, canonical_f64_bytes, canonicalize_zero, debug_assert_canonical App. D §"Floating-Point Values in Canonical State"
Canonical order CanonicalEncode/CanonicalDecode, sort_canonical, CanonicalMap/CanonicalSet App. D §"Ordered Iteration over Sets and Maps"
Fuzz harness fuzz::run_round_trip_fuzz, examples/fuzz_roundtrip hand-off gate

The three determinism rules this crate enforces mechanically

  1. No NaN/inf/-0.0 in canonical state. CanonicalF64 is the only way to put a float into canonical form; it rejects NaN/inf and maps -0.0 to +0.0. Canonical equality is byte equality of the little-endian serialization. Decode rejects non-finite payloads as corruption.
  2. All hashing is domain-separated BLAKE3-256. Preimage puts the 8-byte DomainTag first, every time. DomainTag is a closed vocabulary (built-ins plus MUSCS extension tags, printable ASCII) with a private field, so a foreign or non-ASCII tag can't be minted; derive_system_counter takes a SystemDomainTag, so only a system tag can seed a system identifier. trunc64/trunc128 take the leading bytes big-endian, matching the spec's reference code exactly.
  3. Canonical iteration is a specified total order. Reach for CanonicalMap/CanonicalSet (BTree) instead of HashMap/HashSet, or sort_canonical (gated on CanonicalByteOrder) before it affects canonical output.

Implementation decisions

Per QUICKSTART "Decisions you'll need to make", the calls that touch this crate:

  • Sync only (decision 4). No async traits anywhere; nothing here needs them.
  • blake3 is the sole dependency. One content-hash algorithm for this format version (Ch. 8); no second hash, no RNG dependency (the fuzz harness uses a vendored SplitMix64 so failures reproduce from a seed).
  • MSRV 1.77 for f64::round_ties_even. The spec uses no exotic Rust features; overflow-checks stay on in release so identifier/coordinate arithmetic faults loudly rather than wrapping.
  • unsafe is forbidden crate-wide (#![forbid(unsafe_code)]).

Building and testing

cargo test -p epiphany-determinism          # unit + integration + 1M fuzz gate
cargo clippy --all-targets -- -D warnings    # lint clean
cargo run --release --example fuzz_roundtrip -- 10000000   # extended soak

Hand-off criteria (QUICKSTART, Agent A)

  • cargo test clean.
  • Round-trip canonical encode/decode fuzz harness runs 1M iterations without panic (fuzz_round_trip_one_million_iterations; extended soak via the example binary).

Scope boundaries

ChunkKind, SchemaVersion, ChunkRef, and the full chunk hash_preimage live in epiphany-bundle (Agent D); the typed graph identifiers and the full derive_conflict_id live in epiphany-core/epiphany-ops (Agents B/C). This crate provides only the shared primitives those derivations compose from (DomainTag, Preimage, trunc64/trunc128, canonical float bytes), so there is no dependency cycle and exactly one definition of each contract type.

Ambiguities encountered while building are not resolved in code — they are batched as Pass 11 candidates against the spec (QUICKSTART, Process notes). None were required for this crate.