Findings + review doc: docs/reviews/001-implementation-review.md (the alkcall house pattern). Closes tunnels/review-core-crates and tunnels/review-impl. Findings: - U-1 [major, NOT fixed] — the local UDP adapter is not the framed adapter ADR-003 mandates: codec-framed bytes reach real targets, empty datagrams are EOF-shaped at the adapter (tunnel teardown), >8 KiB datagrams split, unframed target-initiated datagrams are dropped. Executable-pinned by real-socket probes (temporary test, deleted after the run). Remediation task: tunnels/fix-udp-framed-adapter. - C-1 [major, fixed] — AcceptQueue::pop lost wakeup in the check→register window (open op hangs to the establishment bound); fixed via the tokio notify_waiters contract (Notified created before the check each iteration) + multi-thread regression test. - N-4/N-5/N-7/N-8/N-9/N-10/N-11 [minor, fixed] — serialize TunnelParams in open_reverse_channel; stale doc ref; broken doc link; root re-exports (TunnelParams/Substrate/tunnel_open_spec/OP_TUNNEL_OPEN); README (publish dry-run was failing on the missing readme); harness comment; pump_against UDP framing doc note. - N-2 retracted by executable falsification (codec buffering is bounded by construction); N-6 non-finding with rationale. Verified: 63 tests default / 70 with --features local, 3x repeat-run clean both configs; clippy -D warnings (all-targets + wasm32); fmt; doc warning-free; wasm32 check; cargo publish --dry-run passes.
3.4 KiB
id, name, status, depends_on, scope, risk, impact, level, tags
| id | name | status | depends_on | scope | risk | impact | level | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| tunnels/fix-udp-framed-adapter | U-1 remediation — make UdpHalf the FRAMED adapter (ADR-003 at the local boundary) | pending |
|
moderate | medium | component | implementation |
|
Description
Review 001 finding U-1 (docs/reviews/001-implementation-review.md):
the local feature's UdpHalf (src/local/mod.rs) is NOT the framed
adapter ADR-003 mandates at the substrate boundary — it is
boundary-preserving (one datagram per poll_read/poll_write) but raw.
The [len: u16 BE] codec exists only on the session side, so
UDP-over-local tunnels:
- deliver codec-framed bytes to real targets (the target sees
[len]payload, not payload — executable-pinned in the review probes); - tear the tunnel down on an empty datagram (a raw zero-length
datagram is
Ok(())with 0 bytes filled = EOF-shaped totokio::io::copy— the F-2 violation end-to-end; the session-side codec exists precisely to prevent this); - split datagrams > ~8 KiB at the target (
tokio::io::copy'sDEFAULT_BUF_SIZEbounds each read; the raw adapter sends each chunk as its own datagram); - silently drop unframed target-initiated datagrams (the session codec parses a raw datagram's first two bytes as a length header).
The session-side tests pass because the harness's
framed_udp_echo_dial frames symmetrically at the test boundary — a
correct-shape stand-in for what connect_udp itself must do.
The fix
Apply ADR-003's placement: UdpHalf::poll_write frames the caller's
buffer (frame_datagram) and sends one datagram per framed frame;
poll_read de-frames (feed DatagramReader, emit the next payload).
Both halves of the association then speak the same framing; len=0
becomes a 2-byte frame (unambiguous with EOF — the F-2 fix
end-to-end).
Verification gates (from the review)
- A recording UDP echo server asserts the datagrams it receives are
payload bytes only and an empty datagram round-trips
(session
recv_datagramyieldsSome(b""), channel alive). - A >8 KiB datagram round-trips as ONE datagram at the target.
- An unframed target-initiated datagram resolves at the session.
- The existing
local_halvessuite stays green unchanged (its session-level round-trips are framing-symmetric today). cargo test+--features local+ wasm checks as usual; 3× repeat-run stable.
Riders (from the same review, same file)
- U-2:
connect_udpbinds("0.0.0.0", 0)— resolve the target family first (or document the v4-only posture). - U-3: size the recv scratch to the codec's MTU discipline instead of a per-tunnel 65535-byte allocation (or justify the bound).
Acceptance Criteria
UdpHalfframes on write and de-frames on read (ADR-003's placement; the pump stays raw)- The 5 verification gates pass; suites green 3× in both configs
- U-2/U-3 riders resolved or explicitly deferred with rationale
- Review 001's U-1/U-2/U-3/N-1 sections get resolution notes
References
docs/reviews/001-implementation-review.md§U-1 (executable-pinned probe evidence), §U-2, §U-3, §N-1docs/architecture/decisions/003-codec-and-udp-framing.md(the framed-adapter mandate + F-2),docs/architecture/wire.md§Datagram substratesrc/local/mod.rs(UdpHalf),src/wire.rs(the codec to compose)