docs(review 006 Unit 4): spec reconciliation — OQ-05 resolved, WS data-channel docs to the landed state

- OQ-05: deferred → resolved (2026-09-04, review 006 Unit 2+3); the
  consumer-set reframe recorded (WS is also the native-client fallback
  behind hostile NAT/firewall; OQ-04 does not block the wiring).
- ADR-067: status amendment + the v1-cut blockquote gains the Wired
  (2026-09-04) note — per-session-fork shape, openable surface, gates.
- ADR-048: landed-state amendment — §4's hub→browser direction has its
  object (op/register → connection overlay, hub composes via the
  retained Arc<CallConnection>); the op/register ACL posture (UP-02,
  SRV-10 precedent) recorded.
- websocket.md: the step-7 deferral note and the §"Data channels for
  browsers" status block removed (the section now documents the landed
  surface: with_ws_openable_alpns, the OpenableAlpns fallback, cap
  policy, discovery, gates); idle-knob deployment note for silent data
  channels (semantics unchanged; the 60 s default bites more often —
  set None at assembly for long-lived interactive channels).
- Review 003 status → remediated (all findings closed; log in review
  006); its Unit-4 section marked landed.
- alknet-ADR-044 §5 pointer checked: not stale.

Verification: cargo test 454 / 0; --all-features 582 / 0; clippy
(both) clean; fmt clean; doc clean.
This commit is contained in:
2026-09-04 16:17:11 +00:00
parent 2053420f7d
commit 64fa10be31
5 changed files with 100 additions and 33 deletions

View File

@@ -36,6 +36,21 @@ Accepted
> replace other peer-announced ops but never the serving side's own
> registrations — the WS session's `op/register` handler gates on the
> session fork.
>
> **Landed (2026-09-04, review 006 Unit 2+3):** the WS wiring this
> note tracks is in — the hook forks the base registry per session,
> registers the channel ops + openables + bootstrap discovery +
> `op/register` on the fork, and dispatches over it; the session
> retains its live `Arc<CallConnection>` in `WsSessions` (the hub's
> reach-the-browser handle). §4's hub→browser call direction now has
> its object: announced ops land in the connection overlay via
> `op/register`, and the hub composes them through the connection
> handle (gate:
> `op_register_served_per_session_and_collision_is_already_exists`).
> The `op/register` ACL posture on this surface: registered with
> `AccessControl::default()` (the SRV-10 permissive-crate-default
> precedent); deployments gate via a stricter `ChannelsPolicy`
> passed through the hook (review 006 UP-02 decision).
## Status amendment (alkhttp port)

View File

@@ -3,7 +3,8 @@
## Status
Accepted (amended 2026-08-29 — the data-channel half of the WS path is
deferred, not yet wired; see [OQ-05](../open-questions.md))
deferred, not yet wired; see [OQ-05](../open-questions.md); amended
2026-09-04 — the deferred wiring landed, review 006 Units 23)
## Context
@@ -106,6 +107,18 @@ On upgrade, the handler:
> sessions (review-001, WS-03). The deferral and its rationale are
> recorded in [OQ-05](../open-questions.md); the design above is the
> contract the deferred wiring implements.
>
> **Wired (2026-09-04):** step 4 landed (review 006 Unit 2+3) in the
> per-session-fork shape alkcall ADR-047 §4 amendment #2 decided: the
> `install_channel_zero` hook forks the deployment's base registry,
> registers the generic channel ops + the deployment's openables
> (`HttpAdapter::with_ws_openable_alpns`, request-extension fallback)
> + the bootstrap discovery set + `op/register` on the fork, and
> dispatches over it. Openable set default: none (channel 0 only).
> The session retains its live `Arc<CallConnection>` in `WsSessions`
> (WS-26). Gates: the six e2e scenarios in
> `tests/ws_upgrade_session.rs` + the `services/list-peers` announced-op
> discovery gate (alkcall 0.3.1).
Everything ADR-048 says about dispatch — `call.requested`
`Dispatcher::dispatch_requested` with `AccessControl::check` gating,
@@ -169,7 +182,7 @@ in-line channels session:
- [websocket.md](../websocket.md) — the full WS session spec (its
§"Data channels for browsers" carries the same v1-cut note)
- [OQ-05](../open-questions.md) — the data-channel v1 cut deferral
(status `deferred(scope)`; reopened when a browser consumer lands)
(resolved 2026-09-04: the wiring landed, review 006 Units 23)
- [ADR-048](048-websocket-native-session-not-gateway.md) — the native
session (not gateway shape) decision this ADR amends (channel 0
framing; upgrade path)

View File

