subc_protocol/session.rs
1//! Session route control wire contract.
2//!
3//! subc has two distinct channel-0 handshakes. Module registration is the
4//! module-to-subc `HELLO`/`HELLO_ACK` handshake that registers the manifest and
5//! liveness. Route bind is the client-to-subc-to-module request/response
6//! handshake that binds one client route to a module route channel.
7//!
8//! Config is forwarded as an ordered, provenance-tagged tier list. subc treats
9//! every config document as opaque text and preserves `tier`, `source`, and
10//! `doc` exactly from the client `route.open` request to the module
11//! `route.bind`; it never parses, merges, partitions, or relabels config in
12//! transit.
13
14use serde::{Deserialize, Serialize};
15
16use crate::{BindIdentity, RouteTarget};
17
18/// One provenance-tagged config tier supplied during route open.
19#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
20pub struct ConfigTier {
21 /// Trust label for this tier.
22 ///
23 /// Known v1 values are `"user"` and `"project"`, but this is intentionally
24 /// an open string so a future tier is a value, not a struct change.
25 ///
26 /// SECURITY INVARIANT: the label is stamped from `source` (the file path
27 /// that was read), never derived from `doc` content. subc preserves labels
28 /// exactly and never relabels them in transit.
29 pub tier: String,
30 /// Absolute path the document was read from, used for provenance and by AFT
31 /// to infer format/JSONC behavior and produce diagnostics.
32 pub source: String,
33 /// Verbatim config-source text.
34 ///
35 /// subc treats this as opaque bytes-as-text and does not interpret, parse,
36 /// merge, or validate it. AFT owns parsing, including JSONC handling.
37 pub doc: String,
38}
39
40/// subc-to-module channel-0 control RPC body.
41#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
42#[serde(tag = "op")]
43pub enum ModuleControlRequest {
44 #[serde(rename = "route.bind")]
45 RouteBind {
46 route_channel: u16,
47 target: RouteTarget,
48 identity: BindIdentity,
49 #[serde(default)]
50 config: Vec<ConfigTier>,
51 },
52}
53
54/// Module-to-subc channel-0 response body.
55#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
56#[serde(tag = "op")]
57pub enum ModuleControlResponse {
58 /// ACK-only success. Rejections use the `FrameType::Error` lane.
59 #[serde(rename = "route.bind")]
60 RouteBindAck {},
61}
62
63/// Module-to-subc channel-0 push body.
64#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
65#[serde(tag = "op")]
66pub enum ModuleControlPush {
67 #[serde(rename = "route.status")]
68 RouteStatus { route_channel: u16, status: String },
69}