Files
alkhttp/docs/architecture/open-questions.md
T
glm-5.3-flash 802d94ec07 docs(review 007 Unit 2): WS-31 discovery-shadowing note + record corrections
- WS-31: websocket.md §"Data channels for browsers" + ADR-067's landed
  note record that WS-session discovery is the bootstrap set — the
  hook's bootstrap `services/*` registrations overwrite a
  base-registry `services/*` registration on the WS path by design
  (a deployment's custom `services/list` is shadowed on WS sessions
  only).
- ADR-048's landed note: correction + completion — the WS-26
  retention sentence was aspirational at the landed commit (WS-28) and
  is now real; the UP-02 posture's override half is now an explicit
  surface (`with_ws_op_register_acl` / `OpRegisterAcl`), with the
  note that `ChannelsPolicy` could not carry an op ACL.
- ADR-067's landed note: review-007 notes (WS-28 fix + gate, WS-29
  surface, WS-31 record).
- OQ-05 resolution: the retention claim carries the WS-28 correction.
- review-006 UP-02 log + WS-26 paragraph: corrections marking what the
  pre-fix tree did not have, with the landed remediation named.
- review-002 WS-17: the "bounded at 64 sessions" claim corrected —
  the bare-registry semaphore was per-request and bounded nothing;
  `SessionSlots` is the shared-cap surface.
- review-007 status: open for remediation → remediated, with the
  decisions taken (both "implement" options) and the gate names.

Verification: cargo test 454 passed / 0 failed; cargo doc --no-deps
clean (6 pre-existing warnings, identical at baseline).

Review: docs/reviews/007-ws-data-channel-surface-review.md
2026-09-05 05:45:31 +00:00

