docs(arch): break the AlknetClient circular hedge — TlsClientConfig not blocked on dial (ADR-087, resolves OQ-64)
OQ-64 and OQ-55 were linked in a circular dependency: the client-side TLS config was deferred behind the dial seam (OQ-55), but the dial needs the TLS config. No second transport can dial until it has a TLS config; the TLS config was deferred until a second transport dials. Schrödinger's code — required and not required until observed. ADR-087 breaks the circle by separating two concerns that were conflated as 'the same seam': 1. TlsClientConfig — rustls::ClientConfig + ADR-034 verifier selection + ADR-084 crypto provider. Transport-agnostic. All decisions made. Buildable today. A PREREQUISITE for any dial, not a consequence of it. 2. The dial (AlknetClient::dial()) — transport-specific connection establishment. Extracting a transport-polymorphic dial from one shape (QUIC) would bake QUIC in. Legitimate deferral (OQ-55, unchanged). The hub makes this non-optional: a hub dials out to workers it supervises and to other hubs (hub-as-client). The first hub deployment (web + native) dials workers over QUIC with the worker's fingerprint pinned. There is no 'later' for the TLS config — it is on the critical path for the first hub and for alknet-worker. Changes: - ADR-087: TlsClientConfig in alknet-tls, not blocked on OQ-55 - OQ-64: resolved (yes, alknet-tls provides TlsClientConfig) - OQ-55: amended — only the dial seam is deferred; TLS client config is explicitly NOT part of the deferral - TLS README: 'Server-only (for now)' section replaced with TlsClientConfig section; crate is no longer server-only - Hub README: dial/supervision section references TlsClientConfig for outbound connections
This commit is contained in:
1 parent
7d9b1ebad9
commit
77321a7e84
8 files changed
+502
-140
No files matched your search
@@ -282,8 +282,12 @@ all.
|
||||
#### Dial (outbound workers) — transport-agnostic
|
||||
|
||||
The hub dials outbound workers via `ChannelClient`, not `CallClient`.
|
||||
The dial path mirrors the `from_connection` / `connect_quic` split
|
||||
(ADR-080):
|
||||
The hub is a client when it dials out — a hub (B) that connects to
|
||||
another hub (A) is a client from A's perspective. The dial needs a
|
||||
client-side TLS config (`TlsClientConfig`, ADR-087) for the outbound
|
||||
connection's `rustls::ClientConfig` (verifier selection per ADR-034:
|
||||
fingerprint pin for the worker's known key). The dial path mirrors the
|
||||
`from_connection` / `connect_quic` split (ADR-080):
|
||||
|
||||
```rust
|
||||
impl Hub {
|
||||
@@ -299,8 +303,9 @@ impl Hub {
|
||||
) -> Result<(PeerId, ChannelClient), HubError>;
|
||||
|
||||
/// QUIC convenience: dial a worker over QUIC, then
|
||||
/// `dial_worker_connection`. Two-way door — additive over
|
||||
/// `dial_worker_connection`.
|
||||
/// `dial_worker_connection`. Builds a `TlsClientConfig` (ADR-087)
|
||||
/// with the worker's fingerprint pinned (ADR-034), dials QUIC,
|
||||
/// wraps as a channels `Connection`, calls `dial_worker_connection`.
|
||||
pub async fn connect_quic_worker(
|
||||
&self,
|
||||
addr: SocketAddr,
|
||||
@@ -315,11 +320,12 @@ taking over the `Connection`, it runs `from_call` on channel 0 to
|
||||
discover the worker's operations, registers the discovered bundles in
|
||||
the connection's Layer 2 overlay, and attaches the peer to the
|
||||
aggregated env. `connect_quic_worker` is the "I just want QUIC"
|
||||
convenience — it calls `ChannelClient::connect_quic`, then
|
||||
`dial_worker_connection`. A future `connect_tcp_tls_worker` dials
|
||||
TCP+TLS and calls `dial_worker_connection` the same way. The
|
||||
one-way-door surface is `dial_worker_connection`; the dial helpers
|
||||
are two-way-door conveniences.
|
||||
convenience — it builds a `TlsClientConfig` (ADR-087) with the
|
||||
worker's fingerprint pinned, calls `ChannelClient::connect_quic`, then
|
||||
`dial_worker_connection`. A future `connect_tcp_tls_worker` builds a
|
||||
`TlsClientConfig` and dials TCP+TLS the same way. The one-way-door
|
||||
surface is `dial_worker_connection`; the dial helpers are two-way-door
|
||||
conveniences.
|
||||
|
||||
#### Accept (inbound workers and browsers) — transport-agnostic
|
||||
|
||||
@@ -780,6 +786,7 @@ into `CallAdapter::with_aggregated_env`.
|
||||
| Channel 0 pre-negotiated | [ADR-072](../../decisions/072-channel-0-pre-negotiated-call.md) | Channel 0 = `alknet/call`; the `CallAdapter` runs here |
|
||||
| Channel lifecycle operations | [ADR-073](../../decisions/073-channel-lifecycle-operations.md) | `channel/open`/`close`/`control`/`resources/subscribe` — what the hub translates |
|
||||
| Endpoint types and entry points | [ADR-086](../../decisions/086-endpoint-types-and-entry-points.md) | Three endpoint types (web/native/iroh); entry-point vs. endpoint ALPN distinction; split ALPN lists per endpoint type |
|
||||
| `TlsClientConfig` for outbound dials | [ADR-087](../../decisions/087-tlsclientconfig-not-blocked-on-dial.md) | `alknet-tls` provides client-side TLS config; hub-as-client is a first-class use case; not blocked on the dial-seam extraction (OQ-55) |
|
||||
|
||||
## Open Questions
|
||||
|
||||
@@ -843,6 +850,7 @@ See [open-questions.md](../../open-questions.md) for full details.
|
||||
- ADR-082: alknet-tls extraction (`TlsServerConfig` — shared across quinn + TCP+TLS)
|
||||
- ADR-083: Endpoint as multi-transport accept-loop runner (`with_tcp_tls` — TCP+TLS owned by the endpoint; the hub composes transports and handlers)
|
||||
- ADR-086: Endpoint types and entry points (web/native/iroh; entry-point vs. endpoint; split ALPN lists per endpoint type)
|
||||
- ADR-087: `TlsClientConfig` not blocked on dial seam (client-side TLS config; hub-as-client requirement)
|
||||
- alkapi [hub.md](/workspace/@alkdev/alkapi/docs/architecture/hub.md) —
|
||||
the first hub consumer, the concrete use case that informed this
|
||||
crate
|
||||
|
||||
Reference in new issue
Block a user