Extract the deferred AlknetClient as a new crate alknet-client — the client-side analogue of AlknetEndpoint. Three dial methods (QUIC + TCP+TLS via TlsClientConfig, iroh via key) produce a Connection for CallClient::spawn_dispatch / ChannelClient::from_connection to consume. The deferral collapsed because ADR-086 gave the native endpoint type three dial shapes within one endpoint type, ADR-087 broke the circular hedge, and ADR-083 gave the server-side shape to mirror by symmetry. Names the three concept layers that were tangled throughout the initial development (deployment role / establishment side / ALPN-level category) so the fix is legible. Names alknet/register as a dialable entry-point ALPN (native registration, parallel to HTTP registration in OQ-58); its wire protocol is deferred to OQ-66 (blocked on OQ-58's token model). Cross-references updated across 11 existing docs (README, overview, open-questions, OQ-55, tls, hub, core, channels README/overview/ channel-client, call client-and-adapters) to reflect OQ-55 resolved and the new alknet-client crate. Architecture review passed (2 critical, 7 warnings — all addressed).
91 lines
5.5 KiB
Markdown
91 lines
5.5 KiB
Markdown
# OQ-66: `alknet/register` Wire Protocol
|
|
|
|
- **Origin**: `docs/architecture/decisions/089-alknetclient-native-dial-seam.md`
|
|
§6; `docs/architecture/crates/client/README.md` §"`alknet/register`".
|
|
- **Status**: deferred(scope)
|
|
- **Door type**: one-way (the wire protocol — once native workers and
|
|
hubs exchange registration frames, the format is compatibility-locked)
|
|
- **Priority**: medium
|
|
- **Impacts**: Blocks native worker registration over QUIC/TCP+TLS
|
|
without HTTP. A worker that has no HTTP client (a minimal native
|
|
worker, an iroh-only deployment) cannot enroll its key with a hub
|
|
until this is specced and implemented. The HTTP registration
|
|
endpoint (OQ-58) remains the first implementation, so this does NOT
|
|
block the first hub deployment (web + native uses HTTP registration
|
|
for worker provisioning). It blocks the *native-only* registration
|
|
path and the no-HTTP minimal-hub case.
|
|
- **Blocked on**: OQ-58's token model (one-time vs. refresh,
|
|
single-use vs. multi-use, rotation). The `alknet/register` wire
|
|
protocol and the HTTP registration endpoint (OQ-58) share the
|
|
enrollment semantics and the token model — they should converge on
|
|
one model before either's wire format is locked. OQ-58 is open
|
|
(resolvable now); this OQ is blocked on its resolution. The
|
|
frame-format fork (reuse `EventEnvelope` vs. standalone) and the
|
|
enrollment-trait shape (point 5) are independently workable but
|
|
not independently decidable — they depend on the token model.
|
|
- **What is decided (ADR-089 §6)**: `alknet/register` is a dialable
|
|
ALPN — an **entry point** (ADR-086 §2) accepted without an
|
|
established peer identity. Two registration cases exist, both hub
|
|
concerns and both optional:
|
|
- **Token registration** — a freshly-provisioned worker (docker,
|
|
vast.ai, runpod) generates its local identity, dials the hub on
|
|
`alknet/register`, presents a one-time registration token, and
|
|
enrolls its key. The hub creates a `PeerEntry` (mixed-fingerprint
|
|
shape, ADR-034 §3) and returns a session credential.
|
|
- **No-token (open) registration** — a hub that hosts public
|
|
services over channels, or a relay/gateway, accepts registration
|
|
without a token. The enrollment creates a `PeerEntry` with no
|
|
token requirement.
|
|
The dial is the same as any other ALPN (`AlknetClient::dial_quic` /
|
|
`dial_tcp_tls` on `b"alknet/register"`); the difference is the
|
|
handshake protocol on the resulting `Connection`.
|
|
- **What is open**: the **wire protocol** — the handshake on the
|
|
`Connection` after the dial. Specifically:
|
|
1. **Frame format** — does `alknet/register` reuse the call
|
|
protocol's `EventEnvelope` framing (length-prefixed JSON), or
|
|
does it have its own minimal framing? Registration is a one-shot
|
|
request/response (send public key + token, receive session
|
|
credential), not a long-lived call session. Reusing `EventEnvelope`
|
|
ties the register ALPN to `alknet-call` (a dependency); a minimal
|
|
own-format keeps it standalone but adds a second wire format.
|
|
2. **Token model** — one-time vs. refresh, single-use vs. multi-use,
|
|
rotation. This is the same open question as OQ-58 (the HTTP
|
|
registration endpoint's token model). The two paths should share
|
|
the token model — a token issued by the hub works over both HTTP
|
|
and `alknet/register`.
|
|
3. **No-token policy** — who decides whether a hub accepts
|
|
no-token registration? Is it a `DynamicConfig` flag, an
|
|
`IdentityProvider` policy, or a hub-crate config? What `PeerEntry`
|
|
shape does an open-registration enrollment produce (no
|
|
`auth_token_hash`, fingerprint-only)?
|
|
4. **Session credential return** — what does the hub return on
|
|
successful registration? A `PeerEntry`? A session token? Both?
|
|
How does the returned credential feed into the subsequent
|
|
`alknet/channels` connection's `CallCredentials`?
|
|
5. **Relationship to OQ-58** — the HTTP registration endpoint
|
|
(OQ-58) and `alknet/register` share the enrollment semantics
|
|
(create `PeerEntry`, return credential) but differ in transport
|
|
(HTTP vs. raw ALPN). Should they share an enrollment trait in
|
|
`alknet-hub`, with the HTTP endpoint and the `alknet/register`
|
|
handler as two transport-specific front-ends? Or are they
|
|
separate handlers that happen to call the same `IdentityStore`
|
|
write path?
|
|
- **Resolution**: Not yet decidable. The token model (point 2) is the
|
|
shared dependency with OQ-58 — both paths should converge on one
|
|
model. The frame format (point 1) is a genuine fork: reusing
|
|
`EventEnvelope` adds an `alknet-call` dependency to the register
|
|
path (which may be fine — the hub already depends on
|
|
`alknet-call`); a standalone format keeps register minimal but
|
|
diverges. The relationship to OQ-58 (point 5) is the shape question
|
|
that determines whether the register handler lives in `alknet-hub`
|
|
(alongside the HTTP endpoint) or in a separate crate. These need a
|
|
dedicated ADR that works through the token model, the frame format,
|
|
and the enrollment-trait shape together — they are not independently
|
|
decidable.
|
|
- **Cross-references**: ADR-089 (§6 — names the ALPN and its
|
|
entry-point role; defers the wire protocol to this OQ), OQ-58
|
|
(worker registration flow — the HTTP path; shares the token model),
|
|
ADR-086 (§2 — entry-point vs. endpoint ALPN distinction),
|
|
ADR-034 (§3 — the mixed-fingerprint `PeerEntry` shape token
|
|
registration creates), ADR-072 (channel 0 identity resolution —
|
|
the path the session credential feeds into). |