# Packet Format
## Frame Layout
Each packet contains a fixed-size header followed by a bincode-encoded `Message` body.
| 0 | MAGIC | 4 bytes | ASCII `ENP1` sentinel |
| 4 | VERSION | 1 byte | Protocol version, currently `1` |
| 5 | FLAGS | 1 byte | Feature bits, currently `0` |
| 6 | RESERVED | 2 bytes | Big-endian zero, reserved for extensions |
| 8 | BODY_LEN | 4 bytes | Big-endian length of BODY in bytes |
| 12 | BODY | `BODY_LEN` bytes | Deterministic bincode serialization of `Message` |
`BODY_LEN` must exactly match the actual number of bytes present after the header. Packets shorter than 12 bytes or larger than 16,777,216 bytes are rejected. Since the header is always 12 bytes, the encoded body is also capped at 16,777,204 bytes to keep allocations bounded.
## Body Encoding
The body uses `bincode::DefaultOptions::new().with_fixint_encoding()` with deterministic settings. Strings and byte arrays include their lengths, so the serialized representation remains self-delimiting.
`Message`, `MessageType`, and `MessageMeta` are serialized via Serde with the same schema for both encoding and decoding. Adding new enum variants is backward-compatible as long as all peers update together; changing field layouts requires a protocol upgrade.
## Attachment Chunking
Large attachments are transferred through multiple packets:
1. **AttachmentInit** announces the transfer. The metadata embeds the attachment identifier, semantic `AttachmentKind`, chunk sizing, and total byte count. The payload is always empty.
2. **AttachmentChunk** packets stream the bytes. Each chunk records its index, byte offset (`index * chunk_size`), and optional total size for redundant validation. Payloads carry the chunk data.
3. **AttachmentEnd** finalizes the transfer with totals and optional integrity material (e.g., SHA-256). Payload is empty.
4. **AttachmentAbort** or **AttachmentAck** packets inform the sender of failures or completed reception.
This layout makes attachments effectively unlimited. The crate only enforces per-packet safety bounds derived from the frame header; higher layers decide how many chunks to send or accept.