phase 2: task decomposition — 8-task port graph

- crate-init: skeleton, feature gates (ADR-003), TlsError (ADR-002)
- three parallel foundation ports: identity types, fingerprint, pem+signing
- port-server / port-client in parallel (each consumes the foundation;
  client also carries credentials.rs per ADR-005 co-location)
- integration-suite: invariant pins + feature-matrix + seam round-trips
- review-impl: spec-conformance gate — the API-freeze point before the
  alknet rewrite consumes the crate
- validated: taskgraph topo (5 generations), no cycles, critical path
  len 5, risk-path 1.45; medium risk concentrated on the two broad
  ports + the suite (each a diff against a fixed extraction source,
  not open-ended work)
This commit is contained in:
2026-09-10 06:32:44 +00:00
parent d74a27f764
commit 05b3832c88
8 changed files with 706 additions and 0 deletions
+83
View File
@@ -0,0 +1,83 @@
---
id: crate-init
name: Crate skeleton — module files, feature gates, error type, re-exports
status: pending
depends_on: []
scope: narrow
risk: low
impact: project
level: implementation
tags: [scaffold, crate-init]
---
## Description
Initialize the alktls module skeleton per ADR-006: replace the
placeholder `src/lib.rs` with the eight-module layout
(`identity`, `credentials`, `fingerprint`, `server`, `client`, `pem`,
`signing` + `lib.rs`), the feature gates per ADR-003
(`default = []`; `noq`, `tcp`, `acme`), and the `TlsError` type per
ADR-002. Modules may be stubs (`pub fn` bodies `todo!`-free — empty
with doc comments) but the module map, features, deps, and error enum
land now so subsequent tasks are additive, not structural.
### What lands here
- `Cargo.toml` final shape: deps per ADR-003's TOML block (`noq` +
`noq-proto` optional, default-features off; `tokio-rustls`;
`rustls-acme`; the always-present set per the overview's dependency
posture).
- `src/lib.rs`: crate docs (the overview's shape), `TlsError` (the
ADR-002 enum verbatim, including the `noq`-gated `NoqWrap` variant),
and the re-export block (the documented public API surface).
- Empty module files with `//!` doc headers only — no function bodies.
- `.taskgraph.toml` not needed (default `./tasks` works).
### What does NOT land here
- Any ported logic (subsequent tasks).
- Any test beyond a compile assertion that the error enum matches.
## Work
1. Rewrite `Cargo.toml` features/deps per ADR-003.
2. Write `src/lib.rs` with the ADR-002 `TlsError` + module
declarations + re-exports.
3. Create the seven module files with doc headers.
4. Verify the feature matrix compiles (all four combos below).
## Verification
- [ ] `cargo build` (default, `default = []`) passes
- [ ] `cargo test --all-features` passes (noq + tcp + acme all resolve)
- [ ] Each feature alone: `cargo check --features noq`, `--features tcp`,
`--features acme`
- [ ] `cargo clippy --all-targets -- -D warnings`, `cargo fmt --check`
- [ ] `TlsError` is `#[non_exhaustive]` with exactly the ADR-002
variants (`CertLoad`, `SelfSigned`, `Rustls`, `VerifierBuild`,
`NoqWrap` noq-gated, `AcmeConfig`)
## Acceptance Criteria
- [ ] The module map matches ADR-006 (one module per file, re-exported
from `lib.rs`; public API surface is the re-export block)
- [ ] Feature gates match ADR-003 exactly
- [ ] No `todo!`/`unimplemented!`/panics in library code — stubs are
empty or error-returning, never panicking
## References
- docs/architecture/decisions/002-tlserror-shape.md (the enum)
- docs/architecture/decisions/003-noq-replaces-quinn.md (features, deps)
- docs/architecture/decisions/006-module-layout-and-tests.md (module map)
- docs/architecture/overview.md (dependency posture)
## Notes
> Agent fills this during implementation. Document any decisions,
> deviations from architecture, or relevant context discovered.
## Summary
> Agent fills this on completion. Brief description of what was
> implemented, files changed, and any follow-up needed.
+93
View File
@@ -0,0 +1,93 @@
---
id: integration-suite
name: Integration suite — invariant pins + feature-matrix + seam round-trips (tests/)
status: pending
depends_on: [port-server, port-client]
scope: broad
risk: medium
impact: phase
level: implementation
tags: [tests, integration, invariants, phase-gate]
---
## Description
The `tests/` integration suite per ADR-006: the cross-module surfaces
the in-module seed tests cannot cover. A full-crate crate has no
workspace consumers to lean on, so this suite is the invariant gate
before the alknet rewrite consumes the crate.
### The suites
1. **Server seam round-trips** — for each `TlsIdentity` variant
(X509 via generated PEM files in a tempdir, RawKey via
`Ed25519SecretKey::generate`, SelfSigned):
`TlsServerConfig::new``for_noq()` (all-features) /
`for_tcp_tls()` / `rustls_config()` all succeed; the rustls config
carries the expected ALPN list and `max_early_data_size`.
2. **Client seam round-trips**`TlsClientConfig::new` per
credentials cell → `for_noq()` / `into_rustls_config()`;
`enable_early_data` pinned true; ALPN single-value list.
3. **Verifier-selection matrix** — the full `local_identity` ×
`remote_identity` construction matrix (the port-client unit
assertions promoted to integration level, exercising the public API
only).
4. **The nine-scheme exact-list pin** — the regression-proof shape
(exact vec equality, not membership).
5. **Root-store fallback**`load_platform_root_cert_store` (or the
config built from it) yields a non-empty store even when the
platform store is empty (webpki-roots merge; assert non-emptiness
and count > 0).
6. **ACME lifecycle** (`--features acme`): construct an `Acme` identity
with staging URL + tempdir cache; assert spawn-and-return semantics,
`acme-tls/1` in the ALPN list, and the resolver wiring (no network
I/O — do NOT hit Let's Encrypt).
7. **Feature-matrix gate**: `default = []` compiles + tests pass;
`--features noq`; `--features tcp`; `--features acme`;
`--all-features` (the gate is also a CI-verifiable convention, but
the suite includes the combination that exercises every
feature-gated accessor).
### Out of scope (explicitly)
Real handshakes (transport crates' job — the scope boundary), network
ACME orders, iroh (no iroh dep exists here), SOCKS5, dispatch.
## Work
1. Write the `tests/` files (one per suite group is fine).
2. Promote any in-module assertions that exercise cross-module
behavior to integration level (keep the in-module ones too).
3. Wire the exact-list and `enable_early_data` pins.
## Verification
- [ ] Full suite green across all five feature combos
- [ ] The nine-scheme test asserts exact list equality
- [ ] `enable_early_data == true` asserted on a client config
- [ ] ACME test performs no network I/O (staging URL is constructed,
never contacted)
- [ ] `cargo clippy --all-targets -- -D warnings`, `cargo fmt --check`,
`cargo doc --no-deps` (doc comments render)
## Acceptance Criteria
- [ ] All 7 suites exist and pass
- [ ] The suite runs green with a single `cargo test --all-features`
- [ ] `tests/` layout documented in the task Summary
## References
- docs/architecture/decisions/006-module-layout-and-tests.md (the test
plan)
- docs/architecture/server.md + client.md (the invariants)
- Prior art: the extracted crate's in-module tests
(`crates/alknet-tls/src/*.rs` `#[cfg(test)]` blocks)
## Notes
> Agent fills this during implementation.
## Summary
> Agent fills this on completion.
+110
View File
@@ -0,0 +1,110 @@
---
id: port-client
name: Port client side — TlsClientConfig, verifier selection, client auth (src/client.rs)
status: pending
depends_on: [port-identity-types, port-fingerprint, port-pem-signing]
scope: broad
risk: medium
impact: phase
level: implementation
tags: [client, verifiers, port, invariants]
---
## Description
Port `src/client.rs` from alknet-tls per the ADRs: `TlsClientConfig`,
`select_server_verifier`, `build_client_auth`,
`RawKeyClientCertResolver`, `NoClientCertResolver`,
`FingerprintPinVerifier`, `load_platform_root_cert_store`.
### The API deltas (from the extracted code)
- Types rewire: `ConnectionCredentials`/`RemoteIdentity` come from this
crate's `credentials.rs` (ADR-005); fingerprint helpers from this
crate's `fingerprint.rs`; the identity from this crate's
`identity.rs`.
- `for_noq(self)` replaces `for_quinn(self)` (consuming — ADR-004);
`into_rustls_config(self)` unchanged.
### Credentials module (small, rides here)
`src/credentials.rs` — port `ConnectionCredentials` (`local_identity:
Option<TlsIdentity>`, `remote_identity: Option<RemoteIdentity>`, the
builder methods) and `RemoteIdentity` (`fingerprint: String`) from
alknet-core `credentials.rs`, including the load-bearing doc comments
(`None` is the public-X.509-endpoint state, not a placeholder — the
`Option`s drive verifier selection). This task owns the module because
the verifier selection is the semantic consumer of the bundle; the
co-location prevents semantic drift (ADR-005).
### The invariants / selection matrix (test-pinned here)
- Every config: `enable_early_data = true` (the client half of the
0-RTT invariant — ADR-001; pinned as a test) and the aws-lc-rs
provider.
- Verifier selection matrix: `Some(fingerprint)`
`FingerprintPinVerifier`; `None``WebPkiServerVerifier` over the
root store. Fail-closed for unknown raw-key remotes is structural
(the CA verifier is what `None` installs; a raw-key remote cannot
satisfy it — the failure manifests at handshake, never via
`TlsError`).
- Root-store fallback: platform certs first; if empty, merge
`webpki-roots` (never empty); native-certs load errors logged, not
returned. Testable by asserting the merge path (construct with an
empty platform store simulation if the API permits; otherwise assert
the fallback branch by construction — `load_platform_root_cert_store`
returns a non-empty store).
- Client-auth presentation: RawKey → RFC 7250 SPKI cert with
`only_raw_public_keys()` auto-detected from the DER; X509 → loaded
chain via `CertifiedKey::from_der` (errors → `TlsError::Rustls` per
ADR-002); `SelfSigned`/`None``NoClientCertResolver`
(`has_certs() == false`); `Acme``TlsError::AcmeConfig`.
- `FingerprintPinVerifier`: pin match / mismatch on
`verify_server_cert`; TLS 1.2/1.3 signature verification routes
Ed25519 SPKI through `verify_tls13_signature_with_raw_key`; a
mismatched pin fails verification.
## Work
1. Port `credentials.rs` (types + builders + doc comments).
2. Port `client.rs`; apply the deltas; rewire imports.
3. Port the extracted in-module tests.
4. Add the selection-matrix integration test (below).
## Verification
- [ ] Selection-matrix test: all four client-auth presentations × both
verifier branches construct and select the expected resolver
types (inspect via the config's client-auth/verifier state where
the API permits; otherwise assert construction success/error
kind per cell)
- [ ] `Acme` local identity → `TlsError::AcmeConfig`
- [ ] `enable_early_data == true` pinned
- [ ] Root store non-empty (fallback exercised)
- [ ] FingerprintPinVerifier unit tests ported (pin match, mismatch,
raw-key signature routing)
- [ ] `cargo test` (default), `cargo test --all-features`,
`cargo clippy --all-targets -- -D warnings`, `cargo fmt --check`
## Acceptance Criteria
- [ ] `for_noq(self)` / `into_rustls_config(self)` per ADR-004
- [ ] The selection matrix has no fourth path (fail-closed structural)
- [ ] `lib.rs` re-exports the client surface + `ConnectionCredentials`
/ `RemoteIdentity`
## References
- docs/architecture/client.md (the normative doc)
- docs/architecture/decisions/002-tlserror-shape.md, 004, 005
- alknet ADR-034 §3, ADR-088 §5, ADR-091
- Prior art: `/workspace/@alkdev/alknet/crates/alknet-tls/src/client.rs`,
`/workspace/@alkdev/alknet/crates/alknet-core/src/credentials.rs`
## Notes
> Agent fills this during implementation.
## Summary
> Agent fills this on completion.
+75
View File
@@ -0,0 +1,75 @@
---
id: port-fingerprint
name: Port fingerprint helpers + DER parser (src/fingerprint.rs)
status: pending
depends_on: [crate-init]
scope: narrow
risk: low
impact: component
level: implementation
tags: [fingerprint, port]
---
## Description
Port the fingerprint module from alknet-core
(`crates/alknet-core/src/fingerprint.rs`) into `src/fingerprint.rs`
per ADR-005: `fingerprint_from_cert_der(&[u8]) -> Option<String>`
(`ed25519:<hex>` for RFC 7250 Ed25519 SPKI, `SHA256:<hex>` for
anything else — the normalized formats from alknet ADR-030 §6),
`extract_ed25519_raw_key_from_spki(&[u8]) -> Option<[u8; 32]>`, and
the private manual DER parser (`DerParser`).
### Invariants
- Production code stays `sha2` + manual DER — no `rustls::` imports in
the module's non-test code (the extracted module's purity; ADR-006).
- The Ed25519 OID constant is `[0x2b, 0x65, 0x70]` (`1.3.101.112`);
the SPKI BIT STRING is 33 bytes (one unused-bits `0x00` + the
32-byte key). These are the RFC 7250 wire facts the parser encodes.
- `extract_ed25519_raw_key_from_spki` returns `None` for non-Ed25519
SPKI / malformed DER / X.509 certs; `fingerprint_from_cert_der`
falls back to SHA-256-hashing the full DER (returns `None` only for
empty input).
- Port the extracted in-module DER parser tests verbatim (they cover
the malformed-input edges: truncated headers, long-form lengths,
wrong OIDs, bad BIT STRING lengths).
## Work
1. Port the module wholesale (it is self-contained).
2. Port the extracted tests; assert `ed25519:<hex>` and `SHA256:<hex>`
normalization on representative inputs.
3. Confirm no `rustls::` import outside `#[cfg(test)]`.
## Verification
- [ ] Ported tests green (`cargo test fingerprint`)
- [ ] Round-trip: an Ed25519 SPKI built by `signing.rs`'s
`spki_public_key()` yields `ed25519:<hex>` matching the source
key (integration assert — this pins the normalization across
the raw-key paths)
- [ ] Malformed-DER inputs yield `None` / SHA fallback (ported edge
tests)
- [ ] `cargo clippy --all-targets -- -D warnings`, `cargo fmt --check`
## Acceptance Criteria
- [ ] The module compiles without `rustls` in production code
- [ ] Both normalized fingerprint formats are test-pinned
- [ ] `lib.rs` re-exports the two public functions
## References
- docs/architecture/decisions/005-config-types-move-into-alktls.md
- docs/architecture/decisions/006-module-layout-and-tests.md
- alknet ADR-030 §6 (fingerprint normalization — the reference)
- Prior art: `/workspace/@alkdev/alknet/crates/alknet-core/src/fingerprint.rs`
## Notes
> Agent fills this during implementation.
## Summary
> Agent fills this on completion.
+81
View File
@@ -0,0 +1,81 @@
---
id: port-identity-types
name: Port identity types — TlsIdentity, Ed25519SecretKey, AcmeDirectory (src/identity.rs)
status: pending
depends_on: [crate-init]
scope: narrow
risk: low
impact: component
level: implementation
tags: [identity, types, port]
---
## Description
Port the identity types from alknet-core `config.rs` into
`src/identity.rs` per ADR-005: `TlsIdentity` (four variants: `X509 {
cert, key }`, `RawKey(Ed25519SecretKey)`, `SelfSigned`, `Acme {
domains, cache_dir, directory, contact }`), `Ed25519SecretKey`, and
`AcmeDirectory` (`Production` / `Staging` / `Custom(String)` with
`url()`).
### The load-bearing surface (do not change)
- `Ed25519SecretKey`: `generate()`, `from_bytes(&[u8; 32])`,
`as_bytes() -> [u8; 32]`, `public() -> ed25519_dalek::VerifyingKey`,
`sign(&self, message) -> ed25519_dalek::Signature`. The byte surface
is what iroh's `iroh_base::SecretKey` consumes (ADR-005; verified
against iroh 1.1 in Phase 0). Backed by `ed25519_dalek::SigningKey`.
- `Debug` must NOT leak key material (the extracted type formats as
`Ed25519SecretKey(..)` — keep it).
- `AcmeDirectory::Production` / `Staging` URLs are pinned strings
(Let's Encrypt production + staging) — assert them in tests.
- Doc comments carry the OQ-TLS-02 resolution: `SelfSigned` on the
client path presents nothing (documented on the variant).
### What moves vs stays
`TlsIdentity`/`Ed25519SecretKey`/`AcmeDirectory` move here wholesale.
`PeerEntry`, `AuthPolicy`, `Identity`, fingerprint → peer-id
resolution stay OUT (auth layer — ADR-005's carve-out). No
`serde` derives unless the extracted code has them (check; do not add
new surface beyond ADR-005's list without noting it).
## Work
1. Port the three types + their inherent methods from
`crates/alknet-core/src/config.rs`.
2. Port the associated in-module tests (`generate`/`from_bytes`
round-trip, `AcmeDirectory` URL assertions).
3. Add the Debug-no-leak test if not present in the extracted tests.
## Verification
- [ ] `cargo test -p alktls identity` passes (ported tests green)
- [ ] `as_bytes`/`from_bytes` round-trip asserted
- [ ] `AcmeDirectory` URLs asserted (production + staging + custom)
- [ ] `Debug` output contains no key bytes (test: format then assert
hex key absent)
- [ ] `cargo clippy --all-targets -- -D warnings`, `cargo fmt --check`
## Acceptance Criteria
- [ ] `src/identity.rs` holds exactly the ADR-005 type set; no auth
layer types present
- [ ] The byte surface matches the load-bearing list above verbatim
- [ ] `lib.rs` re-exports the three types
## References
- docs/architecture/decisions/005-config-types-move-into-alktls.md
- docs/architecture/decisions/006-module-layout-and-tests.md (module map)
- Prior art: `/workspace/@alkdev/alknet/crates/alknet-core/src/config.rs`
(lines 3380: `Ed25519SecretKey`, `TlsIdentity`, `AcmeDirectory`)
## Notes
> Agent fills this during implementation.
## Summary
> Agent fills this on completion.
+78
View File
@@ -0,0 +1,78 @@
---
id: port-pem-signing
name: Port PEM loading + Ed25519 signing helper (src/pem.rs, src/signing.rs)
status: pending
depends_on: [crate-init]
scope: narrow
risk: low
impact: component
level: implementation
tags: [pem, signing, port]
---
## Description
Port the two shared helper modules from alknet-tls per ADR-005/ADR-006:
- `src/pem.rs` — `load_cert_chain(&Path) ->
Result<Vec<CertificateDer<'static>>, TlsError>` and
`load_private_key(&Path) -> Result<PrivateKeyDer<'static>, TlsError>`.
Read + `rustls_pemfile` parse; errors funnel through `TlsError` (the
extracted `io::Error` paths map to `TlsError::CertLoad` per
ADR-002's `#[from]`).
- `src/signing.rs` — `Ed25519SigningKey`: the rustls
`SigningKey` + `Signer` adapter over `Ed25519SecretKey`
(`choose_scheme` returns Some only for ED25519; `algorithm()`
is ED25519; `spki_public_key()` builds the SubjectPublicKeyInfoDer
via `rustls::sign::public_key_to_spki`). One copy shared by server +
client resolvers.
### Notes
- The extracted `pem.rs` maps a no-key-found file to an
`io::ErrorKind::InvalidData` error — under ADR-002 that surfaces as
`TlsError::CertLoad` (the `#[from] io::Error`). Keep the error kind;
the variant mapping is automatic.
- `Ed25519SigningKey` now wraps *this crate's* `Ed25519SecretKey` (from
`port-identity-types`), not alknet-core's — the import is the one
intentional change from the extraction source.
- Port the extracted tests: choose_scheme Some/None, algorithm,
SPKI non-empty, 64-byte signature, Debug-no-leak; PEM error paths
(missing file, empty file).
## Work
1. Port `pem.rs` + tests (adjust error construction to this crate's
`TlsError`).
2. Port `signing.rs` + tests (rewire to the local identity type).
3. Cross-module test: `load_cert_chain`/`load_private_key` on a
generated self-signed PEM pair (rcgen) round-trip.
## Verification
- [ ] `cargo test pem signing` green (ported + round-trip tests)
- [ ] Signature length is 64 bytes; scheme is ED25519
- [ ] PEM error paths return `TlsError::CertLoad` (not panics)
- [ ] `cargo clippy --all-targets -- -D warnings`, `cargo fmt --check`
## Acceptance Criteria
- [ ] Both modules match the extracted source modulo the identity-type
import and error mapping
- [ ] `lib.rs` re-exports `load_cert_chain`, `load_private_key`,
`Ed25519SigningKey`
## References
- docs/architecture/decisions/002-tlserror-shape.md (the error mapping)
- docs/architecture/decisions/005-config-types-move-into-alktls.md
- Prior art: `/workspace/@alkdev/alknet/crates/alknet-tls/src/pem.rs`,
`.../src/signing.rs`
## Notes
> Agent fills this during implementation.
## Summary
> Agent fills this on completion.
+106
View File
@@ -0,0 +1,106 @@
---
id: port-server
name: Port server side — TlsServerConfig, resolvers, ACME path (src/server.rs)
status: pending
depends_on: [port-identity-types, port-pem-signing]
scope: broad
risk: medium
impact: phase
level: implementation
tags: [server, acme, port, invariants]
---
## Description
Port `src/server.rs` from alknet-tls per the ADRs: `TlsServerConfig`,
`build_rustls_server_config`, `RawKeyCertResolver`,
`AcceptAnyCertVerifier`, `SelfSignedCert` / `generate_self_signed_cert`,
and the ACME branch. This is the biggest port task; the deltas against
the extraction source are all ADR-pinned, everything else is a port.
### The API deltas (from the extracted code)
- Accessors borrow: `for_noq(&self)` (ADR-004), `for_tcp_tls(&self)`
(adopted — did not exist in the extraction), `rustls_config(&self)`
(adopted — the field was `pub(crate)`; now the re-exported accessor).
- `for_noq` replaces `for_quinn`:
`noq::ServerConfig::with_crypto(Arc::new(
noq::crypto::rustls::QuicServerConfig::try_from(inner)?))`; the
failure maps to `TlsError::NoqWrap` (ADR-002/003).
- `build_rustls_server_config`'s `TlsIdentity::Acme` arm: the
extracted `unreachable!` becomes a `TlsError::AcmeConfig` return
(ADR-006; no panics in library code). The internal dispatch
invariant (Acme is handled by `new_acme`) is preserved — the arm is
defensive.
- Field name: `acme_handle` (ADR-006 unified on the alknet-spec name).
### The behavior-preservation invariants (all must be test-pinned here)
- `max_early_data_size = u32::MAX` on every path (X509, RawKey,
SelfSigned, ACME branch).
- `aws_lc_rs::default_provider()` on every path (constructed via
`builder_with_provider`; no process-default fallback).
- `AcceptAnyCertVerifier::supported_verify_schemes()` returns the
nine schemes verbatim (ED25519; ECDSA P-256/P-384; RSA PSS
256/384/512; RSA PKCS1 256/384/512).
- `acme-tls/1` appended by the crate on the ACME path only.
- Verifier behavior: `offer_client_auth() == true`,
`client_auth_mandatory() == false`, empty `root_hint_subjects`,
accepts any client cert.
- `RawKeyCertResolver`: `only_raw_public_keys() == true`, resolves the
SPKI-backed `CertifiedKey`.
### ACME path (feature `acme`)
Port `new_acme` per server.md: `rustls_acme::AcmeConfig` + `DirCache`
+ directory URL + contacts; `state.resolver()` wired in; `acme-tls/1`
appended; the event-loop task spawned (`EventOk`/`EventError` matched
to `tracing` logs — port the extracted log lines); returns immediately.
Handle stored in `acme_handle`, never aborted (detached; OQ-TLS-06).
Without the feature, `Acme` identities return `TlsError::AcmeConfig`.
## Work
1. Port the module; apply the deltas above; rewire imports to this
crate's types (identity, signing, pem, TlsError).
2. Port the extracted in-module tests (they assert most invariants).
3. Add the exact nine-scheme list pin (the extracted test only checks
two schemes' membership).
4. Feature-combo verification (below).
## Verification
- [ ] Invariant pins green: `max_early_data_size` per path,
nine-scheme exact list, resolver behavior, verifier behavior
- [ ] ACME branch (with `--features acme`): spawns, returns
immediately, appends `acme-tls/1` (test with a staging URL +
tempdir cache; do NOT hit Let's Encrypt — construct and assert
config state, assert the ALPN list)
- [ ] `Acme` identity without the `acme` feature → `TlsError::AcmeConfig`
- [ ] `for_noq` / `for_tcp_tls` round-trip per identity variant
(construction-level; handshakes are out of scope)
- [ ] `cargo test` (default), `cargo test --all-features`,
`cargo clippy --all-targets -- -D warnings`, `cargo fmt --check`
## Acceptance Criteria
- [ ] All five server invariants are test-asserted (not just compiled)
- [ ] `for_noq`, `for_tcp_tls`, `rustls_config` exist with ADR-004
signatures (`&self`; `for_tcp_tls` infallible)
- [ ] No `unreachable!`/panics in library code
- [ ] `lib.rs` re-exports the server surface
## References
- docs/architecture/server.md (the normative doc)
- docs/architecture/decisions/002-tlserror-shape.md, 003, 004
- Prior art: `/workspace/@alkdev/alknet/crates/alknet-tls/src/server.rs`
(port source; note every delta above)
## Notes
> Agent fills this during implementation.
## Summary
> Agent fills this on completion.
+80
View File
@@ -0,0 +1,80 @@
---
id: review-impl
name: Review alktls v1 implementation for spec conformance (pre-rewrite gate)
status: pending
depends_on: [integration-suite]
scope: moderate
risk: low
impact: phase
level: review
tags: [review, phase-gate, spec-conformance]
---
## Description
Review the completed port against the architecture docs before the
alknet rewrite consumes the crate. This is the one-way-door gate: the
public API surface freezes here (the rewrite compiles against it).
### The checklist
1. **API surface == ADR-004** — every accessor signature matches the
ADR sketches exactly (`&self` server / `self` client; `for_tcp_tls`
infallible; `rustls_config` borrows). Re-export block is the
documented surface.
2. **`TlsError` == ADR-002** — six variants, `#[non_exhaustive]`, no
string catch-all, `#[source]` chains intact.
3. **Invariants == ADR-001/server.md/client.md** — all five server
invariants + the client 0-RTT half + fail-closed structure, each
with a passing test (check the test asserts the behavior, not
that a compile succeeded).
4. **Deltas vs the extraction source** — diff `src/` against
`crates/alknet-tls/src/` + the moved alknet-core modules; every
difference maps to an ADR-pinned delta (identity-type rewire,
error mapping, `for_noq`, borrowed accessors, no `unreachable!`).
Any un-pinned divergence is either fixed or recorded.
5. **Feature hygiene**`default = []` lean (AGENTS.md convention 4);
tokio subset (`rt`, `sync`, `macros`) in `[dependencies]`; doc
comments on the public API; no inline `//` comments outside the
convention.
6. **Docs sync** — if the port revealed a spec mismatch, the ADR/spec
gets an amendment note (not silent divergence).
## Work
1. Run the checklist against the code.
2. File findings (fix-forward for small ones; blockers get Safe Exit
treatment).
3. Update `docs/architecture/README.md` statuses (Draft → Reviewed for
the specs) when the checklist passes.
## Verification
- [ ] The full checklist passes with findings recorded
- [ ] `cargo test`, `cargo test --all-features`,
`cargo clippy --all-targets -- -D warnings`,
`cargo fmt --check`, `cargo doc --no-deps` all green
- [ ] `cargo publish --dry-run --allow-dirty` passes (packaging
readiness: metadata, license files, exclude list)
- [ ] Spec statuses advanced where the gate passes
## Acceptance Criteria
- [ ] Zero un-pinned divergences from the architecture docs
- [ ] The API surface is declared frozen for the rewrite (README
lifecycle note)
- [ ] Findings + resolutions documented in the task Summary
## References
- docs/architecture/ (all ADRs + specs — the conformance target)
- docs/research/phase-0.md §Prior art (the extraction deltas)
- AGENTS.md (conventions 112)
## Notes
> Agent fills this during implementation.
## Summary
> Agent fills this on completion.