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).
4.1 KiB
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_endpointand the TCP+TLS loop live determines who depends oniroh/tokio-rustlsfor 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-corebehind atcpfeature (owned by the endpoint). The endpoint takes aTcpListener+TlsAcceptorviawith_tcp_tls(listener, acceptor)and runs the accept loop insiderun()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 thetcpfeature and callswith_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. Aalknet-transportcrate 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.dispatchstays 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 callsendpoint.dispatch(), which is core's API. Adding it toalknet-tlswould 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)