The wire protocol is re-specified as DongLoRa Protocol v2 (see PROTOCOL.md). Every type_id, tag-correlation rule, and field layout is incompatible with 0.1.0.
* Add PROTOCOL.md as the normative spec for the v2 wire format.
* Replace framing.rs with a streaming FrameDecoder that emits (type_id, tag, payload) triples on each COBS-delimited, CRC-checked frame.
* Split the single-file lib.rs into dedicated modules: frame, commands, events, errors, modulation, info, crc, chip_id. Re-exports preserve convenience imports at the crate root.
* Replace RadioConfig / Bandwidth with a Modulation enum covering LoRa, FSK/GFSK, LR-FHSS, and FLRC, each with its own typed parameter struct.
* Add TxFlags, RxOrigin, SetConfigResult, OkPayload to model v2 response shapes, and RadioChipId for GET_INFO.
* Rewrite fuzz corpus: replace the 4 cobs_* / command_roundtrip targets with decoder_feed, frame_roundtrip, lora_config_roundtrip, and parse_device_message; drop parse_radio_config.
* Expand proptest and mutation-killer coverage for the new wire shape.
* Rewrite canonical-byte test vectors against the v2 spec.
Four libFuzzer targets:
- parse_command: Command::from_bytes never panics; bounded payload.
- parse_radio_config: RadioConfig::from_bytes never panics.
- cobs_decoder_feed: CobsDecoder::feed is panic-free across arbitrary
byte streams split into arbitrary chunks.
- cobs_roundtrip: structure-aware (via arbitrary crate) Response →
cobs_encode_response → ucobs::decode yields identical raw bytes.
All four smoke-tested at 50k runs each with no findings. Intended CI
cadence is a weekly cron with a larger time budget; per-PR would be
expensive. Requires nightly + cargo-fuzz.