Review 001 N-3 (tasks/tunnels/decide-take-framed-halves), decided before the first external consumer: - Option 1 (keep as-is, docs carry it), recorded as ADR-005 §Amendment. No external consumer exists (window open — the breaking reshape was available but undemonstrated); one take_halves semantic across substrates beats per-substrate divergence; pump_against composes the framed adapter (UdpHalf), not framed halves; and the take_framed_halves convenience is additive — it can land after the first consumer defines its shape. - consumer.md's datagram section states the posture; review 001 §N-3 resolution note landed; task marked completed. Docs-only (no code change). Verified: fmt --check, doc --no-deps warning-free, 63 default / 76 local tests green.
4.7 KiB
id, name, status, depends_on, scope, risk, impact, level, tags, completed
| id | name | status | depends_on | scope | risk | impact | level | tags | completed | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| tunnels/decide-take-framed-halves | N-3 decision — take_halves on datagram sessions hands RAW FRAMED bytes; decide the API posture before the first external consumer | completed |
|
single | low | component | research |
|
2026-09-08 |
Description
Review 001 finding N-3
(docs/reviews/001-implementation-review.md): a datagram session
exposes send_datagram/recv_datagram (codec applied) until
take_halves — then the caller owns RAW halves whose wire bytes carry
the codec framing ([len: u16 BE][payload], documented on
take_halves). The doc covers it, but it is a footgun asymmetry: the
same session flips from "codec applied" to "codec is yours" depending
on which accessor was called, and nothing in the type system warns
about it.
This is an API-posture question, not a bug: ADR-005's surface becomes ABI-stable at the first external consumer, so the decision must land before then. The options on the table:
- Keep as-is + docs (today's posture): raw framed halves are power-user territory; the doc note carries it.
- Add a convenience
take_framed_halves(the review's sketch): aDatagramReader-wrapped pair that keeps the codec so the halves API matches the datagram methods' framing posture. Additive to the rawtake_halves, which stays. - Re-shape
take_halvesfor datagram sessions (breaking, before the window closes): e.g. a datagram session'stake_halvesreturns framed-preserving halves by default, raw access via a distinct explicit method — removes the footgun entirely, at the cost of divergingtake_halvessemantics per substrate.
The decision should weigh: the pump_against shape (a UDP session
pumped against an accepted local half needs the FRAMED adapter on the
accepted side — the same framing-responsibility seam N-11's doc note
covers), what an actual consumer (alkcall's assembly layer, a
DNS-proxy shape) reaches for first, and whether a DatagramReader +
write-frame wrapper pair is small enough to just ship (option 2 is a
thin compose of existing public pieces — src/wire.rs already
exposes both codec halves of the job).
Work
- Re-read review 001 §N-3 + ADR-005 (the API-stability window);
confirm no external consumer has pinned the
take_halvesimport style yet (if one has, the window is closed — record that and choose the additive path (2) or docs-only (1)). - Write the decision as an ADR amendment (ADR-005) or a new ADR if the posture adds a public method; file the OQ only if the decision defers again.
Verification
taskgraphgraph stays acyclic; if an ADR lands,docs/ architecture/and the crate docs stay in sync (cargo doc --no-depsclean); if a method lands, the full battery + wasm checks pass.
Acceptance Criteria
- A written decision (ADR amendment or task-note resolution) with the chosen option and rationale, before the first external consumer
- If the decision adds surface: tests + battery green; review 001 §N-3 gets a resolution note
Resolution (2026-09-08)
Option 1 — keep as-is, docs carry it. Recorded as ADR-005's §Amendment (2026-09-08, N-3). Decision inputs:
- No external consumer exists (workspace grep verified 2026-09-08) — the window is open, so the breaking reshape (option 3) was available but nothing demonstrates the need.
- One
take_halvessemantic across substrates (the tunnel's wire bytes, uninterpreted) beats per-substrate divergence; the framing asymmetry is ADR-003's spec, not drift. - The
pump_againstseam composes the framed ADAPTER (UdpHalf, ADR-003's boundary codec — landed with the U-1 remediation the same day), not framed halves; option 2 would not feed that use. - Option 2 (
take_framed_halves) is additive and can land after the first consumer defines its shape without breaking anything — deferring costs nothing. Design note recorded in the ADR: anAsyncRead-faced wrapper re-collides with F-2's empty-datagram/EOF ambiguity; the codec-side framing wants accessor-shaped surface, which the session already has.
Docs sync: ADR-005 §Amendment; consumer.md's datagram section states the posture; review 001 §N-3 resolution note landed. No code change (the decision adds no surface), so the standing battery is the verification: 63 default / 76 local green, doc build clean.
References
docs/reviews/001-implementation-review.md§N-3 (the finding) and §N-11 (the adjacent pump_against framing seam)docs/architecture/decisions/005-consumer-session-owns-teardown.md(the API-stability window),src/consumer.rs(take_halves,TakenHalves),src/wire.rs(frame_datagram,DatagramReader)