review: phase-gate review 001 — spec conformance of the v1 implementation
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.
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
---
|
||||
id: tunnels/fix-udp-framed-adapter
|
||||
name: "U-1 remediation — make UdpHalf the FRAMED adapter (ADR-003 at the local boundary)"
|
||||
status: pending
|
||||
depends_on: [tunnels/review-impl]
|
||||
scope: moderate
|
||||
risk: medium
|
||||
impact: component
|
||||
level: implementation
|
||||
tags: [local, udp, codec, adr-003, review-remediation]
|
||||
---
|
||||
|
||||
## 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:
|
||||
|
||||
1. deliver codec-framed bytes to real targets (the target sees
|
||||
`[len]payload`, not payload — executable-pinned in the review
|
||||
probes);
|
||||
2. tear the tunnel down on an empty datagram (a raw zero-length
|
||||
datagram is `Ok(())` with 0 bytes filled = EOF-shaped to
|
||||
`tokio::io::copy` — the F-2 violation end-to-end; the session-side
|
||||
codec exists precisely to prevent this);
|
||||
3. split datagrams > ~8 KiB at the target (`tokio::io::copy`'s
|
||||
`DEFAULT_BUF_SIZE` bounds each read; the raw adapter sends each
|
||||
chunk as its own datagram);
|
||||
4. 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)
|
||||
|
||||
1. A recording UDP echo server asserts the datagrams it receives are
|
||||
**payload bytes only** and an **empty datagram round-trips**
|
||||
(session `recv_datagram` yields `Some(b"")`, channel alive).
|
||||
2. A >8 KiB datagram round-trips as ONE datagram at the target.
|
||||
3. An unframed target-initiated datagram resolves at the session.
|
||||
4. The existing `local_halves` suite stays green unchanged (its
|
||||
session-level round-trips are framing-symmetric today).
|
||||
5. `cargo test` + `--features local` + wasm checks as usual; 3×
|
||||
repeat-run stable.
|
||||
|
||||
### Riders (from the same review, same file)
|
||||
|
||||
- U-2: `connect_udp` binds `("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
|
||||
|
||||
- [ ] `UdpHalf` frames 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-1
|
||||
- `docs/architecture/decisions/003-codec-and-udp-framing.md` (the
|
||||
framed-adapter mandate + F-2), `docs/architecture/wire.md`
|
||||
§Datagram substrate
|
||||
- `src/local/mod.rs` (`UdpHalf`), `src/wire.rs` (the codec to compose)
|
||||
Reference in New Issue
Block a user