chore: consume alkcall 0.6.0; OQ-TN-06 resolved by ADR-050

alkcall 0.6.0 landed the review 007 remediation (filed from this
crate's UDP POC pass):
- R-01: Establishment carries the plan (ADR-049 amendment 2) —
  typed-opaque ChannelPlan, OpenHandler gains the plan param, the
  wrapper threads it; the POC's side-channel HandleHandoff and its
  same-resource race are dead (the establisher returns the dialed
  handle: Ok(Establishment::new(plan)))
- R-02: OpenHandler JoinHandle lifetime contract documented (early
  return = teardown-at-birth) + yield-once acceptance flag and
  debug! birth-teardown hint
- R-03: pump_bidi pinned upstream (ADR-050) — two pumps,
  shutdown-on-completion, (u64, u64) copy counts, errors EOF-shaped

alktunnels updates:
- Cargo.toml: alkcall 0.5.0 -> 0.6.0 (lockfile resolves 0.6.0)
- AGENTS.md convention 8: use alkcall channels::pump_bidi, do not
  hand-roll; await it inline inside the OpenHandler's task
- AGENTS.md convention 11: pin note updated; amendment 2 marked
  load-bearing (Establishment::new replaces side-channel handoff)
- AGENTS.md convention 13: fixed ADR citation bug (was "alkcall
  ADR-024, ADR-050" — those are peer-graph-routing and pump-bidi;
  intended targets are alknet ADR-024/ADR-050 with their alkcall
  ports ADR-019/ADR-011)
- AGENTS.md architecture context: ADR-050 + ADR-049 amendment 2 rows
- phase-0-findings OQ-TN-06: RESOLVED — pump_bidi landed upstream;
  the POC is cited as convergence input alongside alktty and the
  assembly-layer copies; Phase 1 consumes the helper
- phase-0-findings OQ-TN-09: implementation note updated —
  Establishment::new(plan) replaces the handoff sketch
- poc-summary: resolutions addendum for both upstream findings
  (R-01/R-02/R-03 with the typed-opaque and (u64, u64) deviations
  recorded); references note 0.6.0 supersession

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:
2026-09-07 09:27:08 +00:00
parent 6beabe9457
commit b3b00f37bd
5 changed files with 90 additions and 26 deletions
+26 -15
View File
@@ -65,8 +65,8 @@ just spawned implementation agents.
expected on public API. Inline `//` comments only when the user asks expected on public API. Inline `//` comments only when the user asks
or when a non-obvious safety/correctness constraint would otherwise be or when a non-obvious safety/correctness constraint would otherwise be
missed (e.g., "a two-pump tunnel must shut down the opposite sink on missed (e.g., "a two-pump tunnel must shut down the opposite sink on
pump completion — `try_join!` alone deadlocks; see alkcall's pump completion — `try_join!` alone deadlocks; see alkcall ADR-050's
channels-adapter spec / alknet ADR-078"). `pump_bidi` / alknet ADR-078").
2. **Error handling** — `thiserror` for library error types 2. **Error handling** — `thiserror` for library error types
(`TunnelError`; `HandlerError`/`StreamError` come from (`TunnelError`; `HandlerError`/`StreamError` come from
@@ -131,10 +131,14 @@ just spawned implementation agents.
canonical two-pump handler (one pump per direction). Each pump MUST canonical two-pump handler (one pump per direction). Each pump MUST
shut down the opposite sink when it completes; `tokio::try_join!` shut down the opposite sink when it completes; `tokio::try_join!`
alone deadlocks. This was POC-validated in the alknet-channels POC alone deadlocks. This was POC-validated in the alknet-channels POC
(Target 3) and pinned as alknet ADR-078. The channels layer drops (Target 3), pinned as alknet ADR-078, and the helper is pinned
all per-channel senders on transport EOF — rely on that for upstream as alkcall `channels::pump_bidi` (ADR-050, review 007
teardown, and emit EOF sentinels (zero-length chunks) on clean R-03) — use it; do not hand-roll the two-pump shape. The channels
sink shutdown. layer drops all per-channel senders on transport EOF — rely on
that for teardown, and emit EOF sentinels (zero-length chunks) on
clean sink shutdown. Await `pump_bidi` inline inside the
`OpenHandler`'s task — the returned `JoinHandle` must track the
data-plane lifetime (R-02; early return = teardown-at-birth).
9. **No forced local binding** — a tunnel must not require the producer 9. **No forced local binding** — a tunnel must not require the producer
(or consumer) to bind a local port. The POC's TCP-tunnel shape (or consumer) to bind a local port. The POC's TCP-tunnel shape
@@ -163,12 +167,14 @@ just spawned implementation agents.
`alkcall::core`. Do not vendor copies into this crate. alkcall is `alkcall::core`. Do not vendor copies into this crate. alkcall is
v0.5.x — breaking changes are expected at this major-zero stage; v0.5.x — breaking changes are expected at this major-zero stage;
this is an early consumer, so we find and fix issues upstream this is an early consumer, so we find and fix issues upstream
rather than working around them. Pin `alkcall = "0.5.0"` and bump rather than working around them. Pin `alkcall = "0.6.0"` and bump
deliberately. The 0.5.0 establishment phase (ADR-049) is deliberately. The 0.6.0 establishment surface (ADR-049 + amendment
load-bearing for this crate: tunnel opens use 2) is load-bearing for this crate: tunnel opens use
`register_openable_with_establisher` so a refused target dial is `register_openable_with_establisher` so a refused target dial is
a typed `channel:open_failed` call error, never a phantom a typed `channel:open_failed` call error, never a phantom channel,
channel. and the establisher returns the dialed handle via
`Establishment::new(plan)` (typed-opaque `ChannelPlan`) — no
side-channel handoff.
12. **BAST document for the wire format** — when the tunnel wire format 12. **BAST document for the wire format** — when the tunnel wire format
gains binary framing (if any beyond pass-through), it carries a gains binary framing (if any beyond pass-through), it carries a
@@ -190,7 +196,8 @@ just spawned implementation agents.
(`provider.owns(id_ref, kind, &id, "tunnel")` — the 4-arg shape; (`provider.owns(id_ref, kind, &id, "tunnel")` — the 4-arg shape;
`OwnershipStore::record` is the 3-arg shape). Tunnels reach local `OwnershipStore::record` is the 3-arg shape). Tunnels reach local
networks — treat the open gate as the security boundary. See networks — treat the open gate as the security boundary. See
alkcall ADR-024, ADR-050. alknet ADR-024 (registry layering, alkcall ADR-019), alknet
ADR-050 (ownership, alkcall ADR-011).
14. **Feature flags** — substrate backends may be feature-gated if the 14. **Feature flags** — substrate backends may be feature-gated if the
need arises. The base crate should compile lean (no socket/platform need arises. The base crate should compile lean (no socket/platform
@@ -260,9 +267,13 @@ non-backend module changes.
- alknet ADR-093 / alkcall ADR-035 — channels pure channel - alknet ADR-093 / alkcall ADR-035 — channels pure channel
multiplexing (8-byte header, no `stream_type`); the tunnel payload multiplexing (8-byte header, no `stream_type`); the tunnel payload
is raw bytes inside the `BiStream` is raw bytes inside the `BiStream`
- alknet ADR-078 — two-pump shutdown-on-completion (the tunnel - alknet ADR-078 / alkcall ADR-050 — two-pump shutdown-on-completion
handler pattern; a helper extraction was deferred until a second (the tunnel handler pattern); the helper is pinned upstream as
two-pump consumer exists — this crate is that second consumer) `alkcall::channels::pump_bidi` — use it, do not hand-roll
- alkcall ADR-049 (amendment 2) — the establishment phase; the
establisher returns the dialed handle via `Establishment::new`
(typed-opaque `ChannelPlan`), replacing the POC's side-channel
handoff
- alknet ADR-074 / alkcall ADR-038 — `ChannelConnection` as a - alknet ADR-074 / alkcall ADR-038 — `ChannelConnection` as a
`BidiStreamSource`; every handler (TTY, tunnel, call) receives a `BidiStreamSource`; every handler (TTY, tunnel, call) receives a
`Connection` `Connection`
Generated
+2 -2
View File
@@ -27,9 +27,9 @@ dependencies = [
[[package]] [[package]]
name = "alkcall" name = "alkcall"
version = "0.5.0" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bbaeb718c370b74f9136d1d59b4608249bd7d1dd2332c0259f98351d709737f" checksum = "a44500900b82904d2a870e444051fc041a042e42ff7190803bbc5b3973f4feeb"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"bytes", "bytes",
+1 -1
View File
@@ -18,7 +18,7 @@ name = "alktunnels"
default = [] default = []
[dependencies] [dependencies]
alkcall = "0.5.0" alkcall = "0.6.0"
tokio = { version = "1", default-features = false, features = ["rt", "sync", "io-util", "macros", "time"] } tokio = { version = "1", default-features = false, features = ["rt", "sync", "io-util", "macros", "time"] }
bytes = "1" bytes = "1"
futures = "0.3" futures = "0.3"
+25 -4
View File
@@ -550,6 +550,19 @@ POC: the `OpenHandler` JoinHandle semantics (see `poc-summary.md` §
Issues Surfaced #1) are where such a helper would pin the teardown Issues Surfaced #1) are where such a helper would pin the teardown
contract. contract.
**RESOLVED 2026-09-07 — the helper landed upstream in alkcall 0.6.0**
(review 007 R-03, ADR-050): `alkcall::channels::pump_bidi(channel,
peer_read, peer_write) -> (u64, u64)`. Shape as this OQ sketched it —
two pumps, shutdown-on-completion wired in, copy counts returned for
observability, errors EOF-shaped (no `Err` state — a mid-stream error
is an abrupt close, so an `io::Result` would be dead code). The POC
is cited in the ADR as convergence input alongside alktty's channels
session and the assembly-layer copies. alktunnels consumes it; the
POC's `pump_halves` is now prior art only. The JoinHandle lifetime
contract (R-02) is documented on the `OpenHandler` type: await the
helper inline inside the handler's task — early return is
teardown-at-birth.
### OQ-TN-07: ALPN strategy ### OQ-TN-07: ALPN strategy
This crate owns the `alk/tunnel`-family ALPN(s). alkcall ADR-004: one This crate owns the `alk/tunnel`-family ALPN(s). alkcall ADR-004: one
@@ -681,9 +694,14 @@ channel stream.
the data stream. the data stream.
- Implementation note (ADR-049 amendment): the establisher takes - Implementation note (ADR-049 amendment): the establisher takes
`(input, auth)` only — the channel's yield-once `BiStream` belongs `(input, auth)` only — the channel's yield-once `BiStream` belongs
exclusively to the pump handler. The tunnel establisher hands the exclusively to the pump handler. **Amendment 2 (alkcall 0.6.0,
dialed connection to the pump handler through its own path (e.g. a review 007 R-01) filled the reserved `Establishment` field:**
oneshot/`Arc<Mutex<Option<_>>>`), not via the open-op input. `Establishment::new(plan)` carries the dialed handle to the pump
handler via its `plan` parameter (`ChannelPlan` — typed-opaque
`Arc<dyn Any + Send + Sync>`; downcast happens in this crate). The
POC's side-channel `HandleHandoff` is dead — no handoff map, no
same-resource race; the establisher just returns
`Ok(Establishment::new(dialed))`.
- What remains for this crate's Phase 1 ADR (narrowed from the - What remains for this crate's Phase 1 ADR (narrowed from the
original frame-vocabulary question): original frame-vocabulary question):
- Half-open semantics: one direction EOFs, the other keeps pumping - Half-open semantics: one direction EOFs, the other keeps pumping
@@ -827,7 +845,10 @@ Candidate reading for the research specialist (to be expanded):
gives both shapes (producer `pump_halves`, consumer gives both shapes (producer `pump_halves`, consumer
`take_halves` + copy): same shape modulo channel side; the `take_halves` + copy): same shape modulo channel side; the
alknet ADR-078 convergence test is satisfied, extraction now alknet ADR-078 convergence test is satisfied, extraction now
decidable in Phase 1 decidable in Phase 1. **RESOLVED 2026-09-07:** the helper
landed upstream in alkcall 0.6.0 as `channels::pump_bidi`
(ADR-050, review 007 R-03) — this crate consumes it; see
OQ-TN-06
- [x] OQ-TN-05 executable input (backend trait vs no-trait) — POC - [x] OQ-TN-05 executable input (backend trait vs no-trait) — POC
confirms stream substrates need no trait: `pump_halves` is confirms stream substrates need no trait: `pump_halves` is
generic over boxed halves (TCP `into_split`, UDP `UdpHalf` generic over boxed halves (TCP `into_split`, UDP `UdpHalf`
+36 -4
View File
@@ -1,6 +1,6 @@
--- ---
status: complete status: complete
last_updated: 2026-09-06 last_updated: 2026-09-07
--- ---
# alktunnels: UDP Tunnel POC Research Summary # alktunnels: UDP Tunnel POC Research Summary
@@ -10,8 +10,10 @@ end-to-end over alkcall 0.5.0 channels, including the ADR-049
establishment phase and the codec decision (raw pass-through for TCP, establishment phase and the codec decision (raw pass-through for TCP,
`[len: u16 BE]` for UDP). 17 tests pass (7 codec + 10 integration); `[len: u16 BE]` for UDP). 17 tests pass (7 codec + 10 integration);
clippy `-D warnings` clean; fmt clean. The remaining unknowns are clippy `-D warnings` clean; fmt clean. The remaining unknowns are
spec-scope (Phase 1 ADRs), not feasibility. spec-scope (Phase 1 ADRs), not feasibility. Both upstream findings
**Date:** 2026-09-06 below landed in alkcall 0.6.0 (review 007) — see §Resolutions
2026-09-07.
**Date:** 2026-09-06 (resolutions added 2026-09-07)
**Scope:** Validates the OQ-TN-10 #1 POC (UDP tunnel) — plus the **Scope:** Validates the OQ-TN-10 #1 POC (UDP tunnel) — plus the
consumer-side of the establisher hand-off (ADR-049), the two-pump consumer-side of the establisher hand-off (ADR-049), the two-pump
pump-handler contract's `JoinHandle` semantics (a real finding — see pump-handler contract's `JoinHandle` semantics (a real finding — see
@@ -247,6 +249,34 @@ substrate access.
shape modulo channel side. The convergence test alknet ADR-078 shape modulo channel side. The convergence test alknet ADR-078
asked for is satisfied. asked for is satisfied.
## Resolutions 2026-09-07 (alkcall 0.6.0, review 007)
Both upstream findings above landed, with deviations recorded in the
review and ADRs:
1. **JoinHandle semantics (→ R-02)** — documented on the `OpenHandler`
type and both `register_openable*` methods: the returned
`JoinHandle` must track the data-plane lifetime; the wrapper awaits
it and its completion triggers channel teardown. Plus the POC's
second ask: a yield-once acceptance flag in
`ChannelBidiStreamSource` and a `debug!` birth-teardown hint in the
teardown task, so the hang-this-POC-found shape is diagnosable at
runtime, not just in docs.
2. **`Establishment` carries the plan (→ R-01)** — filled as
`Establishment { plan: Option<ChannelPlan> }` with
`Establishment::new(plan)`; **typed-opaque** (`ChannelPlan =
Arc<dyn Any + Send + Sync>`), not the `Option<Value>` sketch here —
the payloads are live handles (dialed sockets, TTY handles) with no
JSON representation. The `OpenHandler` gains a `plan` parameter and
the wrapper threads it. The POC's `HandleHandoff` side-channel and
its same-resource race are dead: the establisher returns the dialed
handle directly (`Ok(Establishment::new(dialed))`).
3. **Two-pump helper (→ R-03, bonus)**`alkcall::channels::pump_bidi`
pinned upstream (ADR-050), with `(u64, u64)` copy counts (no
`io::Result` — errors are EOF-shaped per the ADR-078 contract). The
POC's `pump_halves` shape converged and became the helper; Phase 1
consumes it instead of hand-rolling.
## What the POC does NOT validate ## What the POC does NOT validate
1. **Real transports**`tokio::io::duplex` stands in for 1. **Real transports**`tokio::io::duplex` stands in for
@@ -303,7 +333,9 @@ test udp_and_tcp_concurrent ... ok
`ChannelCore::register_openable_with_establisher`, `ChannelCore::register_openable_with_establisher`,
`OpenEstablisher`/`Establishment`/`EstablishmentError`, `OpenEstablisher`/`Establishment`/`EstablishmentError`,
`ChannelOpenError` (typed client error), `run_open_wrapper` `ChannelOpenError` (typed client error), `run_open_wrapper`
(`src/channels/operations.rs`). (`src/channels/operations.rs`). **0.6.0 supersedes parts:** ADR-049
amendment 2 (`Establishment.plan`), ADR-050 (`pump_bidi`), review
007 (filed from this POC, all units landed).
- alknet ADR-078 — the two-pump shutdown-on-completion contract; - alknet ADR-078 — the two-pump shutdown-on-completion contract;
`pump_halves` is its direct implementation. `pump_halves` is its direct implementation.
- alktunnels `docs/research/phase-0-findings.md` — the OQ ledger this - alktunnels `docs/research/phase-0-findings.md` — the OQ ledger this