Files
alkcall/docs/architecture/decisions/054-outgoing-only-x509-three-remote-roles.md
T
glm-5.3-flash 5f019c02f1 docs: re-key architecture docs off the alknet mono-repo — speak as alkcall
The ported docs still framed alknet siblings (alknet-core/-call/-channels/
-http/-tls/-client) as live load-bearing context of this crate. With the
extraction complete and alknet headed for glue-level replacement, the docs
now speak as alkcall and cite the real sibling crates (alkhttp, alktls,
alktty, alktunnels, alktrader).

- ADR-054 (new): re-own the verifier-selection rule in-crate — three
  remote roles (public X.509 endpoint / transport relay / hub),
  ServerCertVerifier by PeerEntry presence, RemoteIdentity None
  load-bearing. Provenance: alknet ADR-034 (never ported), demoted to
  footnote. Resolves OQ-21's cross-repo authority gap.
- OQ-43 (new, deferred(scope)): composition-layer ownership and shape
  after the alknet replacement — the named receiver for the
  downstream-side deferrals (OQ-33 endpoint layer, OQ-41 QUIC-native
  substrate, OQ-42 hub broker, OQ-19 persistence adapters, ADR-045 dial
  seam). README layering diagram redrawn with the composition layer as
  TBD-ownership instead of "alknet / alknode" in concrete.
- Spec docs reframed: titles, self-references, dial/TLS/from_jsonschema
  homes, malformed legacy cite rows removed; dead relative research
  paths qualified as source-repo paths.
- ADR amendments (append-only): 027 (alknet-http -> alkhttp), 031 (post-
  extraction state), 044 (split landed as modules in alkcall), 045
  (name normalization; citation-space note).
- Citation hygiene: unprefixed/colliding source-repo cites prefixed
  ("alknet ADR-NNN (provenance)") across 009/011/022/034/035/038/040/
  043/044/045; stale OQ cites corrected (session registries OQ-04, batch
  semantics OQ-03, verifier rule ADR-054); stale anchors fixed.
- README provenance note consolidated; citation conventions documented.

Verification: markdown link check (all local links resolve, all in-crate
ADR cites point at existing decisions/ files); table integrity check
(uniform row widths across open-questions.md and edited tables); residual
alknet-mention sweep (only provenance/historical/intentional framing
remains); architecture review subagent pass with zero remaining criticals.
Docs-only change — no code paths touched.
2026-10-13 10:53:47 +00:00

125 lines
5.6 KiB
Markdown

