Files
alktunnels/docs/architecture
glm-5.3-flash 508fc6fc28 docs: complete oq-promotion-sync — AGENTS.md current with Phase 1, add TN-12 tracker
- AGENTS.md architecture bullet: spec exists (present tense), OQ tracker
  authoritative; convention 16 de-hedged (shape pinned by ADR-004/005);
  alkcall version drift fixed (v0.4.x/v0.5.x -> v0.7.x per Cargo.toml);
  Phase 1-work bullet -> Phase 1 complete, Phase 2 in tasks/
- phase-0-findings.md: promotion note atop the Open Questions section
  pointing at docs/architecture/open-questions.md; convergence
  checklist's final item checked
- tasks: add architecture/oq-tn-12-tracker (external-trigger tracker for
  OQ-TN-12 deferred(scope), per sdd_process.md deferred-OQ two-halves
  rule); OQ-TN-12 Blocked-on text now references the tracker id
- tasks: oq-promotion-sync completed (scope grew: 3 folded stale
  AGENTS.md refs found during review + the TN-12 tracker)

Verified: taskgraph validate (13 tasks), grep sweep clean for stale
'not exist yet'/version-drift language, cargo test + cargo fmt --check
2026-09-08 06:18:55 +00:00
..

status, last_updated
status last_updated
draft 2026-09-07

alktunnels — Architecture

Arbitrary bidirectional tunnels over alkcall channels: the alk/tunnel-family producer/consumer protocol crate. This directory holds the architecture spec docs and the ADRs. It is the sibling of alktty's architecture (/workspace/@alkdev/alktty/docs/architecture/) — same substrate (alkcall channels), same shape (a producer open-handler + a typed consumer session), different service (tunnels: raw byte/datagram transport, not terminal sessions).

Documents

Document Status Description
overview.md draft Crate purpose, the resource model in brief, dependencies, ALPN, feature gates, module map
wire.md draft The wire format: open-op params JSON (ADR-001), the data-plane codec (raw pass-through for stream substrates; mandatory [len: u16 BE] framing for UDP — ADR-003), sentinels, half-close semantics
producer.md draft The producer half: the channels/tunnel/sub open op, the establisher (dial + listen variants), the pump handler, registration, scope gating
consumer.md draft The consumer half: TunnelSession (stream + datagram variants), the reverse-flow initiator, teardown ownership (ADR-005)
bast.md draft The BAST (Binary Abstract Syntax Tree) document for the data-plane's binary framing (the UDP [len: u16 BE] codec — ADR-003); the stream pass-through has no binary framing to describe
open-questions.md draft Centralized OQ tracker (OQ-TN-01..14; the Phase 0 ledger promoted)

Applicable ADRs

alktunnels-native ADRs (001..005). Upstream ADRs (alkcall/alknet) are referenced by their own numbers and are NOT ported — the alkcall originals at /workspace/@alkdev/alkcall/docs/architecture/decisions/ remain authoritative for the shared surfaces (establishment, channels wire format, pump_bidi, identity seam).

ADR Title Status
001 Open-Op Params Layout: Resource + Substrate Accepted
002 Single alk/tunnel ALPN (Option A) Accepted
003 Data-Plane Codec: Raw Pass-Through (Stream) / Mandatory Length Framing (UDP) Accepted
004 No TunnelBackend Trait — Halves Functions at the Assembly Layer Accepted
005 The Consumer Session Type Owns Teardown Accepted
006 Access-Control Posture — the Open Gate Is the Security Boundary Accepted

