Files
alknet/docs/architecture/questions/055-alknetclient-establishment-extraction.md
T
glm-5.2 bf6ce957c0 docs(arch): tighten tls/endpoint/client specs — remove connect/connect_quic, move CallCredentials to core, shed alknet-call TLS deps
Review of the three new crates (alknet-tls, alknet-endpoint, alknet-client)
+ revised core found compile-blocking inconsistencies, stale claims, and
dep-graph contradictions. All resolved:

Critical:
- C1: CallClient::connect / ChannelClient::connect_quic REMOVED (not
  delegated) — keeping them as thin wrappers over AlknetClient::dial_quic
  would make protocol crates depend on alknet-client, contradicting the
  dep graph. Callers compose dial + take-over (2 lines).
- C2: alknet-client feature gates now pull alknet-core/quinn +
  alknet-core/iroh (for Connection::from_quinn_with_alpn / from_iroh).
- C3: rustls-native-certs + webpki-roots added to alknet-tls deps
  (always-present, not feature-gated — CA-verify path is transport-agnostic).

Warning:
- W1: CallCredentials/RemoteIdentity moved to alknet-core (from
  alknet-call) — the dial must not depend on the call protocol; not a
  two-way-door, it determines the dep graph.
- W2: webpki-roots fallback implemented in spec (ADR-088 §5 added) —
  the code claimed a fallback that never existed; now the store is never
  empty, NoRootAnchors unreachable, containerized deployments work.
- W3: EndpointError removed entirely (BindFailed + HandlerNotFound both
  vestigial after ADR-083); shutdown() is now infallible.
- W4: FingerprintPinVerifier moved to alknet-tls (from alknet-call) —
  alknet-call sheds quinn/rustls/rustls-pemfile/rustls-native-certs
  entirely; CallClient becomes a pure protocol crate.

Plus: ClientError removed (only produced by removed connect); S1
(CallCredentials → ClientVerifierContext mapping + auth_token stripped
at TLS boundary documented); amendment notes on ADR-017, ADR-069,
ADR-080, ADR-082, ADR-087, ADR-090; overview crate graph + README index
updated.

29 files, consistency-reviewed.
2026-07-16 11:33:18 +00:00

3.4 KiB

OQ-55: AlknetClient / Client Establishment Extraction

  • Origin: docs/research/alknet-channels/phase-0-findings.md OQ-CH-14 (the AlknetClient clarification); docs/research/alknet-channels/poc-summary.md §"Issues Surfaced" #1 (the BidiStreamSource finding that motivates separating the client-extraction question from the Connection extension question).
  • Status: resolved (ADR-089)
  • Door type: one-way (crate existence + dial seam — ADR-089)
  • Priority: medium
  • Resolution: AlknetClient is extracted as a new crate alknet-client — the client-side analogue of AlknetEndpoint (ADR-083). Three dial methods: dial_quic / dial_tcp_tls (both build a TlsClientConfig via ADR-087 and call their transport's connector) + dial_iroh (the key-not-config exception, shares the Ed25519SecretKey). The dial produces a Connection for the protocol take-overs (CallClient::spawn_dispatch, ChannelClient::from_connection) to consume — it does not run protocols.
  • Why the deferral collapsed: the blocking condition ("a second transport's real dial existing") is met within the native endpoint type (ADR-086): QUIC + TCP+TLS (both rustls-consuming via TlsClientConfig) + iroh (key-based) — three dial shapes, two sharing TlsClientConfig. ADR-087 broke the circular hedge (TlsClientConfig is a prerequisite, not a consequence of the dial). ADR-083 made the server-side shape a clean accept-loop runner, giving the client-side shape by symmetry. The dial seam is extractable from two different transport implementations, not guessable from one.
  • Scope of the resolution: the native transport-polymorphic dial. The web/browser client (WebSocket, HTTP — the browser bidirectional path per ADR-044/048) was never what this OQ was about — it is a different client surface (the JS SDK / wasm), not a Rust dial, and does not use AlknetClient. Non-Rust native clients (Node/Deno/Bun, Python, wasm) that negotiate TLS against an X.509 endpoint and implement the wire protocols directly are also out of scope — AlknetClient is the Rust native client, one of several possible native clients sharing the same wire protocols.
  • What does NOT block on this (unchanged): each crate building its own client standalone with a shared TlsClientConfig (ADR-087), and each transport-specific dial helper. CallClient's transport-agnostic take-over (spawn_dispatch) and ChannelClient's transport-agnostic take-over (from_connection, ADR-080) are decided; the connect / connect_quic convenience constructors are removed per ADR-089 §5 (not delegated — the dial is centralized in AlknetClient, and the protocol crates shed their TLS/transport deps).
  • Cross-references: ADR-089 (the resolution — AlknetClient native dial seam), ADR-083 (the server-side shape mirrored), ADR-086 (endpoint types — native has QUIC + TCP+TLS + iroh), ADR-087 (TlsClientConfig — the prerequisite the dial consumes), ADR-034 (verifier selection — centralized in TlsClientConfig::new), ADR-065 (server-side transport generalization — the client-side analogue this OQ's deferral avoided preempting, now completed), ADR-070 (the BidiStreamSource extension point — orthogonal to the client establishment question), OQ-CH-14 in docs/research/alknet-channels/phase-0-findings.md (the research-scope question this core-scope OQ carried forward).