Split the last open substrate-placement question: - Unix: ships with the local feature v1 (dial_unix — same halves shape as TCP; the wire enum already carried unix per ADR-001; the params task's schema list includes all three values) - Stdio: OUT of scope — a spawned process's stdin/stdout/stderr IS alktty's pipe mode (LocalTtyBackend + tokio::process + Stdio::piped, alktty tty-local.md): three multiplexed logical streams + the exit-code control chunk (alktty ADR-004) + signal forwarding (REQ-TTY-02). A stdio bridge here would be alktty's runner mode with the terminal stripped out — a strictly worse duplicate that also drops the semantics that matter (a byte tunnel has neither exit codes nor signals). Remote command execution composes via alktty on the same channels substrate. Updated: open-questions.md OQ-TN-14 (resolved), overview.md feature gate + deps + OQ summary, producer.md OQ ref, OQ-TN-10 promotion (#3 split), phase-0-findings + both POC summaries' resolution notes, params task (schema enum includes unix), local-socket-halves task (unix ships, stdio does NOT — with the composition rationale), oq-tn-14-tracker task repurposed (boundary-maintenance: re-opens only if a consumer needs stdio-without-process-semantics — which would need its own ADR, or if the alktty/alktunnels boundary needs sharpening). Verified: taskgraph valid (12 tasks, no cycles)
3.5 KiB
3.5 KiB
id, name, status, depends_on, scope, risk, impact, level, tags
| id | name | status | depends_on | scope | risk | impact | level | tags | ||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| tunnels/params | TunnelParams + open-op spec (schema, scope gate, constants) | pending |
|
narrow | low | component | implementation |
|
Description
Implement src/params.rs per ADR-001 + wire.md §The Open Op: the
TunnelParams wire type, the Substrate discriminator, and the open-op
OperationSpec builder. This is the wire-stable surface (one-way door) —
exact conformance to the ADR is the point.
Types
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TunnelParams {
pub resource: String,
pub substrate: Substrate,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Substrate { Tcp, Udp, Unix }
deny_unknown_fieldsis the loud-rejection posture (ADR-001: unknown fields fail schema validation, never silently ignored).Substrate::Unixis included in the type AND in the open-op schema's enum list v1 (["tcp", "udp", "unix"]— OQ-TN-14 resolved: unix has an implementation path via thelocalfeature). The schema list is the authoritative gate for newer-substrate negotiation: an older producer rejecting a newer substrate value is the SSH "unknown channel type" posture (loud, not silent).
The open-op spec (in producer.rs or params.rs — put it where
tunnels/producer-open-op can consume; the spec builder lives in
params.rs per the module map, producer.rs re-exports)
pub const OP_TUNNEL_OPEN: &str = "channels/tunnel/sub";
pub const TUNNEL_ALPN: &str = "alk/tunnel";
pub const TUNNEL_OPEN_SCOPE: &str = "tunnel:open";
pub fn tunnel_open_spec() -> OperationSpec
OperationType::Sub;Visibility::External; channel-open markerChannelOpenSpec::new(TUNNEL_ALPN).input_schema:{resource: string (required), substrate: string enum ["tcp","udp","unix"] (required)}— JSON Schema Draft shape as the POCs used (unix in the list per OQ-TN-14's resolution).output_schema:{channel_id: integer > 0}.AccessControl.required_scopes: [TUNNEL_OPEN_SCOPE](ADR-006).description: a one-line human hint (round-trips through discovery; the spec's SHOULD).
Error surface
src/error.rs: TunnelError (thiserror) covering the codec + session
errors (filled incrementally by later tasks); plus the re-export of
alkcall::channels::client::ChannelOpenError and an
establishment_reason(&CallError) -> Option<&str> helper
(ADR-049 §4 surface; the POC consumer's shape).
Acceptance Criteria
TunnelParamsround-trips serde; unknown fields rejectedtunnel_open_spec()matches wire.md §The Open Op exactly (op id, type, ALPN marker, schemas, ACL, description)- Schema validation test: valid params pass; missing fields, unknown fields, unknown substrate values all fail
establishment_reasonmapschannel:open_faileddetails.reason (POC-pinned shapes:unknown_resource,dial_failed,resource_shortage)- Unit tests cover the serde + schema shapes
- wasm32 check passes
References
- docs/architecture/decisions/001-open-params-layout.md
- docs/architecture/wire.md §The Open Op
- docs/architecture/decisions/006-access-control-posture.md
- POC reference:
/workspace/alktunnels-udp-poc/src/params.rs+producer.rs::tunnel_open_spec(the shape, withdeny_unknown_fieldsadded)
Notes
Agent fills during implementation.
Summary
Agent fills this on completion.