# ADR-054: Outgoing-Only X.509 and the Three Remote Roles (Re-Owned In-Crate)
## Status
Accepted (re-owns the verifier-selection rule for alkcall's surface;
provenance: alknet ADR-034, not ported)
## Context
alkcall's connection surface depends on a verifier-selection rule and a
role taxonomy that were decided while this crate was a subdirectory of
the alknet mono-repo. The deciding ADR (alknet ADR-034, "Outgoing-Only
X.509 and Three Peer Roles") was never ported, so the rule's authority
lives in a cross-repo link — a dependency on a document outside this
crate for a constraint that binds this crate's public surface:
- `ConnectionCredentials.remote_identity: None` semantics (ADR-022 §7,
(ADR-022 §7; alknet ADR-034 §2/§3, provenance): `None` is a load-bearing state — the
public-X.509-endpoint path, not a missing field.
- Client-side `ServerCertVerifier` selection is by `PeerEntry`
presence, not by key type alone (OQ-14 #2).
- `PeerEntry` asymmetry: a pure-client connection to a public X.509
endpoint is not in the call-protocol peer graph on the client side
(no `PeerEntry`, no `PeerId`, no `PeerRef::Specific` routing).
The alknet mono-repo is being rewritten as a thin glue layer over this
crate and its siblings; cross-repo ADR links will not survive that
rewrite as authority. The rule must be owned here.
## Decision
alkcall re-owns the rule in-crate. Three things are adopted:
### 1. Three remote roles
The single label "X.509 endpoint" conflated three structurally
different remote roles:
- **Public X.509 endpoint** — a remote server reachable by domain
name, authenticated by a CA-issued X.509 cert. The local node is a
*client* of it (a third-party API, a public hub dialed over the
open internet, a peer that exposes domain + X.509 instead of an
Ed25519 raw key). The client authenticates to the server by bearer
token (`auth_token` payload field when riding the call protocol);
the server authenticates to the client by CA verification
(WebPKI), not fingerprint pinning.
- **Transport relay** — a connectivity-assistance node
(iroh's DERP-equivalent) that forwards encrypted datagrams between
peers who cannot directly connect. It is infrastructure, not an
application peer: no registered operations, no peer graph
participation, no `PeerEntry`. Its identity is the transport's
concern, not this crate's.
- **Hub / hosting node** — an application peer acting as a hub in a
hub-and-spoke topology. An ordinary `PeerEntry` holding mixed
fingerprints (Ed25519 raw key and/or X.509) — fingerprint pinning
applies on both cert paths.
### 2. Verifier selection is by `PeerEntry` presence, not key type
The client-side `ServerCertVerifier` is selected by whether the local
node holds a `PeerEntry` for the remote:
| Local `PeerEntry` for remote? | Remote cert | Verifier | Peer graph? |
|-------------------------------|-------------|----------|-------------|
| yes | Ed25519 or X.509 | fingerprint pin | in (`PeerId` resolved from client-cert fingerprint — ADR-025 §5) |
| no | X.509 | `WebPkiServerVerifier` (CA) | **not in** (no `PeerId`) |
| no | Ed25519 raw key | fail closed (no CA to fall back to) | not in |
### 3. `remote_identity: None` is load-bearing
`Some(fingerprint)` means "pin this" (known peer). `None` means "no
`PeerEntry` for this remote" — CA verification for X.509 remotes,
hard failure for Ed25519 raw-key remotes. An implementation must not
default `remote_identity` to a placeholder to satisfy the field, and
must not treat `None` as "skip verification."
### 4. Scope of the re-own
This ADR is the deciding authority for alkcall's surface
(`ConnectionCredentials`, `RemoteIdentity`, the `ServerCertVerifier`
selection the dial-composer implements, `PeerEntry` asymmetry in the
peer graph). It does not re-own alknet ADR-034's other content (ACME
issuance, cert rotation, the alktls config surface) — those remain
properties of the transport/composition layer (see OQ-43, composition
layer). alknet ADR-034 is demoted to provenance: historical origin of
this rule, cited as such.
## Consequences
Positive:
- The constraint binding alkcall's public surface is decided in this
crate's decision log; cross-repo link rot cannot strip the authority.
- OQ-21's "deciding ADR (alknet ADR-034, not ported)" caveat is
resolved — the surviving surfaces (`client-and-adapters.md`
§credentials, ADR-025's `PeerEntry` asymmetry) now cite an in-crate
ADR.
- The alknet rewrite can proceed without a documentation dependency
from this crate on the old repo's ADR numbering.
Negative:
- One more rule with a historical origin story in a different numbering
space; the provenance note (README §References) is the single place
that maps old to new.
## References
- [client-and-adapters.md](../client-and-adapters.md) — the working
spec carrying these semantics (§Credential sources for connections,
§Constraints "Pure-client X.509 connections", `remote_identity`
load-bearing rule)
- [ADR-022](022-call-protocol-client-and-adapter-contract.md) §7 —
transport-identity dimensions on the call protocol
- [ADR-025](025-peerentry-and-identity-id-decoupling.md) —
`PeerEntry` asymmetry, `PeerId` source, client-cert fingerprint →
`peer_id` resolution
- [ADR-012](012-connectioncredentials-decouple-dial-from-call.md) —
`ConnectionCredentials` shape (the dial consumes it; verifier
selection is applied there)
- OQ-21 (resolved by this ADR), OQ-43 (composition-layer ownership —
the transport/composition half mentioned in §4's scope carve-out)
- Provenance: alknet ADR-034, "Outgoing-Only X.509 and Three Peer
Roles" (`/workspace/@alkdev/alknet/docs/architecture/decisions/`),
retained as history, not authority