@@ -80,8 +80,8 @@ with their resolutions; new alkhttp OQs start at OQ-01.
- **Origin**: review-001 finding WS-03 (`docs/reviews/001-initial-implementation-review.md`),
[ADR-067](decisions/067-websocket-carries-channels.md),
[ADR-048](decisions/048-websocket-native-session-not-gateway.md)
- **Status**: deferred(scope: v1 cut — no browser consumer yet; reopened
when one lands)
- **Status**: resolved (2026-09-04 — review 006 Unit 2+3, `030c5ef`;
upstream mechanisms in alkcall 0.3.0)
- **Priority**: medium
- **Question**: ADR-067 §"Data channels for browsers" promises
browser-opened data channels (open ops on channel 0 → chunk
@@ -96,25 +96,37 @@ with their resolutions; new alkhttp OQs start at OQ-01.
deferred is the *wiring*: passing the deployment's openable-ALPN
registrations and `ChannelLifecyclePolicy` through the WS upgrade
path, plus a browser-opened-channel end-to-end test.
- **Resolution**: (pending — v1 cut recorded 2026-08-29 in ADR-067 and
ADR-048; the recently landed WS robustness work — idle-read timeout,
session caps/eviction, pump consolidation — is the foundation the
deferred work builds on. **2026-09-03**: the alkcall mechanisms this
wiring composes on landed — alkcall review 004 Units 13: the
per-session fork as dispatch registry (alkcall ADR-047 §4 amendment
#2), the opt-in connect-side serving loop
(`Dispatcher::serve_single_stream`), and the `op/register` bootstrap
op (alkcall ADR-022 amendment 2026-09-03). **2026-09-04**: alkcall
review 005 remediated the landed mechanisms (serving-loop
concurrency, `op/register` collision policy, spec round-trip
completeness) and alkcall 0.3.0 shipped them; alkhttp now consumes
0.3. What remains here is alkhttp-side wiring only — alkhttp review
003 Unit 2.)
- **Resolution**: The wiring landed (2026-09-04, alkhttp review 006
Unit 2+3): the `install_channel_zero` hook forks the deployment's
base registry per session, registers the generic channel ops, the
deployment's openable ALPNs (`HttpAdapter::with_ws_openable_alpns`,
request-extension fallback), the bootstrap discovery set, and
`op/register` (alkcall ADR-022 amendment), then dispatches over the
fork — alkcall ADR-047 §4 amendment #2's per-session-fork shape.
The session retains its live `Arc<CallConnection>` in `WsSessions`
(evicted with the session). One premise of the original deferral
was corrected along the way (review-003 WS-23): "reopened when a
browser consumer lands" underestimated the consumer set — WS is
also the native-client fallback behind hostile NAT/firewall, and a
Rust WS consumer (the `test_support` client shape) is a legitimate
first consumer. **OQ-04 does not block this wiring**; a browser
consumer needs only binary-frame parsing + byte reassembly ahead of
wasm-targeted alkcall. What the deferral rationale got right: the
alkcall-side machinery was indeed complete — but two wiring
blockers turned out to be design gaps (review-003 WS-24/WS-25),
resolved upstream in alkcall 0.3.0 before the wiring could land.
Gate coverage: the six e2e gates in `tests/ws_upgrade_session.rs`
(open/discoverable/bytes round-trip, close + ledger decrement, cap
denial, mid-open disconnect teardown, `TooLarge` demux resync,
`op/register` + collision), plus the `services/list-peers`
announced-op discovery gate (alkcall 0.3.1).
- **Cross-references**: [ADR-067](decisions/067-websocket-carries-channels.md),
[ADR-048](decisions/048-websocket-native-session-not-gateway.md),
[websocket.md](websocket.md), tasks/websocket/review-001-ws-data-channel-decision.md,
alkcall reviews 004005 (`alkcall/docs/reviews/004-per-connection-dispatch-and-client-serving-review.md`,
`alkcall/docs/reviews/005-serving-loop-concurrency-and-op-register-review.md`)
`alkcall/docs/reviews/005-serving-loop-concurrency-and-op-register-review.md`),
alkhttp review 003 (the drill-down), review 006 (the consequence
review + remediation log)
## Resolved (ported)

View File

