Files
alknet/docs/architecture/questions/062-alpn-list-sharing-two-config-hub.md
T
glm-5.2 7610ec1f31 docs(arch): workspace scope correction (ADR-085) + tls spec review fixes
ADR-085 records the actual workspace scope: the mono-repo is the core
networking toolkit (substrate: core, tls, call, channels; deployment
shapes: hub, worker; foundational handlers: tty, http, ssh, tunnel,
socks5, fs, sftp; vault). Consumer repos (docker, agent) are separate
repos depending on the published core crates. The overview's crate
graph had been describing the wrong scope since ADR-003 — a flat
~12-crate workspace including DNS/messaging/NAPI while omitting
channels, hub, worker, and tls. This stale scope was a causal factor
in the 'assembly layer' hedging pattern: when the overview implies
everything lives in one repo but the architecture needs a hub/worker
composition layer not in the graph, the gap gets filled with
'assembly layer' as an escape hatch. The overview is rewritten to
match the real boundary.

TLS spec review fixes (from architecture review):
- C3: hub/worker/hub-worker terminology pointers (tls README + endpoint.md)
- W1: server-only statement + OQ-64 (client-side TLS helper, deferred)
- W2: ACME task lifecycle semantics (returns immediately, no first-cert await)
- W3: remove stale EndpointError::TlsConfig variant
- W4: update stale ALPN section for two-config hub
- W5: add alknet-tls to hub dep graph (assembly-layer dep)
- W6: trim inline rationale -> point to ADR-084
- W7: ADR-084 status dependency note

New open questions:
- OQ-62: ALPN list sharing for two-config hub (open, high)
- OQ-63: TlsError shape (open, high)
- OQ-64: client-side TLS helper (deferred, blocked on OQ-55)
2026-07-14 12:46:16 +00:00

3.0 KiB

OQ-62: Does a Hub Pass the Same ALPN List to Both TlsServerConfigs?

  • Origin: docs/architecture/crates/tls/README.md (the "What AlknetEndpoint does after the refactor" section describes a hub holding two TlsServerConfigs — raw key + X.509/ACME — but does not state whether each receives the same ALPN list or different lists); docs/architecture/crates/core/endpoint.md (the ALPN section previously stated "both connection sources advertise the same set of ALPNs," which is stale under the two-config hub model).

  • Status: open

  • Door type: one-way (the ALPN list each TlsServerConfig advertises is baked into the rustls::ServerConfig at construction; changing it after the hub is deployed is a config+restart, but the pattern — same-list vs split-list — sets the assembly-layer wiring shape that downstream consumers copy)

  • Priority: high (the hub is the first two-config consumer; its wiring sets the pattern, and an implementer cannot write the hub's assembly code without this decided)

  • Resolution: Not yet decided. The two plausible options:

    Option A — same list (union) to both configs. Both TlsServerConfigs receive registry.alpn_strings() verbatim. The raw-key QUIC listener advertises h2/http/1.1 (browsers can't connect to a raw-key listener anyway, so the advertisement is harmless dead negotiation). The X.509 TCP+TLS listener advertises alknet/call (a native client connecting over TCP+TLS with an X.509 client cert can use it). Simplest wiring; no split logic; every transport can serve every ALPN.

    Option B — split list, transport-appropriate. The raw-key config gets the native ALPNs (alknet/call, alknet/channels, alknet/tty); the X.509/ACME config gets the union including h2/http/1.1 (browser ALPNs that only make sense over TCP+TLS with a domain cert). The assembly layer filters registry.alpn_strings() by which transports can serve each ALPN. More logic; cleaner advertisement (no browser ALPNs on a raw-key listener).

    The question is whether the "harmless dead negotiation" in Option A is acceptable or whether the cleaner advertisement in Option B is worth the split logic. This needs a decision before the hub's assembly code is written — it is not guessable from the existing specs, and guessing produces a wiring shape that downstream consumers copy.

    Note: this is distinct from the iroh path. Iroh takes its ALPN list from iroh::Endpoint::builder().alpns() at construction, set by the assembly layer from registry.alpn_strings(). Iroh uses raw keys only, so it gets the native ALPN set regardless of which option is chosen for the quinn/TCP+TLS pair.

  • Cross-references: ADR-082 (TlsServerConfig::new takes alpns: &[Vec<u8>] — the caller decides), ADR-083 (the assembly layer builds transports; ALPN-list construction is its job), OQ-64 (client-side TLS helper — related but orthogonal; this OQ is server-side advertisement)