epiphany/crates/epiphany-core/src
Levi Neuwirth 7e7a43b050 Fuzzer P1: adversarial decode fuzz + strict-canonical decode + bounded counts
Stands up the Binary Format companion's wire-format-fuzzer charter item as a
core adversarial byte-decode harness, and lands the three robustness fixes it
drove out. The canonical decoders are a trust boundary (a hostile bundle, a
bit-rot chunk, a mismatched implementation), so every byte string must decode
to a clean Err -- never panic, over-allocate, or loop unboundedly -- and any
accepted string must re-encode to itself (canonical decode is injective).

- epiphany-core/src/fuzz.rs (new): run_decode_fuzz mutates a once-built corpus
  (random, substitution, truncation, trailing garbage, length-prefix
  corruption, wrong-type payload, genuine-v0-form) against Score::decode_canonical,
  the versioned seam (v1 + the frozen v0 migration), and a per-value decoder;
  asserts no-panic + injective decode over ~40K inputs/run. Two seeds, plus
  deterministic prefix-rejection sanity tests.

- Strict-canonical decode (the fuzzer's first finding): decode reconstructed via
  normalizing constructors (RationalTime reduces, BTreeSet/BTreeMap re-sort, a
  CanonicalF64/ReferencePitch/Tempo normalizes via new), so distinct byte
  strings could map to one value. Fixed complete-by-construction: Score::
  decode_canonical and the CanonicalValue macro re-encode and reject any input
  not already its canonical form; decode_v0_score does the same against the
  frozen v0 wire form (encode_v0_score promoted to production), so major-0
  snapshots are injective too.

- Bounded collection count (Reader::count): reject any count/length exceeding
  the bytes remaining. A garbage u32 count was a soft-DoS -- decoders looped
  element-by-element toward EOF (e.g. misparsing v1 bytes as v0), ~100ms per
  adversarial input; the bound also caps Vec/set allocation and gives a ~2600x
  fuzz speedup (422s -> 0.16s). Codec round-trips confirm no valid data has
  zero-byte-element collections, so the bound never rejects a real encoding.

Full gate green (workspace tests, clippy -D warnings, fmt, rustdoc -D warnings).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NEs4aYiu8MXjdYdMxw8PTd
2026-07-07 09:42:04 -04:00
..
prepass Schema major 1 Phase D1: Instrument.range + Region flag (snapshot side) 2026-07-06 11:14:52 -04:00
codec.rs Fuzzer P1: adversarial decode fuzz + strict-canonical decode + bounded counts 2026-07-07 09:42:04 -04:00
event.rs Land M1 + M2 (Agent C): framework edge fixes and real-Score graph integration 2026-06-21 16:37:51 -04:00
fuzz.rs Fuzzer P1: adversarial decode fuzz + strict-canonical decode + bounded counts 2026-07-07 09:42:04 -04:00
generators.rs Schema major 1 Phase D1: Instrument.range + Region flag (snapshot side) 2026-07-06 11:14:52 -04:00
graph.rs Schema major 1 Phase D1: Instrument.range + Region flag (snapshot side) 2026-07-06 11:14:52 -04:00
ids.rs Pass 11: ratify provisional byte choices into normative spec text 2026-06-21 22:30:06 -04:00
indexes.rs A B C D F 2026-06-19 12:42:31 -04:00
invariants.rs Schema major 1 Phase D1: Instrument.range + Region flag (snapshot side) 2026-07-06 11:14:52 -04:00
lib.rs Fuzzer P1: adversarial decode fuzz + strict-canonical decode + bounded counts 2026-07-07 09:42:04 -04:00
pitch.rs Schema major 1 Phase D1: Instrument.range + Region flag (snapshot side) 2026-07-06 11:14:52 -04:00
prepass.rs Push 4: Binary Format companion, F1 benches, subquadratic reduction order 2026-07-02 19:02:07 -04:00
tempo.rs Push 4: Binary Format companion, F1 benches, subquadratic reduction order 2026-07-02 19:02:07 -04:00
time.rs Pass 11: ratify provisional byte choices into normative spec text 2026-06-21 22:30:06 -04:00