plumbob 0.1.3

FRL link training state machine for HDMI 2.1
Documentation
# Testing Strategy

plumbob's test suite is built around deterministic state machine tests. All tests run
against scripted implementations of `ScdcClient` and `HdmiPhy`; no real hardware is
required at any point.

## Test structure

All tests live alongside the code they cover in `src/training.rs` and `src/types.rs`.

### Type tests (`src/types.rs`)

Tests for the owned protocol types cover:

- Constructor invariants: `CedCount::new` strips the validity bit (`bits[14:0]` preserved,
  bit 15 masked off)
- Derived trait behaviour: `PartialEq`, `Clone`, `Copy` for all types
- Enum discriminant values: all `LtpReq` and `FfeLevels` variants match the spec encoding
- `From<LtpReq> for LtpPattern` conversions for all four LFSR variants

### State machine tests (`src/training.rs`)

The sim harness consists of two types:

- `SimScdc` — a scripted `ScdcClient` backed by a `VecDeque<TrainingStatus>`. Each call
  to `read_training_status` pops the next entry, simulating a sink's phase-by-phase
  responses. Errors can be injected by inserting a scripted error value.
- `MockPhy` — a minimal `HdmiPhy` that records calls for assertion.

Every branch in `train_at_rate` has a corresponding test:

- Successful training: `flt_ready` and `frl_start` assert after N polls; `ltp_req`
  transitions through one or more patterns before reaching `None`
- Each phase timing out independently (phases 2, 3, and 4)
- Each phase succeeding on the first iteration (`after_iterations: 0`)
- `TrainingError::Scdc` propagating from each of the three `ScdcClient` methods
- `TrainingError::Phy` propagating from `set_frl_rate` and `send_ltp`
- `into_parts` recovering the SCDC client and PHY after a completed attempt

### Trace tests (requires `alloc` feature)

The `alloc`-gated tests exercise `train_at_rate_traced` and assert on:

- Event order and variant presence for all terminal states (success, three timeout variants)
- `LtpPatternRequested` emitted only on `ltp_req` transitions, not once per poll
- `after_iterations` / `iterations_elapsed` counts matching the scripted queue
- `TrainingTrace.config` matching the `TrainingConfig` passed to `train_at_rate_traced`,
  so that timeout counts in events are interpretable against the configured limits

## Coverage

CI measures line coverage with `cargo-llvm-cov` over the `std` feature set. The baseline
is stored in `.coverage-baseline`; CI fails if coverage drops more than 0.1% below it.
New logic without tests will likely trip this.

## Philosophy

The training loop runs identically against simulated and real `ScdcClient` / `HdmiPhy`
implementations. A test that cannot run with a scripted `ScdcClient` does not belong in
this repository. Hardware is never a test dependency.