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:
1 parent
0bf4da3bb6
commit
4014ba66a9
3 files changed
+29
-30
No files matched your search
+14
-15
@@ -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
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
Reference in new issue
Block a user