From b3b00f37bd70ace56e19f72a9c192a90ded19035 Mon Sep 17 00:00:00 2001 From: "glm-5.3-flash" Date: Mon, 7 Sep 2026 09:27:08 +0000 Subject: [PATCH] chore: consume alkcall 0.6.0; OQ-TN-06 resolved by ADR-050 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- AGENTS.md | 41 ++++++++++++++++++++----------- Cargo.lock | 4 +-- Cargo.toml | 2 +- docs/research/phase-0-findings.md | 29 +++++++++++++++++++--- docs/research/poc-summary.md | 40 +++++++++++++++++++++++++++--- 5 files changed, 90 insertions(+), 26 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 8fa7340..1382355 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -65,8 +65,8 @@ just spawned implementation agents. expected on public API. Inline `//` comments only when the user asks 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 - pump completion — `try_join!` alone deadlocks; see alkcall's - channels-adapter spec / alknet ADR-078"). + pump completion — `try_join!` alone deadlocks; see alkcall ADR-050's + `pump_bidi` / alknet ADR-078"). 2. **Error handling** — `thiserror` for library error types (`TunnelError`; `HandlerError`/`StreamError` come from @@ -131,10 +131,14 @@ just spawned implementation agents. canonical two-pump handler (one pump per direction). Each pump MUST shut down the opposite sink when it completes; `tokio::try_join!` alone deadlocks. This was POC-validated in the alknet-channels POC - (Target 3) and pinned as alknet ADR-078. The channels 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. + (Target 3), pinned as alknet ADR-078, and the helper is pinned + upstream as alkcall `channels::pump_bidi` (ADR-050, review 007 + R-03) — use it; do not hand-roll the two-pump shape. The channels + 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 (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 v0.5.x — breaking changes are expected at this major-zero stage; this is an early consumer, so we find and fix issues upstream - rather than working around them. Pin `alkcall = "0.5.0"` and bump - deliberately. The 0.5.0 establishment phase (ADR-049) is - load-bearing for this crate: tunnel opens use + rather than working around them. Pin `alkcall = "0.6.0"` and bump + deliberately. The 0.6.0 establishment surface (ADR-049 + amendment + 2) is load-bearing for this crate: tunnel opens use `register_openable_with_establisher` so a refused target dial is - a typed `channel:open_failed` call error, never a phantom - channel. + a typed `channel:open_failed` call error, never a phantom 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 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; `OwnershipStore::record` is the 3-arg shape). Tunnels reach local 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 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 multiplexing (8-byte header, no `stream_type`); the tunnel payload is raw bytes inside the `BiStream` - - alknet ADR-078 — two-pump shutdown-on-completion (the tunnel - handler pattern; a helper extraction was deferred until a second - two-pump consumer exists — this crate is that second consumer) + - alknet ADR-078 / alkcall ADR-050 — two-pump shutdown-on-completion + (the tunnel handler pattern); the helper is pinned upstream as + `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 `BidiStreamSource`; every handler (TTY, tunnel, call) receives a `Connection` diff --git a/Cargo.lock b/Cargo.lock index 87ef21c..0a2b1d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,9 +27,9 @@ dependencies = [ [[package]] name = "alkcall" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bbaeb718c370b74f9136d1d59b4608249bd7d1dd2332c0259f98351d709737f" +checksum = "a44500900b82904d2a870e444051fc041a042e42ff7190803bbc5b3973f4feeb" dependencies = [ "async-trait", "bytes", diff --git a/Cargo.toml b/Cargo.toml index cbc89ce..4ba11f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ name = "alktunnels" default = [] [dependencies] -alkcall = "0.5.0" +alkcall = "0.6.0" tokio = { version = "1", default-features = false, features = ["rt", "sync", "io-util", "macros", "time"] } bytes = "1" futures = "0.3" diff --git a/docs/research/phase-0-findings.md b/docs/research/phase-0-findings.md index 73155c3..4666a4b 100644 --- a/docs/research/phase-0-findings.md +++ b/docs/research/phase-0-findings.md @@ -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 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 This crate owns the `alk/tunnel`-family ALPN(s). alkcall ADR-004: one @@ -681,9 +694,14 @@ channel stream. 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>>`), not via the open-op input. + exclusively to the pump handler. **Amendment 2 (alkcall 0.6.0, + review 007 R-01) filled the reserved `Establishment` field:** + `Establishment::new(plan)` carries the dialed handle to the pump + handler via its `plan` parameter (`ChannelPlan` — typed-opaque + `Arc`; 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 original frame-vocabulary question): - 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 `take_halves` + copy): same shape modulo channel side; the 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 confirms stream substrates need no trait: `pump_halves` is generic over boxed halves (TCP `into_split`, UDP `UdpHalf` diff --git a/docs/research/poc-summary.md b/docs/research/poc-summary.md index e0b5a85..9e4365a 100644 --- a/docs/research/poc-summary.md +++ b/docs/research/poc-summary.md @@ -1,6 +1,6 @@ --- status: complete -last_updated: 2026-09-06 +last_updated: 2026-09-07 --- # 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, `[len: u16 BE]` for UDP). 17 tests pass (7 codec + 10 integration); clippy `-D warnings` clean; fmt clean. The remaining unknowns are -spec-scope (Phase 1 ADRs), not feasibility. -**Date:** 2026-09-06 +spec-scope (Phase 1 ADRs), not feasibility. Both upstream findings +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 consumer-side of the establisher hand-off (ADR-049), the two-pump 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 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 }` with + `Establishment::new(plan)`; **typed-opaque** (`ChannelPlan = + Arc`), not the `Option` 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 1. **Real transports** — `tokio::io::duplex` stands in for @@ -303,7 +333,9 @@ test udp_and_tcp_concurrent ... ok `ChannelCore::register_openable_with_establisher`, `OpenEstablisher`/`Establishment`/`EstablishmentError`, `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; `pump_halves` is its direct implementation. - alktunnels `docs/research/phase-0-findings.md` — the OQ ledger this