Checklist (all six PASS): 1. API surface == ADR-004 — every accessor signature verified verbatim 2. TlsError == ADR-002 — six variants, #[non_exhaustive], typed sources, AcmeConfig holds exactly the two config-mismatch cases 3. Invariants: all five server invariants + client 0-RTT half + fail-closed structure, each with a passing behavioral test at unit and integration level 4. Deltas vs extraction: all ADR-pinned; two surfaced divergences recorded as ADR amendments — zero un-pinned divergences remain 5. Feature hygiene: default = [] lean, tokio subset (no full), doc comments on public API, no inline // comments, no panics 6. Docs sync: ADR-002 + ADR-003 amendment notes; overview/server/client Draft → Reviewed; README carries the API-freeze lifecycle note 5 findings, all low severity, all resolved forward (table in task Notes) Verification: cargo test (81), cargo test --all-features (92), clippy -D warnings, fmt --check, doc --no-deps, publish --dry-run — all green. API FROZEN for the alknet rewrite.
5.5 KiB
status, last_updated
| status | last_updated |
|---|---|
| accepted | 2026-09-10 |
ADR-003: The QUIC feature is noq, not quinn
Status
Accepted (2026-09-10)
Context
The extracted crate's quinn feature (for_quinn() accessors,
quinn-gated wrap) predates the noq split: iroh has extracted its
internal quinn fork into the standalone, published noq project
(noq / noq-proto / noq-udp; noq 1.2.0 on crates.io), and iroh
1.1.0 is built on noq 1.2.0, re-exporting noq::* as public API.
The alknet rewrite will standardize on noq for QUIC — both the bare
QUIC transport and iroh's internal one — eliminating the duplicate
QUIC implementations.
Phase 0 verified the seam is API-compatible with quinn 0.11
(docs/research/phase-0.md §Prior art: noq):
noq_proto::crypto::rustls::QuicServerConfig::try_from( rustls::ServerConfig)/QuicClientConfig::try_from( rustls::ClientConfig)— same constructor shape, sameNoInitialCipherSuitefailure type, different crate path.- noq 1.2 pins
rustls ^0.23.33; iroh 1.1 pinsrustls 0.23.33— the same 0.23 line this crate pins. One rustls tree across all paths. - noq's
rustls-aws-lc-rsfeature selects the aws-lc-rs provider; iroh'stls-aws-lc-rsdoes the same on the iroh side. The ADR-084 posture composes unchanged. - noq's MSRV is 1.88 — the ecosystem floor (adopted 2026-09-10), so no MSRV tension remains.
The quinn feature has no published consumer: alktls is
pre-consumer, and the alknet rewrite (its only planned consumer)
targets noq. Carrying both features would double the accessor surface
with nothing to transition.
Decision
The QUIC feature is noq. The quinn feature never existed in a
published alktls, so the rename is pre-consumer and free:
[features]
default = []
noq = ["dep:noq", "dep:noq-proto"]
tcp = ["dep:tokio-rustls"]
acme = ["dep:rustls-acme"]
[dependencies]
noq = { version = "1.2", optional = true, default-features = false, features = ["rustls"] }
noq-proto = { version = "1.2", optional = true, default-features = false }
default = [] — all transport features opt-in, matching the
inherited alknet spec's feature-gate shape and AGENTS.md convention 9
(the default crate compiles lean; a consumer that never runs QUIC
should not pull noq + noq-proto). Note the extracted code's
Cargo.toml carries default = ["quinn"] — a silent deviation from
the alknet spec that this port corrects rather than carries forward.
The noq dep is enabled with default-features = false, features = ["rustls"] so noq's provider-selection features do not
fight the crate's explicit provider posture; noq-proto rides along
for the NoqWrap error source.
TlsServerConfig::for_noq(&self) -> Result<noq::ServerConfig, TlsError>(feature-gated onnoq) —noq::ServerConfig::with_crypto(Arc::new( noq::crypto::rustls::QuicServerConfig::try_from(inner)?)).TlsClientConfig::for_noq(self) -> Result<noq::ClientConfig, TlsError>(feature-gated onnoq) — the client-side mirror.TlsError::NoqWrap(#[from] noq_proto::crypto::rustls::NoInitialCipherSuite)(ADR-002).- There is no
for_quinn(), noquinndependency, no quinn feature. - iroh remains key-not-config (ADR-001): iroh's endpoint is fed the
Ed25519 secret key; the
noqfeature does not attempt to serve iroh's TLS, and iroh does not appear in this crate's dependency tree. - The
tcpfeature (tokio-rustls) andacmefeature are unaffected.
Provider wiring on the QUIC path: the rustls configs this crate builds
already carry the aws-lc-rs provider (every path constructs its own
provider via builder_with_provider); noq's rustls feature
consumes that provider from the config.
Consequences
Positive:
- One QUIC implementation across the bare-QUIC and iroh transports; no duplicate quinn/noq stacks in the rewrite's binaries.
TlsErrornever has a deadQuinnWrapvariant.- The crate's MSRV floor (1.88) is honest for the whole tree rather than feature-dependent.
Negative:
- If a future consumer needs quinn (none is known), that is a new
feature alongside
noq— additive, cheap, and only paid if real. - noq is young (1.2.0, first release Feb 2026); its API may churn
faster than quinn 0.11's frozen line (accepted — n0-computer owns
both noq and iroh, and the rewrite rides their stack; pin
noq = "1.2"and bump deliberately).
Amendment (2026-09-10, from the Phase 2 implementation): the
pinned TOML block's features = ["rustls"] was written against the
noq 1.2 API; the lockfile resolves noq-proto 1.3.0, where
ServerConfig::with_crypto(crypto) — the single-arg constructor the
for_noq accessor calls — is #[cfg(any(feature = "aws-lc-rs", feature = "ring"))] (the retry-token key lives in noq's
ring_like module, which needs one of the two provider features).
The noq dependency therefore ships with
default-features = false, features = ["rustls", "aws-lc-rs"].
This does not reopen the provider decision: the config's internal
provider is still the crate's explicit
rustls::crypto::aws_lc_rs::default_provider() on every path (ADR-084
via ADR-003's provider paragraph — noq consumes the provider from the
config), and aws-lc-rs (not ring) is the feature matching that
posture.
References
docs/research/phase-0.md§Prior art: noq — the verified seam facts/workspace/noq,/workspace/iroh— the upstream clones inspected- ADR-001 — the inheritance baseline (quinn-era accessors inherited with deviations recorded here)
- ADR-002 —
TlsError(NoqWrap) - ADR-004 — accessor shapes (
&selfvsself)