chore: consume alkcall 0.5.0; OQ-TN-09 resolved by ADR-049
alkcall 0.5.0 landed the review 006 remediation (filed from this crate's Phase 0 pass): - E-01/N-1: channel-open establishment phase (ADR-049) — register_openable_with_establisher, bounded await, teardown-on- failure, typed channel:open_failed reply (reason in details); ChannelClient::open_channel returns ChannelOpenError - E-02: OperationSpec.description disclosed via discovery - E-03/E-04/N-2: teardown-race log, early-arrival bound docs, count accessor alktunnels updates: - Cargo.toml: alkcall 0.4.0 -> 0.5.0 (lockfile resolves 0.5.0) - AGENTS.md convention 11: pin note updated; ADR-049 marked load-bearing (tunnel opens use register_openable_with_establisher) - phase-0-findings OQ-TN-09: RESOLVED by ADR-049 — the in-band control-frame hunch is superseded (establishment is the open op's reply, not a stream frame); residual for Phase 1 narrowed to half-open semantics; v1 needs no mid-stream control frame - phase-0-findings OQ-TN-08: per-op metadata residue resolved by E-02 (description field; OQ-40 enumerate half stays deferred) - tun2proxy prior-art + alktty-pattern sections: frame-vocabulary notes updated to point at the ADR-049 supersession - upstream posture paragraph updated: review 006 is the working proof of the ask-early rule Verification: cargo test (0 tests, ok), clippy --all-targets -D warnings, fmt --check, wasm32 check, doc --no-deps — all clean
This commit is contained in:
@@ -170,9 +170,12 @@ documented. Key mechanics, all of which generalize:
|
||||
prior art, not speculation — raises confidence in the OQ-TN-02
|
||||
half-answer considerably.
|
||||
- The frame-type set (DATA/KEEPALIVE/ERR) is a useful minimal
|
||||
vocabulary — it maps onto OQ-TN-09's establishment/error frame
|
||||
question (tun2proxy uses flag packets, alktty uses typed control
|
||||
chunks; both are self-contained frames inside the data stream).
|
||||
vocabulary — historically mapped onto OQ-TN-09's establishment
|
||||
question, now superseded there by alkcall ADR-049 (establishment
|
||||
is the open op's reply, not an in-stream frame). KEEPALIVE and
|
||||
ERR both drop (channels owns liveness; establishment is
|
||||
call-level). The vocabulary survives only as anti-prior-art
|
||||
context.
|
||||
- Per-datagram addressing (SOCKS5-style) vs per-channel addressing
|
||||
(fixed target at open) is a real fork for the params design: TCP
|
||||
tunnels fix the target at open; UDP associations may either fix
|
||||
@@ -208,12 +211,13 @@ far-end handle:
|
||||
|
||||
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-09: partially superseded by alkcall ADR-049.** The
|
||||
establishment/error half is resolved at the call layer (the open op
|
||||
replies `channel:open_failed`; no in-stream establishment frame).
|
||||
What the ctrl-frame pattern still informs: whether a *mid-stream*
|
||||
control frame is ever needed (v1 likely not — see OQ-TN-09's
|
||||
resolved status), and the alktty zero-length-sentinel EOF semantics
|
||||
carry over unchanged either way.
|
||||
- **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
|
||||
@@ -571,21 +575,21 @@ the same posture alktty already uses:
|
||||
the socks5 resource governs everything reachable through it, plus
|
||||
whatever policy the socks5 implementation itself applies downstream.
|
||||
|
||||
Residue for Phase 1 (spec-shape, not research): confirm the
|
||||
ops-listing surface carries enough per-resource metadata (substrate
|
||||
type, resource name/description) for a consumer UI to distinguish
|
||||
produced tunnels — or whether `params`-describing metadata rides
|
||||
alongside the operation spec. That is an alkcall ADR-047 interaction,
|
||||
not a new mechanism.
|
||||
Residue for Phase 1 (spec-shape, not research): **resolved 2026-09-06
|
||||
by alkcall 0.5.0** (review 006 E-02): `OperationSpec.description`
|
||||
(`with_description`) lands additively and round-trips through
|
||||
`services/schema` / `from_call` / `op/register`, disclosed by
|
||||
`services/list` and `services/list-peers` when set. The tunnel open op
|
||||
carries its description; the live resource-enumeration half (OQ-40)
|
||||
stays deferred and is not needed for v1.
|
||||
|
||||
**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.
|
||||
**Upstream posture (2026-09-05, updated 2026-09-06):** we own the
|
||||
upstream, and the rule is to make asks early. The E-01/E-02 sweep
|
||||
(alkcall review 006, filed from this crate's Phase 0) is the working
|
||||
proof: the establishment phase (ADR-049), the typed
|
||||
`ChannelOpenError`, and `OperationSpec.description` all landed in
|
||||
0.5.0 within a day of being filed — alktunnels was the consumer that
|
||||
pulled them through. Future upstream asks follow the same path.
|
||||
|
||||
### OQ-TN-09: Lifecycle, teardown, and error reporting
|
||||
|
||||
@@ -604,29 +608,48 @@ 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: direction set 2026-09-05; vocabulary informed 2026-09-06**
|
||||
(survey `ssh-socks5-survey.md` §Comparison). 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. The alktty-style JSON frame is the
|
||||
strictly richest of the four prior-art vocabularies (SSH code+desc,
|
||||
SOCKS5 codes-only, udpgw 1 opaque bit — the counterexample to avoid).
|
||||
**Status: resolved 2026-09-06 by alkcall ADR-049** (alkcall 0.5.0,
|
||||
review 006 E-01 — the establishment gap filed from this crate's Phase
|
||||
0 pass). The in-band control-frame hunch below is **superseded**:
|
||||
establishment failure is now the open op's reply, not a frame on the
|
||||
channel stream.
|
||||
|
||||
Survey inputs for the Phase 1 frame ADR:
|
||||
- Content: establishment ack + failure frame with a small reason-code
|
||||
set mirroring SSH's four (policy-denied / dial-failed /
|
||||
unknown-resource-or-substrate / resource-shortage — mapping 1:1 onto
|
||||
what an open handler can produce: ACL denial, dial failure,
|
||||
unregistered resource/substrate, channels limits) + a detail string
|
||||
(SOCKS5's network/host/refused granularity lives in `detail`, not
|
||||
more codes — codes are wire-stable, detail strings are not).
|
||||
- Failure ⇒ channel closes before data flows: all four prior arts
|
||||
agree; there is no "fail the open but keep the channel" prior art,
|
||||
and none is needed (consumer just opens a new channel).
|
||||
- The frame does NOT need: window adjustments (channels owns
|
||||
backpressure), keepalives (channels owns liveness), fragmentation
|
||||
(not the tunnel's job), per-datagram error replies.
|
||||
- The producer's tunnel open op registers via
|
||||
`ChannelCore::register_openable_with_establisher`; the establisher
|
||||
(`OpenEstablisher`) runs as an awaited, bounded establishment phase
|
||||
— semantically validate params, **dial the target** — before the
|
||||
open op replies. On failure the just-allocated channel is torn down
|
||||
(allocation and teardown balance; ledger un-increment) and the
|
||||
consumer receives `channel:open_failed` with
|
||||
`details: {reason, message}`, `reason ∈ dial_failed /
|
||||
unknown_resource / resource_shortage / handler_error / timeout` —
|
||||
the SSH contract consumer-visibly (a failed open never returns a
|
||||
`channel_id`). No phantom channel, no establishment frame needed on
|
||||
the data stream.
|
||||
- Implementation note (ADR-049 amendment): the establisher takes
|
||||
`(input, auth)` only — the channel's yield-once `BiStream` belongs
|
||||
exclusively to the pump handler. The tunnel establisher hands the
|
||||
dialed connection to the pump handler through its own path (e.g. a
|
||||
oneshot/`Arc<Mutex<Option<_>>>`), not via the open-op input.
|
||||
- What remains for this crate's Phase 1 ADR (narrowed from the
|
||||
original frame-vocabulary question):
|
||||
- Half-open semantics: one direction EOFs, the other keeps pumping
|
||||
(standard two-pump behavior) — the only establishment/teardown
|
||||
question not answered upstream. Dial errors are fully
|
||||
establishment-phase now; byte-level EOFs stay per-direction
|
||||
(unchanged).
|
||||
- Whether the tunnel ever needs a *mid-stream* control frame
|
||||
(post-establishment). Per ADR-049 §6's pinned posture,
|
||||
pump-phase failures are EOF-shaped by design; the SSH/SOCKS5
|
||||
survey found no prior art for in-stream control after
|
||||
establishment beyond udpgw's KEEPALIVE (dropped — channels owns
|
||||
liveness). v1 likely needs none; if a UDP flow table ever needs
|
||||
in-band signaling, that is a substrate-framing decision, not a
|
||||
base-wire one.
|
||||
|
||||
Original question (retained for context): how does a failed target
|
||||
dial reach the consumer, is there an establishment ack before byte
|
||||
pumping, and what are the half-open semantics?
|
||||
|
||||
### OQ-TN-10: POC scope for what remains unvalidated
|
||||
|
||||
@@ -719,14 +742,19 @@ Candidate reading for the research specialist (to be expanded):
|
||||
ownership assumed on the far side; alkcall's existing ACL
|
||||
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 — 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
|
||||
in the socks5 protocol, not params). Per-op metadata residue
|
||||
RESOLVED 2026-09-06: alkcall 0.5.0 review 006 E-02 lands
|
||||
`OperationSpec.description` (round-trips through discovery);
|
||||
the live resource-enumeration half (OQ-40) stays deferred and
|
||||
is not needed for v1
|
||||
- [x] Lifecycle/error resolved (OQ-TN-09) — superseded 2026-09-06 by
|
||||
alkcall ADR-049 (0.5.0): establishment is the open op's awaited
|
||||
phase (`register_openable_with_establisher`); dial failure is a
|
||||
typed `channel:open_failed` call error (reason ∈ dial_failed /
|
||||
unknown_resource / resource_shortage / handler_error / timeout),
|
||||
never a phantom channel. Residual for Phase 1: half-open
|
||||
semantics only; v1 needs no mid-stream control frame
|
||||
- [ ] Codec decision (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
|
||||
|
||||
Reference in New Issue
Block a user