Go to file
Levi Neuwirth 9596d1e824 Push 5 / P2: fuzz the ops decode surface, and find the guard's blind spot
The operation layer has exactly two byte-decode surfaces: MaterializedState and
OperationKindTag. Operation payloads have no decoder -- OperationKind is
encode-only -- so nothing here can yet accept a duplicate TransposeInterval
target. When such a decoder lands it inherits the wire table's seq-strictly-
increasing rule: reject a duplicate, never normalize it away.

No defect in the decoder. It already carries the Phase-1 hardening: a whole-state
re-encode-and-compare guard, and with_capacity(n.min(1024)) at every count site,
so the unbounded-allocation and soft-DoS classes P1 fixed in core do not apply.
2M adversarial inputs across four seeds, ~2s each, clean.

The finding is about the ARCHITECTURE, and it qualifies P1's recorded design
note that the guard "is complete-by-construction, it cannot miss a lenient
codec". It is complete only for fields the decoder NORMALIZES. The BTreeMaps
re-sort and de-duplicate, so a non-canonical encoding of them cannot survive a
round trip. But the guard is BLIND to order-preserving Vec fields: a reordered
anomalies or pending list re-encodes to exactly the bytes it came from, so the
guard sees identity and accepts. Only the per-site windows(2) checks reject
them, and the same holds for a conflict record's caused_by / affected_objects,
which ConflictRecord::encode_canonical writes verbatim.

Measured, not reasoned: removing both per-site Vec order checks leaves a 40K
injectivity sweep GREEN. An injectivity fuzzer structurally cannot see this
class -- it asserts bytes->value->bytes identity, which is exactly what a
missing order check preserves. Those checks were locked by nothing. They are now.

(effects is a Vec with no order check, correctly: its canonical order is
reduction order, which a decoder cannot recompute. Two orderings are two
different states, so injectivity is not at stake.)

Delivered: fuzz::run_decode_fuzz over both surfaces, returning a
DecodeFuzzCoverage the smoke tests assert on -- a decode fuzzer that never
reaches a decoder's accept path proves only the absence of a panic, and mine
initially accepted nothing worth speaking of. Plus one deterministic test per
layer: an out-of-order objects map (guard only), an out-of-order anomaly list
and a reordered pending list (per-site only). Each mutation-verified against the
exact check it locks, and the fuzzer confirmed blind to the per-site pair.

Corpus depth is now a property rather than luck. A fixed list of envelope-set
sizes reduces to states with no conflicts, anomalies, pending, or spellings --
the very branches holding every canonical-order check. Measured: 6 of 12 seeds
failed to produce all four. build_decode_corpus draws until covered and asserts.

Gate: fmt clean, clippy 0, 30 targets / 1007 passed / 0 failed, docs 0 under
-D warnings, conformance 8/8, zero golden churn.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 18:43:21 -04:00
.github/workflows Push 4: Binary Format companion, F1 benches, subquadratic reduction order 2026-07-02 19:02:07 -04:00
crates Push 5 / P2: fuzz the ops decode surface, and find the guard's blind spot 2026-07-09 18:43:21 -04:00
spec The pitch/spelling undo unit is broader than the transpose, on purpose 2026-07-09 18:15:43 -04:00
.gitignore Schema major 1 Phase F: ratify engrave I8/I9/I10 + process trail 2026-07-06 17:40:38 -04:00
CONFORMANCE.md Pass 12 G-pass: ratify the full batch (28 rows) — spec tranche 2026-07-07 10:23:30 -04:00
Cargo.lock Phase 3 tranche 2: quality conformance companions, real metrics, multi-system click fix 2026-07-03 10:39:05 -04:00
Cargo.toml Push 4: Binary Format companion, F1 benches, subquadratic reduction order 2026-07-02 19:02:07 -04:00