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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NEs4aYiu8MXjdYdMxw8PTd |
||
|---|---|---|
| .. | ||
| examples | ||
| src | ||
| tests | ||
| Cargo.toml | ||
| DECISIONS.md | ||
| README.md | ||
README.md
epiphany-bundle
The Epiphany .musc file format, implementing the normative requirements of
Chapter 8 (File Format) of the core specification (spec/core_spec.pdf).
This is Agent D's crate per spec/QUICKSTART.md. It depends on
epiphany-determinism (Agent A) and on nothing else — not on epiphany-core
(Agent B) or epiphany-ops (Agent C):
bundles handle bytes, ops handles semantics. A canonical-base snapshot from the bundle's perspective is opaque bytes plus a frontier DVV; only
epiphany-opsinterprets it. — QUICKSTART
A bundle is a single file: a fixed 64-byte header at offset 0, two 256-byte superblock slots, then a body of immutable, content-addressed chunks. The superblocks are the only mutable on-disk objects. A commit appends new chunks, writes a new manifest chunk, then flips the active superblock by writing the inactive slot and durably flushing it — that flush is the commit point. Because commits only ever append and touch the inactive slot, a crash can never corrupt the active state.
What's here
| Area | Items | Spec |
|---|---|---|
| Prelude | FixedHeader (64 B, CRC-32C), Superblock/CommitState (256 B, CRC-32C), select_active |
Ch. 8 §"The Bundle Layout", §"Superblock Selection" |
| Atomic commit | Bundle::create/open/commit, the 7-step protocol, cold-open path |
Ch. 8 §"The Atomic Write Protocol", §"Streaming Reads" |
| Content addressing | chunk_content_hash/chunk_id, ChunkRef, ChunkKind, CompressionAlgorithm, domain separation |
Ch. 8 §"Content Hashing", §"Chunks" |
| Manifest | Manifest (canonical_base ≠ acceleration_snapshots), SnapshotRef, BlobRef, ProfileDeclaration, ExtensionDeclaration |
Ch. 8 §"The Manifest" |
| Retention | RetentionPolicy (first-class), ProfileConstraints |
Ch. 8 §"Garbage Collection and Retention" |
| Op blocks | pack_operation_blocks (1 MiB soft target), encode_block/decode_block |
Ch. 8 §"Operation Envelope Blocks" |
| Storage | BlockStore, MemStore, FileStore (real fsync), FaultStore (crash sim) |
Ch. 8 §"Durable Writes" |
| Gates | fuzz::run_crash_recovery_fuzz, fuzz::exhaustive_crash_check, fuzz::run_manifest_selection_harness |
QUICKSTART acceptance |
The crash-recovery contract (the acceptance gate)
Kill the process between any two syscalls in the commit protocol; reopen; the bundle must be valid in 100% of runs, and must recover to the previous generation when the crash precedes the durable flush. This is the most important single test in the entire prototype. — QUICKSTART, Agent D
Killing a real process between syscalls cannot be made deterministic, so the
fuzzer drives the commit against a FaultStore that distinguishes live
(page-cache) bytes from durable (survives-a-crash) bytes and can crash after
any chosen syscall — optionally tearing the in-flight superblock write, the
case the slot CRC must catch. After every simulated crash the bundle is reopened
from the durable image and must:
- open successfully (never corrupt);
- be at the previous generation or the new one, never anything else;
- if the commit returned
Ok, be at the new generation; and if the crash was clean (the in-flight flush persisted nothing) and the commit did not complete, be at the previous generation — the exact "recover to the previous generation when the crash precedes the durable flush" property. (A torn final flush may at a full prefix legitimately persist the whole superblock — the genuine post-commit case — so the torn branch admits either generation.) - report no integrity anomaly;
- have every canonical chunk present and hash-intact.
Two drivers exercise this: a randomized 10,000-iteration sweep, and an exhaustive per-commit sweep that tests every syscall boundary crossed with every tear point (clean, and torn at prefixes around the 252-byte CRC offset and the 256-byte slot size). The second leaves no step of the protocol untested.
The companion manifest_selection gate asserts the Chapter 8 superblock-
selection rule across every corruption scenario the QUICKSTART enumerates: slot A
corrupt + B valid (and vice versa), both valid at generation+1, both valid at the
same generation (equivalent, and divergent), a generation gap > 1, a
non-committed slot, a manifest-hash mismatch, and neither valid.
Building and testing
cargo test -p epiphany-bundle # unit + the two gates
cargo clippy -p epiphany-bundle --all-targets -- -D warnings
cargo run --release --example fuzz_crash -- 1000000 # extended crash soak
Hand-off criteria (QUICKSTART, Agent D)
cargo testclean.- Crash-recovery fuzzer passes 10,000 iterations
(
crash_recovery_fuzz_ten_thousand_iterations, two seeds; extended soak via the example binary; exhaustive per-syscall sweep inexhaustive_sweep_across_base_states_and_commit_shapes). - Manifest-selection harness handles every corruption scenario
(
every_selection_scenario_holds). - Real-filesystem
fsyncround-trip (file_store_real_fsync_round_trip).
Scope boundaries (per QUICKSTART "Don't do these")
v0 writes only uncompressed chunks (compression on the write path is deferred),
but reading zstd-compressed chunks and blobs is supported, per the spec's
§Compression MUST (the manifest is mandatory-uncompressed regardless, and a
compressed manifest is rejected). It carries the text-projection root but does
not implement the s-expression projection content, and it preserves extension
declarations and chunks but does not evaluate edit barriers — barrier operands
(OperationKindTag, ObjectKind, EditBarrier) are owned by Agents C and E.
Operation envelopes, snapshots, and causal frontiers are opaque bytes here.
See DECISIONS.md for the prototype byte-layout choices that anticipate the
deferred Binary Format companion, and the batched Pass 11 candidates.