speed-cli 1.0.0

Comprehensive multi-protocol network performance testing CLI (TCP, UDP, QUIC, HTTP/1.1, HTTP/2, h2c, HTTP/3)
# Architecture

`speed-cli` is a single Rust crate built as both a library (`src/lib.rs`, used by
integration tests and embedders) and a thin binary (`src/main.rs`, which just
parses the CLI and dispatches into the library).

## Control plane vs data plane

The tool separates a small **control plane** from the per-protocol **data plane**:

- **Control plane** (`src/control/`): the server binds *every* enabled test
  listener up front — each on its own OS-assigned ephemeral port — then publishes
  a JSON **manifest** over a single HTTP/1.1 control endpoint (default `:9000`).
  The client (or suite) handshakes against that one port, discovers the real
  per-protocol ports, and verifies wire-protocol compatibility before any test
  runs. This is why a user only ever picks the control port.
- **Data plane** (`src/performance/`): one module per protocol (`tcp/`, `udp/`,
  `quic/`, `http/`), each with a client and server half, plus `suite.rs` which
  drives every advertised protocol in sequence for an apples-to-apples report.

See [docs/PROTOCOL.md](docs/PROTOCOL.md) for the wire formats.

## Measurement engine

`src/performance/engine/` is the shared measurement core that every protocol
client builds on:

- **`sampler.rs`** — warmup-aware timing primitives (`offset_us`,
  `measurement_duration_us`).
- **`collector.rs`** — a generic `StatsCollector<T>` that drains samples from an
  unbounded channel into a buffer on one task while a second task refreshes a
  live progress bar. Uses `parking_lot::Mutex`, so a panicked producer cannot
  poison the buffer.
- **`progress.rs`** — progress-bar construction, globally gated (hidden under
  `--quiet` / non-TTY).

Each test produces a stream of **samples** (`report::Sample`): a half-open
interval `[t_start_us, t_start_us + duration_us)` on the test's monotonic time
axis, a byte count, an outcome (success/failure), and a `is_warmup` flag.
Samples taken during the warmup window are excluded from the reported numbers so
results reflect steady state. Aggregation (throughput percentiles, latency
percentiles, jitter) happens at report time.

Latency probes are recorded the same way — one `LatencyMeasurement {
t_start_us, rtt_us }` per probe — so a latency result is a time-line, not just a
summary. On top of that series the report derives tail percentiles, adaptive
**spike detection**, and a time-vs-latency chart (a terminal sparkline plus a
self-contained SVG in the HTML report). The UDP `latency-under-load` test type
(`--type latency-load`) drives this end to end: it captures an idle baseline,
then probes latency at ~200 Hz while saturating the link, and reports the
idle-vs-loaded "bufferbloat" inflation — stored in the report's
`latency_under_load` field (added in schema version 6) and the WiFi / AP
latency-spike signal.

## Reports

`src/report/` defines the result types and serialization:

- `TestReport` carries the environment snapshot, the two peers' identities, the
  test configuration, and the per-stream samples. It is versioned by
  `REPORT_SCHEMA_VERSION`; imports reject any other version (no backward-compat
  shims — CBOR is binary and compact).
- `src/utils/{export,import}.rs` handle CBOR (the canonical, re-importable
  format) and `src/renderer/` renders a self-contained HTML report. There is no
  JSON report format by design.

## Output discipline

The report (and "exported to X" confirmations) go to **stdout**; every log line,
progress bar, and diagnostic goes to **stderr** via `tracing`
(`src/utils/logging.rs`). So `speed-cli client ... > out.cbor` captures only the
report. Verbosity (`-v/-vv/-q`, `RUST_LOG`) and color (`--color`, `NO_COLOR`) are
global flags.

## Tooling

Tasks and tooling are managed by [mise](https://mise.jdx.dev); git hooks by
[hk](https://hk.jdx.dev). CI (`.github/workflows/`) runs the static gate
(`fmt`, `clippy -D warnings`, `typos`, `cargo-machete`) plus the test suite on
Linux/macOS/Windows, and release-plz automates versioned GitHub Releases. See
[CONTRIBUTING.md](CONTRIBUTING.md).