@@ -1,6 +1,6 @@
---
status: draft
last_updated: 2026-08-30
last_updated: 2026-09-04
---
# WebSocket — the Browser Bidirectional Path (Channels over WS)
@@ -89,8 +89,12 @@ route on `HttpAdapter`'s router. The handler:
7. Data channels (1..N) route per the deployment's openable-ALPN
registrations; the browser opens them via the per-ALPN open ops on
channel 0 (alkcall ADR-047), the same mechanism any consumer uses.
*(Deferred wiring, v1 cut — see [OQ-05](open-questions.md);
step 6, channel 0, is all v1 implements.)*
Wired 2026-09-04 (review 006 Unit 2+3): the hook registers the
deployment's openables — `HttpAdapter::with_ws_openable_alpns`
(default: none) or the `OpenableAlpns` request-extension fallback —
plus the generic channel ops, the bootstrap discovery set, and
`op/register`, on the per-session fork (alkcall ADR-047 §4
amendment #2).
The **default upgrade path is `/alk/channels`** (was `/alknet/call` in
the alknet design). The path must not collide with the reserved
@@ -209,6 +213,17 @@ strict**:
the same deployment posture as `from_wss`'s drop monitor
([ADR-070](decisions/070-from-wss-consumer-adapter.md)): the idle
knob bounds *demux parking*, not app liveness.
- **Data channels sharpen this knob's bite** (surfaced with the
data-channel wiring, review 006): a silent-but-alive *data channel*
(an idle SSH-style session, an open-but-quiet tunnel) forwards no
chunks, so the deadline runs out and the whole WS session is evicted
with `1001` — exactly the same semantics as before the wiring
(this is not a new rule), but the 60 s default now hits more often
because sessions live longer and carry quiet channels. A deployment
serving long-lived interactive channels should set
`with_ws_idle_timeout(None)` at assembly and lean on the same levers
as above; the idle knob remains a demux-parking bound, not an
application keepalive.
- Layered note (the WS-13/FWD-15 interaction recorded here): the
*HTTP* SSE path (`/subscribe`) sends server-side keep-alive comment
frames every 15 s — see
@@ -243,11 +258,6 @@ before ACL). This is alkcall ADR-017's model; see also
### Data channels for browsers
> **Status (2026-08-29):** decided design, deferred wiring — the v1 WS
> path installs channel 0 only; browser data-channel opens are not yet
> wired (review-001, WS-03; [OQ-05](open-questions.md)). The mechanism
> below is the contract the deferred wiring implements.
A browser opens a data channel exactly as any channels consumer:
1. Calls the per-ALPN open op on channel 0
@@ -264,6 +274,17 @@ This is what makes the WASM-SSH-client-in-a-browser use case (the one
that motivated the alknet WebTransport track) workable over WS: the
SSH byte stream rides a data channel.
The openable set is declared with `HttpAdapter::with_ws_openable_alpns`
(each `OpenableAlpn { spec, open_handler }`; the ALPN-specific handlers
stay in the ALPN crates — alkhttp ferries the registrations), with the
`OpenableAlpns` request-extension fallback for bare-registry/custom
upgrade routes. Cap policy is the `ChannelsPolicy` extension (one
instance consulted by both the open wrappers and the demux teardown).
Peer-announced ops (`op/register`) land in the connection-local
overlay; discovery: `services/list` (the session's own surface) and
`services/list-peers` (peer-announced ops, alkcall 0.3.1). E2E gates
for the whole flow live in `tests/ws_upgrade_session.rs`.
### Bidirectionality
The WS channels session inherits both protocols' native

View File

@@ -2,7 +2,11 @@
## Status
Verified, open for remediation.
Remediated (2026-09-04). WS-24/WS-25 resolved upstream (alkcall 0.3.0,
review 006); WS-20/21/22/23/26/27 + UP-01 landed (review 006 Units
23, `030c5ef`); Unit 4 docs landed with review 006 (OQ-05 resolved).
The remediation log lives in
[review 006](006-alkcall-0.3.0-consequence-review.md).
## Scope
@@ -447,17 +451,19 @@ Using `test_support::WsClient` (the Rust-native-consumer shape):
5. `TooLarge` chunk on a data channel survives (demux resync) —
already proven alkcall-side; assert it through the WS path.
## Unit 4 — spec reconciliation (docs)
## Unit 4 — spec reconciliation (docs) — LANDED (2026-09-04, review 006)
- OQ-05 → resolved (or narrowed to the remaining piece), with the
consumer-set reframe recorded (WS-23): browser + native fallback;
OQ-04 not blocking.
- OQ-05 → resolved, with the consumer-set reframe recorded (WS-23):
browser + native fallback; OQ-04 not blocking.
- ADR-067 v1-cut note and ADR-048 reconciliation note updated to the
landed state; websocket.md §"Data channels for browsers" status
block removed; the alknet-ADR-044 §5 pointer checked for staleness.
block removed; the alknet-ADR-044 §5 pointer checked (not stale).
- websocket.md gains the idle-knob deployment note for silent data
channels (already true, just surfaced where a deployer reads).
Landed with review 006 Units 23; see review 006's remediation log
for the landed shape and its verification.
---
## Verification log (this pass)