fix(hardware): drop-instead-of-truncate subcarrier count in 802.11bf bridge (ADR-157 §B1)

OpportunisticCsiBridge::ingest built CsiReportPayload.n_subcarriers via
`self.amp_accum.len() as u16`, which would silently wrap a count above 65_535.
Replace with `u16::try_from(...).ok()?` (drop-instead-of-truncate). Disclosed
honestly as defense-in-depth on an UNREACHABLE path: ingest already gates
subcarrier_count > MAX_REPORT_SUBCARRIERS (484) at entry and report.validate()
rejects oversized counts downstream, so the cast can never wrap in practice.
Correct-by-construction rather than gate-dependent; no behavior change, no new
test (the gate prevents the input that would exercise it).

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
ruv 2026-06-11 21:00:32 -04:00
parent 8fb6ef6547
commit 0b78eb6e03
1 changed files with 9 additions and 1 deletions

View File

@ -289,8 +289,16 @@ impl OpportunisticCsiBridge {
}
let scale = self.frames_in_batch as f64;
// Drop-instead-of-truncate: `as u16` would silently wrap a subcarrier
// count above 65_535. That count is already gated to
// `<= MAX_REPORT_SUBCARRIERS` (484) at `ingest`'s entry, so this branch
// is unreachable in practice — but `try_from().ok()?` makes the
// construction correct-by-construction rather than relying on the
// upstream gate, and drops the batch cleanly if the invariant ever
// changes (ADR-157 §B1, defense-in-depth — not a live bug).
let n_subcarriers = u16::try_from(self.amp_accum.len()).ok()?;
let payload = CsiReportPayload {
n_subcarriers: self.amp_accum.len() as u16,
n_subcarriers,
amplitudes: self.amp_accum.iter().map(|a| (a / scale) as f32).collect(),
phases: self
.phase_sin_accum