Unit 10: honest stubs, substrate mode docs, spec-doc renumbering

- C-10: channel/control returns channel:control_not_implemented (OQ-39)
- C-11: channel/resources/subscribe returns channel:resources_not_implemented (OQ-40)
- C-14: adapter.rs doc comments accurately describe in-line-only substrate
  mode; QUIC-native multi-stream deferred to alknet (OQ-41)
- C-15: ChannelClient code already clean (stale open_channel_stream ref
  removed in prior unit); no code changes needed
- C-26: spec docs updated to post-047 model (per-ALPN open ops, no
  ChannelDirection, no ResourceEntry.access); stale alknet ADR refs
  (071/075/076/078/079/080/093/094) renumbered to alkcall equivalents
  (034/035/039/040/041/042/043)
- OQs 39-41 filed in open-questions.md

Verification: cargo test (483 passed), cargo clippy (clean),
cargo fmt (clean), cargo doc (no warnings)
This commit is contained in:
deepseek-v4-pro committed 2026-08-14 07:05:46 +00:00
1 parent 49e01c1ff4
commit 6c5aa0c8e1
6 files changed
+163 -153

No files matched your search

+54 -54
View File
@@ -48,56 +48,55 @@ impl ChannelClient {
pub async fn from_connection(connection: Connection)
-> Result<Self, ChannelError>;
/// Open a data channel with the given ALPN and params. Sends
/// `channel/open` on channel 0, waits for the response, and returns
/// the channel.
/// Call a per-ALPN open op (`channels/<alpn>/sub` or
/// `channels/<alpn>/pub`) on channel 0. Returns the
/// `ResponseEnvelope` (which carries `channel_id` on success).
/// In single-stream call mode (ADR-036 amendment), this writes
/// `call.requested` through channel 0's shared frame writer and
/// awaits the response via the `PendingRequestMap`.
pub async fn call_open_op(&self, operation_id: &str, input: Value)
-> ResponseEnvelope;
/// Open a data channel by calling the per-ALPN open op on channel 0
/// and adopting the resulting `channel_id` (ADR-047 §5 odd/even
/// split). The connect side calls the open op; the accept side
/// allocates the `channel_id` (even). The connect side then adopts
/// the `channel_id` via `ChannelManager::adopt_channel` to install
/// local routing state.
///
/// Returns the `channel_id`, the `MpscSendStream` (write half), and
/// the `MpscRecvStream` (read half). The caller can build a
/// `Connection` from these via `channel_source` and
/// `Connection::from_source`.
pub async fn open_channel(
&self,
operation_id: &str,
input: Value,
alpn: &str,
params: Value,
direction: ChannelDirection,
) -> Result<Channel, ChannelError>;
) -> Result<(u32, MpscSendStream, MpscRecvStream), String>;
/// Subscribe to the peer's resource updates. Returns a stream of
/// resource-set events (ADR-037 channel/resources/subscribe). Each
/// event carries the JSON `output.resources` array from ADR-037's
/// `channel/resources/subscribe` response shape.
pub async fn subscribe_resources(&self)
-> Result<BoxStream<ResourceEvent>, ChannelError>;
/// The call-protocol connection on channel 0, for invoking channel
/// lifecycle operations and any other call ops the peer exposes.
pub fn call(&self) -> &CallConnection;
}
pub enum ChannelDirection {
InitiatorToResponder,
ResponderToInitiator,
}
pub struct Channel {
pub channel_id: u32,
/// The channel's BiStream, accessible via the BidiStreamSource
/// (accept_bi — ADR-038 as amended by ADR-035).
pub source: ChannelBidiStreamSource,
}
/// One event from `channel/resources/subscribe`. Wraps the JSON `output`
/// object from ADR-037's subscribe response — the `resources` array
/// describing what ALPNs the peer exposes and with what `access` preview.
/// The channels crate maps the JSON to this typed struct; the fields mirror
/// ADR-037's response shape.
pub struct ResourceEvent {
pub resources: Vec<ResourceEntry>,
}
pub struct ResourceEntry {
pub alpn: String,
pub backends_or_targets: Vec<String>, // ALPN-specific enumeration
pub access: Value, // preview of AccessControl (advisory)
/// Take the `CallConnection` — used by the consumer to register
/// imported ops (`from_call`) on the connection's overlay. After
/// this, `call_open_op` returns an error (the connection is owned
/// by the consumer).
pub async fn take_call_connection(&self) -> Option<CallConnection>;
}
```
### Post-047: per-ALPN open ops, not a generic `channel/open`
ADR-047 dissolved the generic `channel/open` operation into per-ALPN
open ops (`channels/<alpn>/sub`, `channels/<alpn>/pub`). Each ALPN
crate registers its own open op via `ChannelCore::register_openable`
(ADR-047 §3, as amended 2026-08-13 — per-connection registration).
The `ChannelClient` calls these ops by name on channel 0 via
`call_open_op`; `open_channel` wraps `call_open_op` + `adopt_channel`.
The pre-047 `ChannelDirection`, `Channel { channel_id, source }` struct,
and `subscribe_resources` method are deferred (OQ-40, OQ-41). The
`ResourceEntry.access` preview was dropped by ADR-047 §6 — it is
available via `services/schema` on the op spec.
## Transport-agnostic by construction
`ChannelClient` is the client side of the channels protocol. The channels
@@ -131,13 +130,12 @@ an already-established, already-authenticated `Connection`, exactly as
## Bidirectionality preserved
The channels protocol is bidirectional — either side can open a channel
(ADR-037 §direction semantics). `ChannelClient::open_channel` supports both
`ChannelDirection::InitiatorToResponder` and
`ChannelDirection::ResponderToInitiator`. The client is not "the client
side" in the request/response sense — it can also receive `channel/open`
requests from the peer (the peer initiates, the client's `ChannelManager`
responds). This mirrors the call protocol's operation overlay (each side
populates what operations they expose).
(ADR-037 §direction semantics). The connection owner (the side that holds
the `ChannelManager`) allocates `channel_id`s (ADR-047 §5). The connect
side calls per-ALPN open ops on channel 0; the accept side allocates the
`channel_id` and responds. Both sides can initiate — the connect side
calls the open op, the accept side could also call open ops on the
connect side's channel 0 (if the connect side registers any).
`ChannelClient` is one endpoint of a bidirectional channels connection. The
name follows the `CallClient` convention (the side that dialed), not a
@@ -167,24 +165,26 @@ All design decisions are documented as ADRs in [decisions/](decisions/).
| ADR | Decision | Summary |
|-----|----------|---------|
| [080](decisions/080-channelclient.md) | ChannelClient | Client side; transport-agnostic `from_connection` primary; dial lives in `AlknetClient` (ADR-045, resolves OQ-55) |
| [093](decisions/093-channels-pure-channel-multiplexing.md) | channels Pure Channel Multiplexing | No `stream_types` on `open_channel`/`Channel`; handler owns sub-stream multiplexing |
| [043](decisions/043-channelclient.md) | ChannelClient | Client side; transport-agnostic `from_connection` primary; dial lives in `AlknetClient` (ADR-045, resolves OQ-55) |
| [035](decisions/035-channels-pure-channel-multiplexing.md) | channels Pure Channel Multiplexing | No `stream_types` on `open_channel`/`Channel`; handler owns sub-stream multiplexing |
## Open Questions
- **OQ-55** (resolved by ADR-045): `AlknetClient` core **dial+TLS seam**
— `alknet-client` with three dial methods. `ChannelClient`'s API is
transport-agnostic (`from_connection`); the dial is the shared seam.
See [ADR-045](decisions/089-alknetclient-native-dial-seam.md).
See [ADR-045](decisions/045-alknetclient-native-dial-seam.md).
## References
- ADR-043: ChannelClient (the decision)
- ADR-035: channels pure channel multiplexing (no `stream_types`)
- ADR-037: channel lifecycle operations (`open_channel` sends `channel/open`)
- ADR-037: channel lifecycle operations (`open_channel` sends per-ALPN open ops)
- ADR-038: ChannelBidiStreamSource (what `Channel.source` wraps, as
amended by ADR-035 — `accept_bi` yields a `BiStream`)
- ADR-039: ChannelManager (the shared state `ChannelClient` holds)
- ADR-047: openable ALPNs are operations (per-ALPN open ops dissolve
the generic `channel/open`)
- OQ-55: AlknetClient / client establishment extraction
- `docs/architecture/crates/call/client-and-adapters.md` — `CallClient` (the
shape `ChannelClient` mirrors)