docs: port architecture specs and ADRs from alknet-http; write new alkhttp ADRs 067-070
Phase 1 (SDD) — architecture documentation: Ported specs (adapted for alkcall, producer/consumer terms, 6-endpoint gateway, channels-over-WS, Sub/Pub operation types): - overview.md, http-server.md, http-adapters.md, http-mcp.md - README.md index (rewritten for alkhttp) New ADRs: - 067: WebSocket carries the channels protocol (8-byte chunk demux, channel 0 = alk/call, upgrade path /alk/channels) - 068: gateway /publish endpoint for Pub operations (NDJSON body) - 069: WebTransport out of scope in alkhttp (alknet concern) - 070: from_wss consumer adapter (wss feature, tokio-tungstenite) Ported ADRs (25, same numbers, port notes + amendments where the extraction changed facts): 001-004, 010, 014, 015, 017, 022, 023, 027, 034, 036, 037, 039, 041, 042, 044, 045, 046, 047, 048, 049, 051, 066. websocket.md rewritten for the channels session; open-questions.md seeded (OQ-01 WS byte-stream adapter, OQ-02 /publish framing, OQ-03 from_wss reconnect, OQ-04 browser client ownership). Verified: cargo test, clippy -D warnings, fmt, doc --no-deps.
This commit is contained in:
@@ -0,0 +1,408 @@
|
||||
# ADR-048: WebSocket Carries the Native Call-Protocol Session, Not the Gateway Shape
|
||||
|
||||
*Ported from alknet ADR-048 (WebSocket Carries the Native Call-Protocol Session, Not the Gateway Shape); re-targeted to alkhttp.*
|
||||
|
||||
## Status
|
||||
|
||||
Accepted
|
||||
|
||||
## Status amendment (alkhttp port)
|
||||
|
||||
- **The WS path carries the channels session** (alkhttp ADR-067): a
|
||||
browser WS connection is demultiplexed by the channels protocol —
|
||||
8-byte chunk headers per alkcall ADR-034/ADR-035 — rather than being a
|
||||
bare `EventEnvelope` stream. **Channel 0 is pre-negotiated as
|
||||
`alk/call`** (alkcall ADR-036) and carries the native call-protocol
|
||||
session **exactly as this ADR describes** — the dispatch loop, the
|
||||
overlay rules, and the browsers-not-peers property all stand
|
||||
unchanged; they apply to channel 0.
|
||||
- **Framing on channel 0 is length-prefixed JSON** (alkcall's frame
|
||||
format, alkcall ADR-014) **inside the 8-byte chunk header** — **not**
|
||||
one-envelope-per-WS-message. The WS message boundary carries chunks,
|
||||
not envelopes; see alkhttp ADR-067 §framing. Sentences below that
|
||||
speak of "one `EventEnvelope` = one binary WS message" are the
|
||||
original 2026 framing, retained as decision history; the operative
|
||||
framing is the channels-chunk model just described.
|
||||
- **The default WS upgrade path is `/alk/channels`** (was
|
||||
`/alknet/call` in the alknet original — renamed per the alkcall ADR-004
|
||||
`alk/` ALPN convention and per alkhttp ADR-067's channels session).
|
||||
|
||||
## Context
|
||||
|
||||
alkhttp ADR-044 (Accepted) removed h3/WebTransport from this crate's
|
||||
scope (see alkhttp ADR-069; the alknet record deferred it) and committed
|
||||
WebSocket as the browser bidirectional path: a browser upgrades an
|
||||
HTTP/1.1 or HTTP/2 request to WebSocket and the resulting full-duplex WS
|
||||
connection carries the call protocol's `EventEnvelope` frames (in the
|
||||
current wire model: on channel 0, as length-prefixed JSON inside
|
||||
channels chunks). alkhttp ADR-044 §1 established that the call
|
||||
protocol's `call.requested`/`call.responded`/`call.completed`/`call.aborted`
|
||||
exchange "works over WebSocket with no protocol change — the same `Dispatcher`,
|
||||
the same `PendingRequestMap`, the same correlation by request ID."
|
||||
|
||||
alkhttp ADR-044 §1 also established *what shape the WS session carries* — the native
|
||||
`EventEnvelope` call-protocol session — but it does so as part of a larger
|
||||
argument about why WebTransport isn't required, not as a crisp rule an
|
||||
implementer is told not to violate. Two facts make the distinction worth its
|
||||
own explicit decision record:
|
||||
|
||||
1. **The HTTP surface has a deliberate, well-documented invoke contract: the
|
||||
`to_openapi` gateway pattern** (alkhttp ADR-042, alkhttp ADR-047). The gateway is 5 fixed
|
||||
endpoints (`/search`, `/schema`, `/call`, `/batch`, `/subscribe`), where
|
||||
`/call` takes `{ "operation": "/fs/readFile", "input": {...} }` and invokes
|
||||
through `OperationRegistry::invoke()`. It is a well-shaped, simple contract.
|
||||
An implementer writing the WS handler could plausibly ask: "should the WS
|
||||
path expose the same 5-endpoint gateway shape, so a WS client looks like an
|
||||
HTTP client?" That is a reasonable question, and the answer is no — but the
|
||||
answer is currently implicit in alkhttp ADR-044's framing, not stated as a rule.
|
||||
|
||||
2. **The two surfaces serve different architectural roles, and that difference
|
||||
is load-bearing.** The HTTP gateway is, by HTTP's nature, a *one-directional
|
||||
projection* — client initiates, server responds (see the alkhttp server
|
||||
spec, §"One-directional projection"). The whole reason WebSocket exists in
|
||||
this architecture is to *restore the call protocol's native bidirectionality
|
||||
for browsers* (alkhttp ADR-044 §4): a WS connection is full-duplex, so both
|
||||
sides can initiate `call.requested` frames. Putting the gateway's
|
||||
one-directional shape on WS re-introduces the one-directional limitation
|
||||
that WS exists to fix. The two surfaces are not interchangeable; they are
|
||||
deliberately different tools for deliberately different jobs.
|
||||
|
||||
### The two invoke contracts, contrasted
|
||||
|
||||
| Aspect | HTTP gateway (`/call`, alkhttp ADR-042/047) | WS native session (this ADR) |
|
||||
|---------|--------------------------------------|------------------------------|
|
||||
| Direction | One-directional (client→server calls only) | Bidirectional (either side can `call.requested`) |
|
||||
| Wire unit | HTTP request/response | Channels chunk (8-byte header, alkcall ADR-034/035); channel 0 payload = length-prefixed-JSON `EventEnvelope` (alkcall ADR-014) |
|
||||
| Invoke shape | `POST /call` with `{ "operation": "/fs/readFile", "input": {...} }` | `call.requested` event with `{ operation, input }` payload (the call protocol's native shape) |
|
||||
| Discovery | `GET /search` (gateway endpoint) | `services/list` as an ordinary call-protocol op |
|
||||
| Schema | `GET /schema` (gateway endpoint) | `services/schema` as an ordinary call-protocol op |
|
||||
| Streaming | `POST /subscribe` (SSE frames) | `call.responded` events as channel-0 frames (no SSE) |
|
||||
| Dispatcher | axum route handler → `OperationRegistry::invoke()` | shared `Dispatcher` (alkcall ADR-015, stream-agnostic) |
|
||||
| Multiplexing | HTTP/2 native; HTTP/1.1 sequential | Channels channel IDs (alkcall ADR-034/035) + request ID (alkcall ADR-015) |
|
||||
|
||||
The WS row is the call protocol's own native session, with WebSocket as the
|
||||
transport instead of QUIC (carried on channel 0 of the channels session per
|
||||
alkcall ADR-036). The HTTP row is a projection of that session into
|
||||
HTTP's one-directional shape, with the gateway as the deliberate interface for
|
||||
clients that only speak HTTP.
|
||||
|
||||
### Why the gateway shape is wrong on WS
|
||||
|
||||
Three concrete reasons:
|
||||
|
||||
1. **It duplicates the native invoke path with a lossier one.** The call
|
||||
protocol's `call.requested` event *is* the invoke primitive; the gateway's
|
||||
`/call` is that primitive wrapped in an HTTP envelope. On WS, the envelope
|
||||
is unnecessary — there is no HTTP request/response cycle to fit into. A
|
||||
gateway-on-WS would be a translation layer translating the call protocol to
|
||||
itself, losing bidirectionality in the process.
|
||||
|
||||
2. **It loses the per-caller filtering property the native session already
|
||||
has.** The gateway's `/search` exists to give HTTP clients the
|
||||
`AccessControl::check(identity)`-filtered discovery that the call protocol
|
||||
provides natively via `services/list`. On WS, `services/list` is already a
|
||||
call-protocol op the browser can call directly — the filtering is already
|
||||
there. A gateway-on-WS re-implements a filtering property the native session
|
||||
already provides.
|
||||
|
||||
3. **It breaks the symmetry with the QUIC path.** The `alk/call` QUIC path
|
||||
(alkcall ADR-015, alkcall ADR-022) is the native `EventEnvelope` session over
|
||||
QUIC bidirectional streams. WS is the same session over WS messages (via
|
||||
the channels session's channel 0 — alkcall ADR-036). Making the
|
||||
WS path different from the QUIC path (by putting the gateway on WS) creates
|
||||
two browser-reachable invoke contracts for no architectural reason — the
|
||||
QUIC path is the reference, and WS should mirror it, not diverge from it.
|
||||
|
||||
### The prior art is already native-session-shaped
|
||||
|
||||
The `@alkdev/pubsub` WebSocket client/server (`event-target-websocket-client.ts`,
|
||||
`event-target-websocket-server.ts`) — the working prior art alkhttp ADR-044 cites as
|
||||
the reason the WS path is cheap — already carries the `EventEnvelope { type, id,
|
||||
payload }` shape over WS binary messages, with no gateway-style wrapping. The
|
||||
call protocol's `EventEnvelope` was derived from the pubsub envelope
|
||||
(refined with typed event names and structured payloads); the delta is small
|
||||
and well-defined (see the alkcall crate docs, §"Transport agnosticism").
|
||||
A browser/Node WS client derived from the pubsub
|
||||
prior art speaks the native session shape, not a gateway shape. The
|
||||
gateway-on-WS variant would require *un-translating* the pubsub client's
|
||||
native-session shape into the gateway's `{ operation, input }` shape — work
|
||||
that has no payoff because the native shape is what both the QUIC path and the
|
||||
pubsub prior art use. *(In the current wire model, the client additionally
|
||||
speaks the channels chunk framing around those envelopes — alkcall ADR-034/035
|
||||
via alkhttp ADR-067.)*
|
||||
|
||||
## Decision
|
||||
|
||||
### 1. A WebSocket connection is a native `EventEnvelope` call-protocol session, not the HTTP gateway shape
|
||||
|
||||
The WS handler on `HttpAdapter` hands the WS message stream to the call
|
||||
protocol's shared `Dispatcher` — the same dispatch loop the call adapter
|
||||
uses for `alk/call` QUIC connections (alkcall ADR-015, stream-agnostic
|
||||
correlation; a WS message stream is another `BiStream`-satisfying
|
||||
transport). Concretely in alkhttp (per alkhttp ADR-067): the WS handler
|
||||
demultiplexes the 8-byte chunk framing of the channels protocol (alkcall
|
||||
ADR-034/ADR-035); **channel 0 is pre-negotiated as `alk/call`**
|
||||
(alkcall ADR-036) and its chunk payloads are `EventEnvelope` frames in
|
||||
alkcall's length-prefixed JSON frame format (alkcall ADR-014). The
|
||||
browser writes `EventEnvelope` frames as channel-0 chunks; the handler
|
||||
reads them and dispatches via `OperationRegistry::invoke()`. Responses
|
||||
(`call.responded`, `call.error`, `call.completed`, `call.aborted`) are
|
||||
written back as channel-0 chunks.
|
||||
|
||||
The `to_openapi` gateway endpoints (`/search`, `/schema`, `/call`, `/batch`,
|
||||
`/subscribe` — alkhttp ADR-042, alkhttp ADR-047) **do not appear on the
|
||||
WebSocket path**. They are the HTTP one-directional projection's invoke
|
||||
contract; WS carries the call protocol's own native session, which is a
|
||||
different (and richer) thing.
|
||||
|
||||
### 2. Discovery and schema are call-protocol ops, not WS-specific endpoints
|
||||
|
||||
The browser calls `services/list` and `services/schema` as ordinary
|
||||
`call.requested` events over the WS connection (channel 0). They are
|
||||
call-protocol operations, not WS endpoints. There is no `/search` or
|
||||
`/schema` on WS — those are the HTTP gateway's names for the same
|
||||
discovery primitives. The filtering the gateway provides via
|
||||
`AccessControl::check(identity)`-filtered `/search` (alkhttp ADR-042 §3)
|
||||
is provided on the WS path by the same mechanism the call protocol uses
|
||||
everywhere: `services/list` is `AccessControl`-filtered natively (see
|
||||
the alkcall crate docs, client-and-adapters, §"services/list"). No
|
||||
WS-specific discovery surface exists or is needed.
|
||||
|
||||
### 3. Subscriptions project as native `call.responded` events, not SSE
|
||||
|
||||
A `Subscription` operation invoked over WS streams `call.responded`
|
||||
events as channel-0 frames directly — no SSE `data:` framing (that is
|
||||
the `h2`/`http/1.1` projection for `/subscribe`, per the streaming
|
||||
handler decision, alkhttp ADR-049; on WS it is unnecessary because WS is
|
||||
already a framed full-duplex channel). `call.completed` closes the
|
||||
stream; `call.aborted` closes it with an error frame. This is the
|
||||
native streaming projection for the WS path, mirroring how subscriptions
|
||||
work on the QUIC path.
|
||||
|
||||
### 4. Bidirectionality is native and unchanged from the QUIC path
|
||||
|
||||
The WS call-protocol session inherits the call protocol's native
|
||||
bidirectionality (alknet ADR-043 §2, transferred to WebSocket per
|
||||
alkhttp ADR-044 §3): both sides can send `call.requested` frames. The
|
||||
browser calls operations on the hub; the hub can call operations
|
||||
registered on the browser's side, over the same session, using the same
|
||||
`PendingRequestMap` and `EventEnvelope` framing as `alk/call`. The
|
||||
browser case where the client registers no operations of its own is the
|
||||
common case — the server→client call direction is unused because the
|
||||
browser has nothing to call. That is a use-case scoping, not an
|
||||
architectural limitation.
|
||||
|
||||
### 5. This is a clarifying decision, not a new one
|
||||
|
||||
alkhttp ADR-044 §1 commits the native-session shape ("the call
|
||||
protocol's framing fits the WebSocket path cleanly ... the same
|
||||
`Dispatcher`, the same `PendingRequestMap`, the same correlation by
|
||||
request ID"). This ADR does not change that decision; it makes the
|
||||
implication an explicit, implementer-visible rule: **the WS path is the
|
||||
native session, and the gateway shape is deliberately not applied to
|
||||
it.** An implementer reading alkhttp ADR-044 alone could plausibly ask
|
||||
"should the WS path expose the gateway endpoints too?" — this ADR's job
|
||||
is to make the answer discoverable as a decision record, not implicit in
|
||||
framing.
|
||||
|
||||
## Consequences
|
||||
|
||||
**Positive:**
|
||||
- One invoke model for the call protocol, regardless of transport. The
|
||||
QUIC path and the WS path run the same `EventEnvelope` session through
|
||||
the same `Dispatcher` (on the WS path, via channel 0 of the channels
|
||||
session — alkhttp ADR-067); the HTTP gateway is the one-directional
|
||||
projection for clients that only speak HTTP. An implementer building
|
||||
the WS handler reuses the `Dispatcher` and `OperationRegistry::invoke()`
|
||||
dispatch path verbatim — no WS-specific routing, no WS-specific
|
||||
discovery surface, no second invoke contract to design or maintain.
|
||||
- The `@alkdev/pubsub`/`@alkdev/operations` TypeScript clients sync to
|
||||
the call protocol with no translation layer: their `EventEnvelope`
|
||||
shape is already the native session shape, and the call protocol's
|
||||
envelope is a refined superset of the pubsub envelope (alkhttp ADR-044
|
||||
§"Concrete prior art"). The gateway-on-WS variant would have required
|
||||
un-translating the pubsub client's native-session shape; this decision
|
||||
avoids that un-translation entirely. *(The clients also speak the
|
||||
channels chunk layer around those envelopes — alkcall ADR-034/035.)*
|
||||
- Per-caller `AccessControl`-filtered discovery is already a property of
|
||||
the native session (`services/list`). No WS-specific filtering surface
|
||||
to build or document; the call protocol's authorization model applies
|
||||
unchanged.
|
||||
- The browser is a bidirectional call target during a live session, not
|
||||
a peer-graph member (alkhttp ADR-044 §5, alkhttp ADR-034 §4). The
|
||||
native session shape is what makes this clean: the browser gets
|
||||
bidirectional call capability through the connection-local Layer 2
|
||||
overlay (alkcall ADR-019) without peer-graph membership, and the
|
||||
gateway shape would not have changed this — but it would have made the
|
||||
WS path diverge from the QUIC path for no benefit.
|
||||
|
||||
**Negative:**
|
||||
- A WS client cannot use the gateway's `{ "operation": ..., "input": ... }`
|
||||
body shape — it must speak the call protocol's native `call.requested`
|
||||
event (inside the channels chunk framing). This is honest (the WS path
|
||||
*is* the call protocol), but a developer who learned the gateway shape
|
||||
from the HTTP surface must learn the `EventEnvelope` shape (plus the
|
||||
chunk framing) for WS. The pubsub prior art and the
|
||||
`@alkdev/operations` TypeScript client already speak the envelope
|
||||
shape, so the delta is small for the primary consumer — but it is a
|
||||
real difference from the HTTP gateway's simpler `{ operation, input }`
|
||||
invoke body.
|
||||
- The 5 gateway endpoint names (`/search`, `/schema`, `/call`, `/batch`,
|
||||
`/subscribe`) are HTTP-specific and do not carry over to WS. A deployment
|
||||
documenting its surface for both HTTP and WS clients documents two invoke
|
||||
shapes (the gateway for HTTP; the native session for WS). This is the cost
|
||||
of using the right tool for each transport instead of forcing one shape onto
|
||||
both.
|
||||
|
||||
## Reversal
|
||||
|
||||
This ADR clarifies a decision alkhttp ADR-044 already committed (§1
|
||||
describes the native session; this ADR makes that the explicit,
|
||||
implementer-visible rule). The reversal posture is therefore alkhttp
|
||||
ADR-044's, not a separate one: the WS path itself is not deferred (it is
|
||||
the browser path), and the native-session-not-gateway choice is a
|
||||
clarification of what that path carries — reversing it would mean
|
||||
adopting the gateway shape on WS, which would re-introduce the
|
||||
one-directional limitation WS exists to fix (§Context reason 1). The
|
||||
original text's realistic reversal path — "WebTransport revives and adds
|
||||
a second browser bidirectional path" — is an alknet posture and does not
|
||||
apply to this crate: WebTransport is removed from alkhttp scope entirely
|
||||
(alkhttp ADR-069), and the ALPN-stream-proxy (alknet ADR-040) is an
|
||||
alknet record, not ported here. If a second browser bidirectional
|
||||
transport ever exists, it is an alknet transport concern fronting the
|
||||
stable HTTP surface this crate publishes; this ADR's rule (WS = native
|
||||
session on the channels path, not gateway) is unaffected — the gateway
|
||||
shape stays HTTP-only regardless of how many browser bidirectional
|
||||
transports exist.
|
||||
|
||||
## Assumptions
|
||||
|
||||
1. **The call protocol's `EventEnvelope` framing fits the WebSocket path
|
||||
cleanly.** In the original 2026 framing: an `EventEnvelope` is a
|
||||
self-delimited JSON object; one envelope per WS binary message. In
|
||||
the current wire model (alkhttp ADR-067): the WS message boundary
|
||||
carries channels chunks (8-byte header, alkcall ADR-034/ADR-035), and
|
||||
channel 0 — pre-negotiated as `alk/call` (alkcall ADR-036) — carries
|
||||
`EventEnvelope` frames as length-prefixed JSON (alkcall ADR-014's
|
||||
frame format) inside the chunk payload. The load-bearing property —
|
||||
self-delimited frames, no streaming deserializer across frame
|
||||
boundaries — is unchanged. This is verified by prior art: the
|
||||
`@alkdev/pubsub` WebSocket client/server carries the same
|
||||
`{ type, id, payload }` envelope over WS binary messages.
|
||||
|
||||
2. **The shared `Dispatcher` runs over the WS path unchanged.** alkcall
|
||||
ADR-015 commits stream-agnostic correlation; a WS message stream is
|
||||
another `BiStream`-satisfying transport (per alkcall ADR-038, the
|
||||
channels `ChannelConnection` is itself a `BiStreamSource`). The
|
||||
`Dispatcher` and `PendingRequestMap` are transport-agnostic; only the
|
||||
connection-establishment half differs (WS upgrade handler vs QUIC
|
||||
accept/dial).
|
||||
|
||||
3. **The primary WS consumer is a browser or Node client derived from
|
||||
the `@alkdev/pubsub`/`@alkdev/operations` prior art.** That client
|
||||
already speaks the native `EventEnvelope` shape (now wrapped in the
|
||||
channels chunk framing). The gateway's simpler `{ operation, input }`
|
||||
body shape is the HTTP path's affordance for clients that only speak
|
||||
HTTP; a client that has chosen WS has already opted into the call
|
||||
protocol's native framing.
|
||||
|
||||
4. **`services/list` and `services/schema` are sufficient discovery for
|
||||
the WS path.** They are `AccessControl`-filtered (per-caller) and
|
||||
return the full `OperationSpec` respectively. The gateway's `/search`
|
||||
and `/schema` are HTTP-shaped names for these same primitives; on WS
|
||||
the primitives apply directly. No WS-specific discovery surface is
|
||||
needed.
|
||||
|
||||
## References
|
||||
|
||||
- alkhttp ADR-067 — **the amendment that defines the current WS wire
|
||||
model**: the WS session carries the channels protocol (8-byte chunk
|
||||
multiplexing); channel 0 is pre-negotiated `alk/call` and carries the
|
||||
native call-protocol session described here.
|
||||
- alkcall ADR-034 / alkcall ADR-035 — the channels wire format (8-byte
|
||||
chunk header; pure channel multiplexing).
|
||||
- alkcall ADR-036 — channel 0 is pre-negotiated `alk/call`.
|
||||
- alkcall ADR-014 — the call protocol's hand-rolled `EventEnvelope`
|
||||
framing (length-prefixed JSON); the frame format carried in channel-0
|
||||
chunk payloads.
|
||||
- alkcall ADR-015 — call-protocol stream model; stream-agnostic
|
||||
correlation (`Dispatcher`/`PendingRequestMap`); a WS message stream is
|
||||
another `BiStream`-satisfying transport.
|
||||
- alkcall ADR-038 — `ChannelConnection` as a `BiStreamSource`; the
|
||||
channels-session side of the stream-agnostic claim.
|
||||
- alkcall ADR-022 §5 — `to_*` adapters are projections that consume the
|
||||
registry; WS is not a `to_*` adapter (it carries the native session,
|
||||
it doesn't project it).
|
||||
- alkcall ADR-019 — Layer 2 per-connection overlay where
|
||||
browser-registered ops (if any) land.
|
||||
- alkhttp [ADR-034](034-outgoing-only-x509-and-three-peer-roles.md) §4
|
||||
(amended by alkhttp ADR-044 §5) — browsers are not peers; the
|
||||
connection-local overlay gives the browser bidirectional-call
|
||||
capability without peer-graph membership.
|
||||
- alkhttp ADR-049 — the SSE projection for `/subscribe` (the HTTP
|
||||
one-directional streaming path; on WS, subscriptions project as native
|
||||
`call.responded` events, no SSE).
|
||||
- alkhttp ADR-042 — the gateway pattern this ADR clarifies is HTTP-only.
|
||||
- alknet ADR-043 §2/§3 — bidirectionality and the no-`PeerId`
|
||||
connection-local overlay, transferred to WebSocket per alkhttp ADR-044
|
||||
§3 *(alknet record; not ported to alkhttp)*.
|
||||
- alkhttp [ADR-044](044-defer-webtransport-browsers-use-websocket.md) —
|
||||
the ADR that committed WS as the browser path; this ADR clarifies the
|
||||
shape of what it committed (§1 implies the native session; this ADR
|
||||
makes it an explicit rule).
|
||||
- alkhttp ADR-047 — the gateway as the sole HTTP invoke path (the
|
||||
HTTP-only contract this ADR clarifies does not extend to WS).
|
||||
- alkhttp ADR-001 / ADR-002 — ALPN-based dispatch; `HttpAdapter` as the
|
||||
`ProtocolHandler` for `h2`/`http/1.1`; the WS upgrade rides the HTTP
|
||||
surface.
|
||||
- alkhttp ADR-069 — WebTransport removed from alkhttp scope (context for
|
||||
the reversal posture above).
|
||||
- The alkcall crate docs — call-protocol spec (§"Transport
|
||||
agnosticism") and client-and-adapters spec (§"services/list"); the old
|
||||
relative links into the alknet spec tree became textual references to
|
||||
the alkcall crate's own documentation.
|
||||
|
||||
## Port notes
|
||||
|
||||
- **Amended by alkhttp ADR-067, per the status amendment above:** the WS
|
||||
session now carries the **channels protocol** (8-byte chunk
|
||||
multiplexing, alkcall ADR-034/035) with **channel 0 pre-negotiated as
|
||||
`alk/call`** (alkcall ADR-036) instead of a bare `EventEnvelope` WS
|
||||
message stream. The dispatch/overlay/browsers-not-peers content of
|
||||
this ADR stands unchanged and applies to channel 0. The framing on
|
||||
channel 0 is **length-prefixed JSON** (alkcall ADR-014) inside the
|
||||
chunk payload — **not one-envelope-per-WS-message**; the WS message
|
||||
boundary carries chunks, not envelopes (alkhttp ADR-067 §framing).
|
||||
Original one-envelope-per-message sentences are retained as decision
|
||||
history with inline annotations (Decision 1, §Context table,
|
||||
Assumptions 1).
|
||||
- **Upgrade path rename:** the default WS upgrade path is `/alk/channels`
|
||||
(was `/alknet/call`) — renamed per the alkcall ADR-004 `alk/` ALPN
|
||||
convention and per alkhttp ADR-067 (the path carries the channels
|
||||
session). The original statement "/alknet/call" appears nowhere in the
|
||||
ported body except as this note.
|
||||
- Renames: "alknet-http" → "alkhttp"; `CallAdapter` (old name in the
|
||||
dispatch-loop sentence) is the call-protocol adapter now vendored in
|
||||
the alkcall crate; "alknet ADR-012" (stream model) → **alkcall
|
||||
ADR-015**; "alknet ADR-017 §5" (`to_*` projection) → **alkcall ADR-022
|
||||
§5**; "alknet ADR-024" (registry layering) → **alkcall ADR-019**.
|
||||
alkcall ADR numbers differ from alknet ADR numbers; each citation
|
||||
names the owning crate.
|
||||
- alknet ADR-036 (SSE mapping) and alknet ADR-049 (streaming handler)
|
||||
correspond to **alkhttp ADR-049** in this crate; the SSE `/subscribe`
|
||||
references are re-cited accordingly.
|
||||
- alknet ADR-043 is cited as an alknet record (not ported to alkhttp);
|
||||
its §2/§3 transfers are restated with alkcall ADR-019 as the overlay
|
||||
citation.
|
||||
- Links rewritten per alkhttp conventions: `../crates/http/...` and
|
||||
`../crates/call/...` relative links became textual "alkhttp server
|
||||
spec" / "alkcall crate docs" references (the original
|
||||
`http-server.md` §"WebSocket browser path" and `websocket.md` spec
|
||||
pointers describe alknet spec-tree documents; in this crate the
|
||||
equivalent content lives in the `server`/`websocket` subsystem specs
|
||||
to be written under `docs/architecture/`).
|
||||
- `OperationRegistry::invoke()`, `Dispatcher`, `CallConnection`,
|
||||
`PendingRequestMap`, `EventEnvelope` are alkcall-owned types (see
|
||||
alkcall ADR-014/015/019/022); cited textually, not re-defined here.
|
||||
- Original title preserved: "WebSocket Carries the Native Call-Protocol
|
||||
Session, Not the Gateway Shape".
|
||||
Reference in New Issue
Block a user