fix: remove the zombie DatagramCodecError::InvalidLength variant

The coverage review found `InvalidLength {declared, have}` is a
zombie: `DatagramReader::feed` never returns `Err` — it buffers
partial frames indefinitely, and the truncated-stream contract is
carried by `is_mid_datagram` (the codec diagnostic) plus
`TunnelIoError::TruncatedDatagram` (the session surface). The
variant's doc claimed it was the truncated-stream error; no spec
(ADR-003, wire.md, bast.md) names it, and no external consumer
exists (verified 2026-09-08 per ADR-005's N-3 amendment), so the
API window is open — removed before the first consumer pins it.

Also removes the `unreachable!` arm its removal strands in the
`local` adapter's recv mapping (a no-panic path; single-variant
destructure now), and records the planned-shape correction in the
completed wire-codec task doc.

Verified: cargo test (--all-features and default), clippy
--all-targets -D warnings, fmt --check, wasm32 check + clippy — all
clean.
This commit is contained in:
glm-5.3-flash committed 2026-09-09 06:48:44 +00:00
1 parent 0bf4da3bb6
commit 4014ba66a9
3 files changed
+29 -30

No files matched your search

+14 -15
View File
@@ -317,21 +317,20 @@ impl AsyncRead for UdpHalf {
.expect("scratch allocated above");
match this.sock.try_recv(scratch) {
Ok(n) => {
let framed = frame_datagram(&scratch[..n]).map_err(|e| match e {
// A >u16 datagram cannot exist on a well-formed
// wire (the IP theoretical max is 65507); treat it
// as the fail-loud framing violation it is.
DatagramCodecError::Oversize(len, max) => std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!(
"udp datagram {len} bytes exceeds the codec frame bound {max} \
(truncation fails loud — OQ-TN-13)"
),
),
DatagramCodecError::InvalidLength { .. } => {
unreachable!("frame_datagram never yields InvalidLength")
}
})?;
let framed = frame_datagram(&scratch[..n]).map_err(
|DatagramCodecError::Oversize(len, max)| {
// A >u16 datagram cannot exist on a well-formed
// wire (the IP theoretical max is 65507); treat
// it as the fail-loud framing violation it is.
std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!(
"udp datagram {len} bytes exceeds the codec frame bound {max} \
(truncation fails loud — OQ-TN-13)"
),
)
},
)?;
if framed.len() <= buf.remaining() {
buf.put_slice(&framed);
} else {
+7 -10
View File
@@ -32,20 +32,17 @@ pub const MAX_DATAGRAM_LEN: usize = u16::MAX as usize;
const DATAGRAM_LEN_FIELD: usize = 2;
/// Codec errors: oversize at frame time, and the truncated-stream
/// error a mid-datagram stream end maps to (the fail-loud posture,
/// OQ-TN-13 — never a silent partial datagram).
/// Codec errors: oversize at frame time. The truncated-stream case is
/// not a codec error — the decoder buffers partial frames indefinitely
/// (`is_mid_datagram` is the diagnostic) and the SESSION surfaces a
/// stream end mid-datagram as `TunnelIoError::TruncatedDatagram` (the
/// fail-loud posture, OQ-TN-13 — never a silent partial datagram).
#[derive(Debug, Error)]
pub enum DatagramCodecError {
/// A datagram larger than [`MAX_DATAGRAM_LEN`] was framed — the
/// u16 length field would wrap. Rejected at frame time.
#[error("datagram too large for u16 length prefix: {0} bytes (max {1})")]
Oversize(usize, usize),
/// The stream ended mid-datagram (declared length not satisfied).
/// A clean peer never ends the stream mid-datagram; this is a
/// truncated-stream error, not a partial datagram.
#[error("unexpected end of datagram buffer: declared {declared}, have {have}")]
InvalidLength { declared: usize, have: usize },
}
/// Frame one datagram into the chunk stream: `[len: u16 BE][payload]`.
@@ -131,8 +128,8 @@ impl DatagramReader {
/// `true` while a partial datagram is in flight (for teardown
/// diagnostics — a clean peer never ends the stream mid-datagram;
/// an end while this is set is [`DatagramCodecError::InvalidLength`]'s
/// condition).
/// an end while this is set is the session's
/// `TruncatedDatagram` condition).
pub fn is_mid_datagram(&self) -> bool {
self.current.is_some()
}
+8 -5
View File
@@ -23,7 +23,7 @@ pin.
```rust
pub const MAX_DATAGRAM_LEN: usize = u16::MAX as usize; // 65535
pub struct DatagramCodecError { .. } // thiserror: Oversize(usize), InvalidLength(...)
pub struct DatagramCodecError { .. } // thiserror: Oversize(usize, usize) (planned shape; InvalidLength removed post-review — see Notes)
pub fn frame_datagram(payload: &[u8]) -> Result<Bytes, DatagramCodecError>
// [len: u16 BE][payload]; len=0 is a legal empty datagram; >65535 = Oversize at frame time
@@ -90,9 +90,11 @@ the POC proved no collision).
invariant is load-bearing, so the module doc states why raw
pass-through is structurally broken for UDP).
- Error naming per the task's API: `Oversize(usize, usize)` (was
POC's `TooLarge`) + `InvalidLength {declared, have}` (the
truncated-stream shape — the OQ-TN-13 fail-loud posture's codec-side
anchor).
POC's `TooLarge`). (2026-09-09: the `InvalidLength` variant was
REMOVED post-review — `feed` never returned it; the truncated-stream
contract is `is_mid_datagram` + the session's `TruncatedDatagram`
instead, per the coverage-review commit. A completed task doc
records its planned shape, not corrections made after.)
- `feed` returns `Vec<Bytes>` per the task API (the POC's
`Vec<Datagram>` wrapper dropped — `Bytes` is the payload; the mux
handoff is zero-copy via `BytesMut::freeze`).
@@ -113,7 +115,8 @@ the POC proved no collision).
`src/wire.rs` complete: `frame_datagram` (Oversize at frame time,
`len=0` legal), `DatagramReader` (incremental decoder, `is_mid_datagram`
teardown diagnostic), `DatagramCodecError {Oversize, InvalidLength}` —
teardown diagnostic), `DatagramCodecError {Oversize}` (originally
sketched `{Oversize, InvalidLength}`; see the 2026-09-09 note above) —
the ADR-003/BAST contract in executable form. 8 codec tests + 6 params
tests = 14 passing. Verified: cargo test, clippy --all-targets -D
warnings (native + wasm32), fmt --check, wasm32 check — all clean.