# CLAUDE.md
Development guide for the `ant-protocol` crate.
## Project Overview
`ant-protocol` is the wire contract between
[`ant-client`](https://github.com/WithAutonomi/ant-client) and
[`ant-node`](https://github.com/WithAutonomi/ant-node). It holds the
types and helpers both sides must agree on. Nothing else belongs here.
## Scope (what goes in vs what stays out)
**In:**
- Wire message types (`ChunkMessage`, put/get/quote request + response).
- Protocol constants (`CHUNK_PROTOCOL_ID`, size limits, close-group sizing, proof tags).
- `ProtocolError`.
- Content-addressing helpers that are pure functions on 32 bytes.
- `send_and_await_chunk_response` (shared send/receive helper on `P2PNode`).
- `PaymentProof` + `SingleNodePayment` (construction, `pay`, `verify`).
- ML-DSA-65 signature verification for quotes and merkle candidates.
- Re-exports of shared transitive deps under `evm`, `transport`, `pqc`.
**Out:**
- Node-side quote generation and signing keys (live in `ant-node`).
- On-chain payment verification state machine / cache (live in `ant-node`).
- `LocalDevnet`, node process management, binary supervision (live in `ant-client`).
- DHT-internal `saorsa-core` types used only inside the node
(`DHTNode`, `TrustEvent`, `DhtNetworkEvent`, …). `ant-node` keeps
its own `saorsa-core` dep; Cargo unifies the version because this
crate pins it.
Rule of thumb: if only one side needs it, it doesn't belong here.
## The version pinning rule
`ant-protocol` is the single version-pin for `evmlib`, `saorsa-core`,
and `saorsa-pqc`. **`ant-client` must not declare direct dependencies
on those three crates** — it must go through `ant_protocol::{evm,
transport, pqc}`. This prevents silent version skew that would
otherwise produce two incompatible copies of `ProofOfPayment` or
`P2PNode` at runtime.
`ant-node` legitimately touches node-only `saorsa-core` surface
(DHT internals) and keeps a direct `saorsa-core` dep for that. Cargo
still unifies the version because both declarations must be
compatible with `ant-protocol`'s pin.
When adding a new type to the re-export modules, check that it is
actually used on both sides — if only one side needs it, it stays as
a direct dep on that side, not a re-export here.
## Design Principles
1. **Small surface.** Every item in `lib.rs` is either a wire type both
sides use, a pure helper, or a shared protocol function. Think twice
before adding anything else.
2. **No panics in production code.** `#[deny(clippy::unwrap_used,
expect_used, panic)]` is on. Tests may relax this with
`#[allow(clippy::unwrap_used, expect_used, panic)]` locally.
3. **`pay` and `verify` co-located.** The client calls `pay`; the node
calls `verify`. Tests exercise both ends against Anvil. Splitting
them would let the two sides drift silently.
4. **Logging is optional and zero-cost when off.** The `logging`
feature re-exports `tracing` macros. With `--no-default-features`
the macros expand to `()`.
5. **No I/O except what the shared protocol requires.** The only I/O
in this crate is the P2P send/receive in `chunk_protocol` and the
Anvil-backed payment flows in `SingleNodePayment`. If you find
yourself adding a third I/O path, ask whether it really belongs in
both crates.
## Development Commands
```bash
# Fast compile check
cargo check --all-features
# Full test suite (includes Anvil-backed tests — needs Foundry installed)
cargo test --all-features -- --test-threads=1
# Unit tests only (fast, no Anvil)
cargo test --lib
# Lint + format
cargo clippy --all-targets --all-features -- -D warnings
cargo fmt --all
# Docs
cargo doc --all-features --no-deps
# Confirm no-default-features still builds
cargo build --no-default-features
# Pre-publish verification
cargo publish --dry-run
```
## Release Process
1. Bump `version` in `Cargo.toml` (semver: bump **major** for any wire
change, **minor** for additive wire-compatible changes, **patch**
for fixes).
2. Update `CHANGELOG.md`.
3. Commit, push, open PR.
4. After merge, create and push a tag matching the Cargo version:
`git tag v2.1.0 && git push origin v2.1.0`.
5. The `Release` workflow validates, runs the full test suite,
publishes to crates.io, and creates a GitHub Release.
Manual publish path (if CI is unavailable) is just `cargo publish`
from a clean checkout of the tagged commit, with
`CARGO_REGISTRY_TOKEN` in the environment.
## When to bump
- Change a wire message field (add, remove, rename, retype): **major**.
- Add a new `ChunkMessageBody` variant (existing variants unchanged): **minor**
— serde enum encoding preserves unknown variants through postcard's
discriminant strategy, so old decoders reject the new variant cleanly.
- Add a new helper, new constant, new optional field: **minor**.
- Fix a bug that doesn't change the wire: **patch**.