- Bump alkcall 0.8.0 -> 0.8.1 (duplicate adopt/open channel-state
destruction fix from alkcall's fuzz campaign; AGENTS.md stale-pin fix).
- Adopt fuzzing per docs/plans/fuzzing.md (mirrors alkcall's
docs/research/fuzzing.md as-built layout): fuzz/ workspace with own
[workspace] table, nightly pinned for the subtree only, invariant
logic in a stable-toolchain shared crate.
- Targets: chunk_frame (5-byte chunk codec), negotiation_frame
(negotiation framing + NegotiateRequest + error_response_bytes +
the cross-codec peek-disambiguation seam), control_json
(ControlMessage JSON + signal_from_name). src/local/ out of scope
(not wire-attacker-shaped).
- 328 committed seeds (deterministic generator); grown corpora
gitignored. Corpus replay on stable is the standing fuzz gate
(cargo test --manifest-path fuzz/shared/Cargo.toml).
- Detached-runner rule (fuzz/run-detached.sh): campaigns never run in
the foreground of an agent session - OOM in a target must cost the
fuzzer, never the session host.
- Root Cargo.toml gained [workspace] members/exclude (MSRV vs fuzz
nightly dev-deps footgun) and fuzz/ in the publish exclude.
Verification: cargo test (113), cargo test --all-features (156),
clippy stable + wasm32-unknown-unknown, fmt, doc, publish dry-run,
corpus replay 328 seeds - all green. 10-min detached campaigns on all
three targets: 0 crashes/hangs/OOMs/leaks (chunk_frame cov-saturated
at 710 edges; negotiation_frame 3.69M execs cov 3157; control_json
8.6M execs cov 2035). Corpus replay caught three harness-model
mismatches pre-campaign (payload-slice shape; the negotiation framing
layer is length-prefix-only - Json unreachable from read_frame;
zero-length frames admitted by the reader, rejected by the adapter's
parse). Campaigns recorded in docs/plans/fuzzing.md section 8.