Files
alknet/docs/architecture/questions/060-transport-construction-location.md
T
glm-5.2 2abe8f1872 docs(arch): TCP+TLS as first-class owned transport — resolves OQ-60, dissolves OQ-61
ADR-083 revised: TCP+TLS moves from an external sibling loop calling
public dispatch to a first-class owned transport via
with_tcp_tls(listener, acceptor), running inside run() alongside the
quinn and iroh accept loops. The endpoint owns all its accept loops;
shutdown() stops them all. The multi-owner shutdown problem (OQ-61)
does not arise — dissolved.

The reason TCP+TLS was structurally excluded (ADR-010 Am. 1: the
endpoint built transports internally, TCP+TLS couldn't fit) is gone
after ADR-083 — the endpoint no longer builds transports; it runs
accept loops on whatever it's given. TCP+TLS is a listener transport,
same shape as quinn and iroh. ADR-010 Amendment 2 supersedes Am. 1's
struct-level exclusion.

dispatch stays public — but for genuinely external shapes (SSH channels,
future WebTransport streams), which are connection-internal multiplexing,
not listener transports. The listener-vs-multiplexing distinction is now
explicit.

OQ-60 resolved: the TCP+TLS loop lives in alknet-core behind a tcp
feature (owned by the endpoint); builder functions are inlined by the
assembly layer. A alknet-transport crate was rejected — it would contain
only trivial builders; the real component (the loop) is in core. Hub-
specific composition lives in the hub crate; transport runtimes that any
node might need live in core.

Updated: ADR-010 (Amendment 2), ADR-082 (TCP+TLS loop location), ADR-083
(revised), core/endpoint.md (struct + dispatch + shutdown), hub/README.md
(transport table + assembly example + stale sibling references),
tls/README.md (endpoint section + TCP+TLS loop location + references),
open-questions.md (OQ-60 resolved, OQ-61 dissolved).

Review: zero critical issues, five warnings fixed (stale hub README
prose, stale core endpoint.md struct/dispatch listings, stale ADR-082
TCP+TLS loop location, stale TLS README reference entry, hub front-matter
date).
2026-07-14 08:58:50 +00:00

70 lines
4.1 KiB
Markdown

# OQ-60: Where Does Transport Construction Live?
- **Origin**: `docs/architecture/decisions/083-endpoint-as-accept-loop-runner.md`
(the endpoint refactor commits to the boundary — construction is not
in the endpoint — but not the location of transport construction).
- **Status**: resolved
- **Door type**: one-way (where `build_iroh_endpoint` and the TCP+TLS
loop live determines who depends on `iroh` / `tokio-rustls` for
transport construction; the dep-graph shape is structural)
- **Priority**: high (the hub is the first multi-transport consumer;
its assembly code sets the pattern)
- **Resolution**: Split answer (resolved by ADR-083 revision, 2026-07-14):
**TCP+TLS accept loop → `alknet-core` behind a `tcp` feature (owned
by the endpoint).** The endpoint takes a `TcpListener` +
`TlsAcceptor` via `with_tcp_tls(listener, acceptor)` and runs the
accept loop inside `run()` alongside the quinn and iroh loops. TCP+TLS
is a listener transport — same shape as quinn and iroh (accept →
extract ALPN + fingerprint → `Connection::from_bidi` → `dispatch`).
Making it owned gives the endpoint a single uniform ownership model:
it owns all its accept loops, `shutdown()` stops them all. The
multi-owner shutdown problem (OQ-61) does not arise. Any node that
wants TCP+TLS enables the `tcp` feature and calls `with_tcp_tls` — no
hub dependency. This reverses ADR-010's "TCP is not an endpoint struct
concern": the reason TCP was excluded (the endpoint built transports
internally, TCP+TLS couldn't fit) is gone; the endpoint is now a
multi-transport accept-loop runner and TCP+TLS fits the same shape.
**Builder functions (`build_iroh_endpoint`, `build_quinn_endpoint`,
`build_tcp_tls`) → inlined by the assembly layer.** These are trivial
API calls (2-15 lines each, pure configuration, no shared logic). The
assembly layer (the deployment binary — today primarily the hub
crate's composition code) inlines them. No helper crate or module —
20 lines total across all three. A `alknet-transport` crate was
considered and rejected: it would contain only trivial builders (the
real component, the TCP+TLS loop, is in core). Hub-specific transport
helpers, if they accumulate, live in the hub crate, not a generic
transport crate.
**`dispatch` stays public** — but for genuinely external shapes (SSH
channels, future WebTransport streams), not for TCP+TLS. The
distinction: listener transports (quinn, iroh, TCP+TLS) produce
connections from an accept loop the endpoint owns; multiplexing
transports (SSH, WT) produce connections from within an existing
connection, and the endpoint can't own their accept loop.
**Why not the hub crate for the TCP+TLS loop:** "the assembly layer"
is, in practice, usually the hub. But a hub-worker serving TCP+TLS
shouldn't depend on the hub crate for a transport loop. The loop
belongs in core (behind a feature), where any node can use it. The hub
crate owns hub-specific *composition* (wiring adapters, relay, peer
lifecycle), not transport runtimes.
**Why not `alknet-tls`:** `alknet-tls`'s stated job is TLS setup —
`rustls::ServerConfig`, cert resolvers, ACME (ADR-082). The TCP+TLS
accept loop is transport runtime, not TLS setup. It calls
`endpoint.dispatch()`, which is core's API. Adding it to `alknet-tls`
would make a cert-provider crate depend on the endpoint's dispatch API
and own a transport runtime — a category error.
**Why not `alknet-transport` (new crate):** The real component (the
TCP+TLS loop) is in core. What's left for a transport crate is trivial
builder functions. A crate for 20 lines of API calls doesn't earn its
existence. If future transport runtimes accumulate that don't fit
core, a transport crate can be created then — but not speculatively.
- **Cross-references**: ADR-083 (endpoint refactor — the revision that
resolved this), ADR-082 (`alknet-tls` — the cert provider boundary),
ADR-010 (original endpoint design — "TCP is not an endpoint struct
concern" is revised), OQ-61 (dissolved — the multi-owner shutdown
problem does not arise with TCP+TLS owned by the endpoint)