Key Design Principles

  1. A tunnel is a resource, not an address. params identify a produced resource + substrate discriminator; the producer owns the backing (local port, docker container, in-process service, unix socket). No URL-style general addressing in the wire — rich addressing enters only through -D/dynamic composition, which speaks its protocol inside the tunnel payload. See ADR-001 and wire.md.

  2. Role follows the resource; connection direction is independent. Whoever can reach the target is the producer (registers openable channels); whoever wants the bytes is the consumer. -L and -R are the same open op with the entry point on different machines — no protocol-level direction (the hub-owns-the-connection model, OQ-TN-03). Validated by the reverse-flow POC: the worker serves on the connect side; the hub initiates per accept. See producer.md and consumer.md.

  3. Raw pass-through for stream substrates; mandatory length framing for UDP. A tunnel has one data stream per direction — no sub-demux key, no tunnel-level header on stream substrates (0 B tunnel overhead; the channels 8-byte header is the only cost). UDP rides [len: u16 BE] framing — mandatory for correctness (F-2; the rationale and the executable pin live in ADR-003). See ADR-003 and wire.md.

  4. The two-pump shape is alkcall::channels::pump_bidi — never hand-rolled. The producer's pump handler and the consumer-side pump both consume the upstream helper (ADR-050); each pump shuts down the opposite sink on completion (half-close semantics fall out). The OpenHandler's returned JoinHandle tracks the data-plane lifetime (early return = teardown-at-birth, R-02). See producer.md.

  5. No backend trait. Stream substrates need "produce boxed halves for a resource" — a function, not a trait (the UDP POC's OQ-TN-05 finding). The inversion point is the assembly layer wiring substrate halves into the establisher/pump; substrate types stay in feature-gated backend modules. The listen variant (producer accepts instead of dialing) is an establisher shape, not a trait. See ADR-004.

  6. The consumer session type owns teardown. One session = one channel = one tunnel (the channel ID is the flow key). The adopted side has no wrapper awaiting its pump (reverse POC W3) — the session must hold the pump handle and reap the channel on completion/close. See ADR-005 and consumer.md.

  7. Backpressure and limits are inherited, not redefined. Bounded per-channel buffers, the 256-channel cap, monotonic IDs, and the zero-length-sentinel EOF convention are alkcall channels invariants; the tunnel crate consumes them and does not build a second demux/mux (AGENTS.md convention 10).

  8. Security posture: the open gate is the boundary. Scope-gated opens (TUNNEL_OPEN_SCOPE = "tunnel:open", stable once published — ADR-006), alkcall's op-level ACL via register_openable; caller identity resolves in the 0.7.0 precedence order (token > ServingConfig.identity > transport); the establisher/pump handler see the per-call opener identity. No target allowlists, no tunnel-specific policy machinery in v1. See ADR-006 and producer.md.

  9. Wasm-clean default crate. The default crate (protocol only) compiles to wasm32-unknown-unknown; socket/platform I/O lives in feature-gated backend modules (AGENTS.md conventions 4/14), same as alktty.

Relevant Open Questions

All open questions are tracked in open-questions.md. The Phase 0 OQ ledger (OQ-TN-01..10, docs/research/phase-0-findings.md) is promoted there; the questions affecting the spec set are summarized in each doc's Open Questions section.

References

  • Phase 0 research: docs/research/phase-0-findings.md (OQ ledger), docs/research/poc-summary.md (UDP POC), docs/research/reverse-poc-summary.md (reverse-flow POC), docs/research/ssh-socks5-survey.md (SSH/SOCKS5/udpgw prior art)
  • Upstream: alkcall ADR-047 (openable ALPNs are operations), ADR-049 (establishment phase + amendment 2 plan payload), ADR-050 (pump_bidi), ADR-022 §2 (both-sides serving), ADR-047 §5 (connection-owner allocation), ledger CF-005/CF-006 (identity seam); alknet ADR-078 (two-pump contract), ADR-071/093 (channels wire format); alkcall ADR-042 (hub relay)
  • Upstream reviews/ledger (the spec cites these IDs): /workspace/@alkdev/alkcall/docs/reviews/007-establishment-follow-ups-review.md (R-01 = the Establishment plan payload, R-02 = the OpenHandler lifetime contract, R-03 = pump_bidi) and /workspace/@alkdev/alkcall/docs/reviews/consumer-findings-ledger.md (CF-005/CF-006 = the identity seam, resolved in 0.7.0)
  • Sibling precedent: alktty (/workspace/@alkdev/alktty) — the producer/consumer-on-channels shape, wasm-clean default, feature-gated local backend, BAST convention
  • POC code: /workspace/alktunnels-udp-poc (forward), /workspace/alktunnels-reverse-poc (reverse)