Files
alkhttp/docs/architecture/open-questions.md
T
glm-5.3-flash df86f89440 docs(review 003): land the Unit-1 re-point; extend it to alkcall review 005 + 0.3.0
Commits the re-point edits left uncommitted in the working tree
(5b62307's follow-through; alkcall review 005 verified these lines at
that tree), updated to the post-review-005 state:

- ADR-048 reconciliation note gains the 2026-09-04 update: alkcall
  review 005 remediated the landed mechanisms (serving-loop
  concurrency G-01/G-02, op/register collision policy G-03, spec
  round-trip G-04, bootstrap-list alignment G-05) and alkcall 0.3.0
  shipped them; alkhttp now consumes 0.3. The ADR-022 collision
  sub-amendment binds here: a peer-announced op never shadows the
  serving side's own registrations — the WS session's op/register
  handler gates on the session fork.
- OQ-05 resolution gains the same dated update and extends the
  cross-references to alkcall reviews 004-005.

What remains here is still alkhttp-side wiring only (review 003
Unit 2).
2026-09-04 14:55:23 +00:00

137 lines
8.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**: deferred(scope: v1 cut — no browser consumer yet; reopened
when one lands)
- **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**: (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.)
- **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`)
## 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)).