The spec docs had not caught up with the stub-sweep fix commits (4eae18f..3317ea0), and the ported docs still carried alknet numbering that now collides with alkcall's own ADR range. Spec sync with the landed code: - call-protocol.md: register_imported/register_imported_all return Result and refuse marked specs; marked-spec registration refusal contract spelled out (ADR-047 am. 4 §4.8, ADR-022 am. 2026-10-13) - client-and-adapters.md: from_call flow gains the Pub sink-forwarding branch and the marked-op refusal (resolves OQ-37 — no from_call relay wrapper; sanctioned compositions are ChannelRelay::register_relay_openable / ChannelClient) - ADR-051: "channel/control is not implemented" stale sentence replaced with the ADR-052 per-leg control contract - OQ-37 resolved; OQ-22 split (primitive resolved; broker placement out of scope) with new OQ-42 for the downstream hub broker (deferred(scope), concretely blocked); OQ-24 resolved by the shipped add/strip surface; OQ-41 → deferred(scope) with blocking condition - README: OQ bullets renumbered to tracker IDs; alknet-collision note rewritten (range 001..053, alknet prefix convention); new principle 11 (implement-or-stop-advertising); AGENTS.md ADR range 001..053 Port-debt repair: - 149 broken decision links across 17 docs — ported with alknet numbers/paths, most now remapped to alkcall files by slug; the rest link the alknet repo per the README convention - stale OQ numbering rewritten to tracker IDs in call-protocol.md, call-README.md, operation-registry.md, client-and-adapters.md, ADR-025, channels-overview/README/wire, channel-client - unambiguous "alknet ADR-NNN" labels where an alknet number collides with an alkcall ADR (052 TTY vs channel/control, 033 storage vs rust-canonical, 025/026/027+020 vault vs PeerEntry/auth ADRs) Verified: cargo test (697 + guard), fmt, clippy --all-targets -D warnings; full markdown link scan clean.
11 KiB
status, last_updated
| status | last_updated |
|---|---|
| current | 2026-10-13 |
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 |
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 an alknet-hub composition on top of 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. |
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 alknet-endpoint, not channels. Named to stop the re-tangle |
| 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 alknet's QUIC accept loop. Blocked on: alknet's multi-stream substrate integration. 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 |