154 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Open Questions
Centralized tracker. Format follows the SDD process
(`docs/sdd_process.md` §Open Questions Format). Ported alknet OQs that
resolved before the extraction are recorded in the resolved section
with their resolutions; new alkhttp OQs start at OQ-01.
## Status legend
`open` | `resolved` | `deferred(scope)` | `partially resolved`
## Open
### OQ-01: WS ↔ byte-stream adaptation semantics
- **Origin**: [websocket.md](websocket.md), [ADR-067](decisions/067-websocket-carries-channels.md)
- **Status**: resolved (POC `ws-byte-adapter`; validated end-to-end — see
the task's Summary in `tasks/websocket/byte-adapter.md`)
- **Priority**: high
- **Resolution**: The adapter treats the WS message stream as a byte
stream in both directions; the 8-byte chunk header is the only
framing. Inbound: WS read task → bounded mpsc (64 slots; backpressure
= send awaiting capacity, applying TCP-level backpressure to the
socket) → `AsyncRead` drains; channel close = EOF. Outbound: a writer
task parses 8-byte chunk headers out of the pending byte buffer (live-
confirmed: a single response frame arrives as TWO chunks —
`write_frame`'s prefix and body surface as separate mux payloads) and
emits one WS message per chunk, splitting at a 1 MiB
`WS_MESSAGE_CAP` (receiver's boundary is the chunk header, not the
message). Flush is a no-op (writes queue; the writer task emits
independently). Close: WS close → read EOF → REQ-CH-02 teardown;
`shutdown` closes the write channel (mux pumps emit zero-length
sentinels on sender drop). Client-side consequence: chunk ≠ frame —
channel-0 consumers reassemble length-prefixed frames from the byte
stream; and the dispatcher reads `operationId` from the request
payload.
- **Cross-references**: ADR-067, [websocket.md](websocket.md),
tasks/websocket/byte-adapter.md
### OQ-02: `/publish` body framing details
- **Origin**: [ADR-068](decisions/068-gateway-publish-endpoint.md)
- **Status**: resolved (implementation: gateway-publish task, 2026-08-28)
- **Priority**: medium
- **Resolution**: First line of the NDJSON body carries
`{ "operation": "/{service}/{op}", "chunk": {...} }`; subsequent
lines are chunk values only. Terminal errors are plain HTTP status +
JSON body (NOT an NDJSON line) — consistent with every other gateway
endpoint's error surface. A `?operation=` query parameter was
considered and rejected: it duplicates the first-line field and adds
a second way to name the op (two sources of truth) for no curl-ability
gain. The first-line convention is the single naming point.
Implemented in `src/gateway/routes.rs::publish_handler`.
### OQ-03: `from_wss` reconnection semantics
- **Origin**: [ADR-070](decisions/070-from-wss-consumer-adapter.md)
- **Status**: open
- **Priority**: medium
- **Resolution**: (pending)
- **Question**: On a dropped WSS connection, does `from_wss`
auto-reconnect + re-discover (`services/list`) + reconcile imported
registrations, or does v1 surface call failures (`INTERNAL`,
retryable) and leave the policy to the assembly layer? The v1
default (fail with retryable errors) is documented in ADR-070; the
question is whether a built-in policy is ever warranted.
### OQ-04: Browser client library ownership
- **Origin**: [websocket.md](websocket.md)
- **Status**: open
- **Priority**: low
- **Blocked on**: a concrete browser consumer (the alk UI) needing the
JS/TS client for channels-over-WS. The framing contract is the
alkcall BAST document (`chunk-header.bast.json`); the client library
lives outside this crate. Deferred(scope: browser UI work).
### OQ-05: Browser-opened data channels over WS — v1 cut
- **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**: 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
demultiplexing of channels 1..N), and ADR-048's bidirectionality
promise leans on the same connection-local machinery. The v1
implementation wires channel 0 only (`install_channel_zero` +
`Dispatcher::run_loop_single_stream`, `src/websocket/upgrade.rs`);
no `ChannelCore`/`register_openable`/`ChannelOperations` path exists
for a browser to open a data channel (grep-verified, review-001).
The design is decided (ADR-067: the browser opens data channels
exactly as any channels consumer — nothing new to design); what is
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**: 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; review 007 WS-28 corrected the landed
guard's scope — the handle was retained for microseconds, not the
task's lifetime — and its remediation bound the guard in the
channel-0 task's frame, gated by
`live_connections_visible_mid_session_and_drain_after_teardown`).
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`),
alkhttp review 003 (the drill-down), review 006 (the consequence
review + remediation log)
## Resolved (ported)
Resolutions inherited from the alknet architecture; recorded here for
reference. Full rationale in the alknet mono-repo's open-questions.md
and the cited ADRs.
| OQ (alknet) | Title | Resolution | Where it lives now |
|-------------|-------|------------|--------------------|
| OQ-11 | Handler-level auth resolution observability | Resolved: resolved identity stored on `Connection` via `set_identity` | alkcall core; [http-server.md](http-server.md) §Auth |
| OQ-13 | Operation path format | Resolved: `/{service}/{op}` is the operation path format (gateway bodies carry it; no direct-call surface) | [ADR-036](decisions/036-http-to-call-operation-mapping.md), [ADR-047](decisions/047-remove-direct-call-http-surface.md) |
| OQ-17 | Call protocol client and adapter contract | Resolved: `OperationAdapter` async trait; `to_*` projections | alkcall ADR-022; [ADR-017](decisions/017-call-protocol-client-and-adapter-contract.md) |
| OQ-24 / OQ-26 | Operation error schemas / `AdapterError` variants | Resolved: protocol/operation codes distinct; `HTTP_<status>` prefix; `AdapterError` `#[non_exhaustive]` | alkcall ADR-016; [ADR-023](decisions/023-operation-error-schemas.md) |
| OQ-37 | X.509 outgoing-only / three peer roles | Resolved: browsers are not peers | [ADR-034](decisions/034-outgoing-only-x509-and-three-peer-roles.md) |
| OQ-39 | `to_openapi` published-spec versioning | Resolved: `info.version` semver tracks the gateway endpoint contract | [ADR-045](decisions/045-to-openapi-gateway-spec-versioning.md) |
| OQ-40 | reqwest client config and connection pooling | Resolved: `ClientWithMiddleware` + retry + Retry-After middleware; rebuild-and-swap | [http-adapters.md](http-adapters.md) §HTTP client |
| OQ-12 | TLS identity provisioning | Resolved (alknet): browsers require X.509; provisioning itself is an alknet concern | [ADR-027](decisions/027-tls-identity-redesign-acme-rawkey-decoupling.md); [ADR-069](decisions/069-webtransport-out-of-scope.md) |
Not carried: OQ-38 (WebTransport standalone relay scope) — moot here;
the relay is an alknet concern ([ADR-069](decisions/069-webtransport-out-of-scope.md)).