docs: OQ-TN-09 direction set; alktty stream-splitting pattern as prior art
- OQ-TN-08 residue updated with the upstream posture: we own alkcall, upstream asks happen early (alktty/alkhttp precedent — both required upstream fixes/additions; only 3 downstream dependents now, each resolved issue makes future dependents cheaper). Ops-listing metadata is expected to be a small upstream alkcall change, not a workaround. - OQ-TN-09: control-frame hunch accepted (self-contained frame, alktty ADR-006 shape; dial errors are channel-closing, byte EOFs stay per-direction); frame vocabulary follows the alktty pattern; concrete set = Phase 1 ADR. - New prior art section: the alktty stream-splitting pattern (split BiStream -> ChunkReader/ChunkWriter -> pump to handle halves) proposed as the general tunnel pattern — 'tty without the five stream types'. Comparison table (tty vs TCP vs UDP codecs/handles/ pumps); implications for OQ-TN-09 (ctrl frames via stream types), OQ-TN-05 (handle = boxed AsyncRead/AsyncWrite halves; UDP flow table is the real design surface), OQ-TN-06 (helper convergence test against pump_session may be nearly free). Open: codec choice (reuse 5-byte / stripped / raw + UDP framing). - Checklist updated accordingly.
This commit is contained in:
@@ -184,6 +184,57 @@ documented. Key mechanics, all of which generalize:
|
||||
protocol likely needs only flow-level idle expiry, not
|
||||
transport-level keepalive packets — TBD in the spec.
|
||||
|
||||
## Prior art: the alktty stream-splitting pattern (`OQ-TN-09`, `OQ-TN-05`)
|
||||
|
||||
Discussed 2026-09-05. alktty tunnels io-like streams: the adapter
|
||||
splits the `BiStream` from `accept_bi` into read/write halves
|
||||
(`tokio::io::split`), wraps each half in a `ChunkReader`/`ChunkWriter`
|
||||
(`wire.rs` — the 5-byte `[stream_type: u8][length: u32 be][payload]`
|
||||
codec), and pumps chunks between the wire halves and the backend's
|
||||
`TtyHandle` halves. Strip packets on the way in, wrap packets on the
|
||||
way out; everything above the codec sees plain `AsyncRead`/`AsyncWrite`.
|
||||
|
||||
The proposal: that same pattern (or close) may be *the* tunnel pattern.
|
||||
A tunnel is then literally "tty without the five stream types" — split
|
||||
the channel's `BiStream`, wrap the halves in a codec, pump to/from
|
||||
substrate halves. What differs per concern is only the codec and the
|
||||
far-end handle:
|
||||
|
||||
| | alktty | alktunnels (TCP) | alktunnels (UDP) |
|
||||
|---|---|---|---|
|
||||
| wire codec | 5-byte, 5 stream types | raw pass-through or minimal framing | length-prefixed datagrams (tun2proxy-style) |
|
||||
| far end | `TtyHandle` (stdin/stdout/stderr/ctrl) | `TcpStream` split halves | `UdpSocket` + flow table |
|
||||
| pumps | 3 (stdout/stderr + stdin, exit future coordinates) | 2 (the ADR-078 shape) | 2 + flow expiry |
|
||||
|
||||
Implications:
|
||||
|
||||
- **OQ-TN-09 falls out naturally.** alktty's `STREAM_CTRL_IN/OUT`
|
||||
(flag frames inside the same codec) is the precedent for the
|
||||
establishment/error frame: same codec, one extra stream type
|
||||
(`TUNNEL_CTRL` or similar), typed control messages — rather than a
|
||||
separate framing layer. alktty's zero-length-sentinel EOF semantics
|
||||
carry over unchanged.
|
||||
- **OQ-TN-05 (backend trait) gets a concrete shape to judge.** If
|
||||
tunnels are "split + wrap + pump," the far-end handle is just
|
||||
"(AsyncRead + AsyncWrite) halves" for stream substrates — which is
|
||||
either a very thin trait or no trait (fn returning boxed halves).
|
||||
The UDP case's flow table is the real differentiator to design
|
||||
around, not the stream case.
|
||||
- **Possible convergence with OQ-TN-06 (two-pump helper).** If the
|
||||
pump loop shape is identical to alktty's modulo the number of pumps,
|
||||
a shared helper extraction (this crate's second-consumer moment,
|
||||
alknet ADR-078) should be evaluated against alktty's `pump_session`
|
||||
too — the convergence test the ADR asked for may be nearly free.
|
||||
- **Wasm story intact** — the codec is pure byte manipulation; the
|
||||
split/pump plumbing is tokio-async, no substrate types in the
|
||||
protocol layer. Same as alktty.
|
||||
|
||||
Open: whether the tunnel codec is *literally* alktty's 5-byte format
|
||||
with different stream-type constants (reuse), a stripped 5-byte
|
||||
variant (1 stream type + ctrl), or raw pass-through with framing only
|
||||
for UDP (the OQ-TN-01 reframe suggests TCP needs nothing beyond the
|
||||
channels chunk stream). Phase 1 ADR, before the first consumer.
|
||||
|
||||
## Open Questions
|
||||
|
||||
These are the design questions Phase 0 must resolve (or explicitly defer)
|
||||
@@ -501,6 +552,15 @@ produced tunnels — or whether `params`-describing metadata rides
|
||||
alongside the operation spec. That is an alkcall ADR-047 interaction,
|
||||
not a new mechanism.
|
||||
|
||||
**Upstream posture (2026-09-05):** we own the upstream. Both prior
|
||||
downstream crates (alktty, alkhttp — `/workspace/@alkdev/alkhttp`)
|
||||
required fixes/additions to alkcall, and the rule is to make those
|
||||
asks *early*: there are only three downstream dependents right now,
|
||||
and each issue resolved upstream makes the next dependent cheaper. So
|
||||
if the ops listing needs per-resource metadata (or anything else in
|
||||
the ADR-047 interaction), the expectation is a small upstream alkcall
|
||||
change in Phase 0/1 — not a workaround in this crate.
|
||||
|
||||
### OQ-TN-09: Lifecycle, teardown, and error reporting
|
||||
|
||||
The two-pump shape gives byte-level teardown for free (EOF sentinels;
|
||||
@@ -518,11 +578,15 @@ POC issue #6). What's missing is the error/level above bytes:
|
||||
(standard two-pump behavior) — is that always desired, or does the
|
||||
consumer need a "close both" control?
|
||||
|
||||
**Status:** open — needs a wire-format decision (ADR) if an error frame
|
||||
is added. Half-answer (hunch): a self-contained control frame (alktty
|
||||
ADR-006 shape) carrying an establishment result/error, sent before any
|
||||
data chunk; dial errors are tunnel-closing (the whole channel dies),
|
||||
whereas byte-level EOFs stay per-direction.
|
||||
**Status: direction set 2026-09-05** — the original half-answer is
|
||||
accepted: a self-contained control frame (alktty ADR-006 shape)
|
||||
carrying an establishment result/error, sent before any data chunk;
|
||||
dial errors are tunnel-closing (the whole channel dies), whereas
|
||||
byte-level EOFs stay per-direction. Beyond that, the frame vocabulary
|
||||
should follow the alktty stream-splitting pattern (§Prior art: the
|
||||
alktty stream-splitting pattern) rather than invent a parallel
|
||||
mechanism. Concrete frame set lands as a Phase 1 ADR (wire-stable
|
||||
before the first consumer).
|
||||
|
||||
### OQ-TN-10: POC scope for what remains unvalidated
|
||||
|
||||
@@ -601,8 +665,15 @@ Candidate reading for the research specialist (to be expanded):
|
||||
applies as-is; ops listing (ADR-047) is tunnel-resource
|
||||
discovery; `-D` = "tunnel a socks5 connection" (target selection
|
||||
in the socks5 protocol, not params). Residue: per-resource
|
||||
metadata in the ops listing (alkcall ADR-047 interaction,
|
||||
Phase 1)
|
||||
metadata in the ops listing — small upstream alkcall ask,
|
||||
early per the upstream posture (alktty/alkhttp precedent)
|
||||
- [x] Lifecycle/error direction set (OQ-TN-09) — establishment/error
|
||||
control frame accepted in principle (dial errors are
|
||||
channel-closing); frame vocabulary follows the alktty
|
||||
stream-splitting pattern; concrete set = Phase 1 ADR
|
||||
- [ ] Codec decision (new, from the alktty pattern prior art) — reuse
|
||||
5-byte format vs stripped variant vs raw pass-through + UDP
|
||||
framing; feeds OQ-TN-07 (ALPN) and the OQ-TN-05 trait shape
|
||||
- [ ] Decision input: backend trait vs no-trait (OQ-TN-05), now
|
||||
including the hub re-produce composition question
|
||||
- [ ] Targeted POC(s) run + summary (OQ-TN-10) — UDP first, reverse
|
||||
|
||||
Reference in New Issue
Block a user