# Changelog

All notable changes to PeerNet are documented here. The format is
based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
this project follows [Semantic Versioning](https://semver.org/) once
it reaches `1.0.0`.

## [Unreleased]

### Added

- **Credo** added as a dev/test dependency with `--strict` cleanliness.
  Configuration in `.credo.exs` (default + a few project-specific
  refinements). All current source passes `mix credo --strict` with
  zero issues.

### Added

- **`PeerNet.NetworkMonitor`** behaviour + **`Polling`** default
  implementation. Notices when local IP set changes (e.g. WiFi
  switch) and notifies subscribers. Wires into Registry so a
  network change triggers immediate teardown of all live connections
  — much faster than waiting for TCP keepalive or app-level
  Liveness to time out the dead links.
- **Noise XX handshake** — full
  `Noise_XX_25519_ChaChaPoly_SHA256` implementation in pure Elixir
  on `:crypto`. SymmetricState, CipherState, HandshakeState, all
  message-pattern processing per the Noise spec.
- **`PeerNet.Channel`** — post-handshake AEAD wrapper. ChaCha20-
  Poly1305 with the Noise nonce format, per-direction
  CipherStates, counter-exhaustion protection.
- **`PeerNet.BeamDist`** — convenience module for asymmetric-trust
  RPC. The "phone controlling Nerves" use case in 5 lines on each
  side.
- **`PeerNet.Discovery.UDP`** — LAN broadcast discovery. Compact
  39-byte announce frame, configurable cadence and listen port,
  pluggable transport for testability.
- **Auto-reconnect** — Registry redials trusted peers with
  exponential backoff (500ms → 1s → 2s → ... → 30s cap) when their
  connection drops.
- **`PeerNet.Liveness`** — app-level heartbeat. Per-ping check
  timers detect dead peers in seconds rather than waiting for TCP
  keepalive.
- **`PeerNet.Discovery`** behaviour with **`Manual`** and **`UDP`**
  reference implementations.
- **`PeerNet.Registry`** — pubkey-keyed peer state with auto-
  connect on discovery and reconnect on disconnect.
- **`PeerNet.Frame.encode_raw/1` and `decode_raw/1`** — bypass ETF
  for already-encoded bytes (used by Channel for AEAD ciphertexts).

### Changed

- **`PeerNet.Identity` migrated from Ed25519 to X25519** — Noise's
  DH primitive is X25519. The keyfile magic bumped from `0x01` →
  `0x02`; old keyfiles return `{:error, :invalid_keyfile}` on load
  rather than silently misbehaving. Apps must regenerate identities
  after upgrading.

### Removed

- `PeerNet.PeerIndex` — replaced by `PeerNet.Registry`, which
  subsumes its responsibilities and adds discovery / reconnect.
- `PeerNet.Identity.sign/2` and `verify/3` — Noise XX cryptographic-
  ally binds peer identity into the transcript hash; explicit
  per-message signatures are no longer used. Apps that need long-
  term-key sigs for app-level data should layer that themselves.

### Security

- The wire is now end-to-end AEAD-encrypted. Previous milestones
  (M2 POC) shipped plaintext over TCP — never use a v0.0 build for
  anything beyond local-network testing.
- Frame and Channel both use `:erlang.binary_to_term/2` with
  `:safe` to defend against atom-table exhaustion from malformed
  or hostile peers.

## [0.0.1] — 2026-05-05 (POC)

Initial walkable POC. Identity, Trust, Frame, Handlers (pure layer);
Connection, Acceptor, Handshake (transport layer with plaintext +
Ed25519 challenge-response). Not released to Hex.
