The ported docs still framed alknet siblings (alknet-core/-call/-channels/
-http/-tls/-client) as live load-bearing context of this crate. With the
extraction complete and alknet headed for glue-level replacement, the docs
now speak as alkcall and cite the real sibling crates (alkhttp, alktls,
alktty, alktunnels, alktrader).
- ADR-054 (new): re-own the verifier-selection rule in-crate — three
remote roles (public X.509 endpoint / transport relay / hub),
ServerCertVerifier by PeerEntry presence, RemoteIdentity None
load-bearing. Provenance: alknet ADR-034 (never ported), demoted to
footnote. Resolves OQ-21's cross-repo authority gap.
- OQ-43 (new, deferred(scope)): composition-layer ownership and shape
after the alknet replacement — the named receiver for the
downstream-side deferrals (OQ-33 endpoint layer, OQ-41 QUIC-native
substrate, OQ-42 hub broker, OQ-19 persistence adapters, ADR-045 dial
seam). README layering diagram redrawn with the composition layer as
TBD-ownership instead of "alknet / alknode" in concrete.
- Spec docs reframed: titles, self-references, dial/TLS/from_jsonschema
homes, malformed legacy cite rows removed; dead relative research
paths qualified as source-repo paths.
- ADR amendments (append-only): 027 (alknet-http -> alkhttp), 031 (post-
extraction state), 044 (split landed as modules in alkcall), 045
(name normalization; citation-space note).
- Citation hygiene: unprefixed/colliding source-repo cites prefixed
("alknet ADR-NNN (provenance)") across 009/011/022/034/035/038/040/
043/044/045; stale OQ cites corrected (session registries OQ-04, batch
semantics OQ-03, verifier rule ADR-054); stale anchors fixed.
- README provenance note consolidated; citation conventions documented.
Verification: markdown link check (all local links resolve, all in-crate
ADR cites point at existing decisions/ files); table integrity check
(uniform row widths across open-questions.md and edited tables); residual
alknet-mention sweep (only provenance/historical/intentional framing
remains); architecture review subagent pass with zero remaining criticals.
Docs-only change — no code paths touched.
14 KiB
status, last_updated
| status | last_updated |
|---|---|
| current | 2026-10-13 (composition-layer re-key) |
Open Questions
Open questions are tracked here, organized by theme. Each question has a status, priority, and (when resolved) a resolution citing the ADR.
Status values: open, resolved, deferred(scope), deferred(unclear),
partially resolved, dissolved.
Call Protocol
| OQ | Title | Status | Priority | Resolution |
|---|---|---|---|---|
| OQ-01 | Call protocol scope within a connection | resolved | medium | ADR-015 — stream model, multiplexing |
| OQ-02 | Operation path format and routing scope | resolved | medium | /{service}/{op} is the correct design |
| OQ-03 | Batch operation semantics | resolved | low | Correlated call.requested events |
| OQ-04 | Session-scoped operation registries | resolved | medium | ADR-019 — OperationEnv trait layering |
| OQ-05 | Abort cascade semantics for nested calls | resolved | high | ADR-020 |
| OQ-06 | Privilege model and authority context | resolved | high | ADR-017 |
| OQ-07 | Handler identity registration path and composition authority | resolved | high | ADR-018 |
| OQ-08 | Operation error schemas | resolved | high | ADR-016 |
| OQ-09 | Safe vault operations for call protocol exposure | resolved | high | ADR-010 — none exposed |
| OQ-10 | dissolved | medium | ADR-024 — remote_safe/trusted_peer retired | |
| OQ-11 | OperationAdapter error type (AdapterError variants) | resolved | medium | DiscoveryFailed, SchemaParse, Transport, Unauthorized, SamePeerCollision |
| OQ-12 | from_call re-import trigger | resolved | low | ADR-028 — manual free function |
| OQ-13 | from_call namespace collision | resolved | low | Same-peer = error; cross-peer dissolved (ADR-024) |
| OQ-14 | CallClient TLS client-auth | resolved | high | quinn client-auth; key-type-aware verification |
| OQ-15 | PeerRef::Any routing policy | resolved | low | Insertion-order first-match |
| OQ-16 | services/list-peers re-export semantics | resolved | low | Opt-in; services/list is own-ops-only |
| OQ-17 | Multi-hop federation | deferred(scope) | low | One-hop model is the commitment; multi-hop is a feature extension |
| OQ-18 | PeerId — crypto identity vs stable logical id | resolved | high | ADR-025 — PeerId = Identity.id (stable) |
| OQ-19 | Persistent peer registry | resolved | medium | ADR-025 — core trait + in-memory default; persistence adapters separate |
| OQ-20 | dissolved | medium | PeerEntry supports multiple credential paths | |
| OQ-21 | X.509 outgoing-only case | resolved | medium | Three remote roles; PeerEntry asymmetry correct. Re-owned in-crate by ADR-054 — the verifier-selection rule that binds alkcall's surface (RemoteIdentity: None semantics, ServerCertVerifier by PeerEntry presence) is decided here, not by the un-ported source ADR (which is demoted to provenance). |
Call Protocol — Pub/Sub
| OQ | Title | Status | Priority | Resolution |
|---|---|---|---|---|
| OQ-22 | Call protocol pub/sub primitive — pub to go with sub | resolved | high | The question had two halves, both now decided. (1) The primitive: ADR-046 delivers OperationType::Pub + HandlerKind::Sink + call.published wire event + invoke_sink() dispatch + CallConnection::publish(). (2) Placement of the fan-out/broker: out of scope for alkcall — the call protocol is point-to-point; a topic registry that outlives individual calls is a routing concern that sits above it. The hub composes the broker on top of the Pub/Sub primitives (ADR-047 §"What this ADR decides" Gap B). The broker design itself is tracked as OQ-42. See §"Pub/Sub Gap" below. |
| OQ-42 | Hub message broker (topic registry, Pub↔Sub matching, N-consumer fan-out) |
deferred(scope) | medium | Deferred downstream: the broker is a hub composition layering on alkcall's Pub/Sub primitives, not an alkcall deliverable (OQ-22 placement resolution, ADR-047 Gap B). Blocked on: a concrete producing crate committing to fan-out — a spec that requires one produced topic with N independent spoke subscribers (plausible first candidate: alktrader market-data distribution; ADR-046 §fan-out records the consumer-blind rationale). Not circular — the primitives it composes on are delivered and load-bearing (ADR-046), and no alkcall API surface advertises or depends on the broker. The hub itself lives in the composition layer (owner — OQ-43). |
Pub/Sub Gap
The call protocol's StreamingHandler / invoke_streaming() path
(ADR-021) is point-to-point: a call.requested arrives, the handler
produces a stream of call.responded events back to that one caller.
There was no mechanism for a producer to stream data to a responder
(producer→consumer streaming), and no fan-out (one producer, N consumers).
ADR-046 resolves the directional gap: OperationType::Pub is the
producer→consumer streaming complement to Sub (was Subscription,
renamed for symmetry). HandlerKind::Sink is the consuming handler
type. call.published is the wire event carrying stream chunks.
invoke_sink() is the dispatch path. CallConnection::publish() is
the client method. The Subscription variant is renamed to Sub
(wire string "sub").
Placement decided: the broker is not an alkcall deliverable. The
fan-out/broker mechanism (topic registry, Pub↔Sub matching,
N-consumer fan-out) sits above the call protocol: the call protocol is
point-to-point (one initiator, one responder, a stream between them);
a topic registry that outlives individual calls is a different
lifecycle and a different concern. The broker is a hub composition on
top of the Pub/Sub primitives — ADR-047 §"What this ADR decides"
(Gap B) places it out of scope for alkcall. The Pub primitive is the
load-bearing piece the broker composes on (delivered, ADR-046); ADR-053
served the broker's originally-named first consumer
(channel/resources/subscribe) with enumerators instead.
The broker design is downstream work (OQ-42, deferred(scope)). It unblocks when a concrete producing crate commits to fan-out. The original deferral's rationale (ADR-046 §fan-out — designing the broker without its first real consumer produces a half-design) still holds: the honest state is a tracked, concretely-blocked deferral, not a pending promise. The "channels session" phrasing in ADR-046 §fan-out should be read as this placement decision (the channels work has since landed; what remains unbuilt is the downstream hub broker).
Channels
| OQ | Title | Status | Priority | Resolution |
|---|---|---|---|---|
| OQ-23 | Full channel-level flow-control windowing | deferred(scope) | low | Bounded-buffer decided (ADR-040); full windowing blocked on HOL-blocking deployment observation |
| OQ-24 | Channels add/strip API shape | resolved | low | Resolved by the shipped surface: the strip is integrated into the read/write path — the demux loop consumes read_header/write_chunk so a handler's BiStream yields payload chunks and never sees the 8-byte header (ADR-035; matches ADR-037's payload-parse contract). The low-level primitives (parse_header/write_header/read_header/write_chunk/write_eof in channels::wire) remain exposed as the standalone utility for tooling/codegen, but no handler-facing add/strip wrapper exists or is needed. |
| OQ-31 | channel/open ACL granularity |
resolved | high | ADR-047 — channel/open dissolves into per-ALPN ops; each op has its own access_control |
| OQ-32 | Quota lifecycle (opener vs closer, transport drop) | resolved | high | ADR-047 §7 — the per-connection opener ledger; decrement on every teardown path, keyed by opener |
| OQ-33 | Per-identity connection cap (endpoint layer) | deferred(scope) | low | Named as a separate layer (ADR-047 §"ALPN category reframe" references the findings); belongs at the endpoint/connect-accept layer of the composition stack, not channels. Named to stop the re-tangle. The endpoint layer's home is the composition layer (owner — OQ-43; today it lives in the alknet glue). |
| OQ-34 | channel_open marker wire format |
resolved | medium | ADR-047 §2 — boolean "channel_open": true in services/schema; ALPN derivable from op name |
| OQ-35 | OperationEnv::channel_manager() coupling |
resolved | high | ADR-047 §4 — extension trait ChannelOperationEnv in channels-call; call crate stays free of channels types |
| OQ-36 | channel_id allocation in Pub case |
resolved | medium | ADR-047 §5 — "connection owner allocates" (the side that holds the ChannelManager); amends "responder allocates" |
| OQ-37 | from_call relay wrapper for marked ops |
resolved | medium | ADR-022 amendment 2026-10-13 — there is no from_call relay wrapper, and there won't be one: marked (channel_open) announcements are refused with MARKED_SPEC_UNSUPPORTED, and register_imported/register_imported_all refuse marked specs (ADR-047 amendment 4 §4.8) — a marked op's data plane (the allocated channel's BiStream) has no overlay path. The sanctioned compositions are named in the refusal: ChannelRelay::register_relay_openable (ADR-051) for a relaying hub, ChannelClient (ADR-043) for direct consumption. from_call's discovery still reconstructs the marker (ADR-047 Gap F) for reporting, but importing a marked spec is refused at the overlay landing. |
| OQ-38 | ALPN→path-segment mapping | resolved | low | ADR-047 §"Negative" — strip the alk/ prefix; ALPNs without that prefix use the full ALPN string (rare, two-way-door) |
| OQ-39 | channel/control control-handle surface |
resolved | medium | ADR-052 — the control-handle surface is implemented: per-channel control callbacks contributed by the ALPN establisher (Establishment::with_control), wrapper-installed and teardown-removed in the manager; the op routes the ALPN-specific message and answers channel:no_control_handle when the channel's ALPN registered none. The stub (channel:control_not_implemented) was removed with the single-publish fix (reviews 010 S-02 / 011). |
| OQ-40 | channel/resources/subscribe live subscription |
resolved | medium | ADR-053 — the live subscription is implemented: one ResourceEnumerator per openable ALPN (provided by the producing crate, snapshot-then-changes), aggregated by the handler over the scan-once snapshot; an empty registry emits one { "resources": [] } seed and stays open. The one-shot error stub was removed with the single-publish fix (reviews 010 S-03 / 011). The alktunnels discovery-UI note (review 006 E-02) is served by the enumerator surface. |
| OQ-41 | QUIC-native multi-stream substrate | deferred(scope) | medium | Deferred downstream — the substrate lives in the dial/accept layer, which alkcall does not own. Only the in-line substrate mode is implemented (single bidi stream, header-demuxed N channels); the QUIC-native multi-stream mode (accept remaining bidi streams, read headers off each — ADR-034 §substrate modes) belongs in the composition layer's QUIC accept loop. Blocked on: the composition layer's multi-stream substrate integration (owner — OQ-43; today the alknet glue, being replaced). Impacts: none in-crate — the wire format and demux loop are correct for both substrates; alkcall stays transport-agnostic (no QUIC dependency, WASM-compatible). |
Core Types
| OQ | Title | Status | Priority | Resolution |
|---|---|---|---|---|
| OQ-25 | BiStream type definition | resolved | high | ADR-005 — trait, Connection parameter |
| OQ-26 | AuthContext resolution timing | resolved | high | ADR-003 — hybrid resolution |
| OQ-27 | ALPN string naming convention | resolved | medium | ADR-004 — alk/ prefix |
| OQ-28 | Dynamic handler registration | resolved | low | ADR-019 — curated static, overlays dynamic |
| OQ-29 | Handler-level auth resolution observability | resolved | medium | set_identity() on Connection for observability |
| OQ-30 | Dynamic resource ownership | resolved | high | ADR-011 — OwnershipProvider, resource_id_path |
Composition Layer
The layer above alkcall that owns dial/accept, hub composition, and
endpoint concerns. As of 2026-10 that layer is the alknet glue (the
alknet mono-repo's crates: its client dial helper AlknetClient, its
endpoint crate, its hub wiring); the mono-repo itself is being replaced
by thin glue over alkcall and its sibling protocol/host crates
(alkhttp, alktty, alktunnels, alktrader, alktls, …). Several deferred
questions name "downstream" as their receiver — this OQ is the named
receiver for all of them, so the deferrals survive the replacement
rather than being repo-pinned to a codebase slated for deletion.
| OQ | Title | Status | Priority | Resolution |
|---|---|---|---|---|
| OQ-43 | Composition-layer ownership and shape after the alknet replacement | deferred(scope) | medium | Deferred scope: who owns dial/accept/hub composition, the endpoint layer (OQ-33), the QUIC-native substrate (OQ-41), and persistence adapters (OQ-19) after the alknet mono-repo is replaced — and whether that composition is one thin glue workspace (an alknode-type crate consuming alkcall + the sibling crates) or several small glue binaries. Blocked on: the glue-workspace decision being committed (the stated direction is "a couple kloc of glue", but the shape — one workspace vs several binaries — and its ownership are not yet committed). Impacts: re-keys the deferrals OQ-33, OQ-41, OQ-42, OQ-19; determines the dial seam's future home (ADR-045's AlknetClient, today in the alknet glue); determines where hub-relay wiring templates are consumed (ADR-042, ADR-051). Not blocking any alkcall v0.9 API surface — alkcall is transport-blind and composition-blind by construction (ADR-031, ADR-035). Cross-references: OQ-33, OQ-41, OQ-42, OQ-19; ADR-045, ADR-031, ADR-042, ADR-051. |