Files
alktunnels/tasks/tunnels/params.md
T
glm-5.3-flash 3a447273a8 docs: resolve OQ-TN-14 — unix in via local, stdio out (alktty owns process stdio)
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)
2026-09-07 19:44:03 +00:00

102 lines
3.5 KiB
Markdown

---
id: tunnels/params
name: TunnelParams + open-op spec (schema, scope gate, constants)
status: pending
depends_on: [tunnels/crate-init]
scope: narrow
risk: low
impact: component
level: implementation
tags: [wire, params, open-op]
---
## 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
```rust
#[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_fields` is the loud-rejection posture (ADR-001: unknown
fields fail schema validation, never silently ignored).
- `Substrate::Unix` is 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 the `local` feature). 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)
```rust
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 marker
`ChannelOpenSpec::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
- [ ] `TunnelParams` round-trips serde; unknown fields rejected
- [ ] `tunnel_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_reason` maps `channel:open_failed` details.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, with `deny_unknown_fields`
added)
## Notes
> Agent fills during implementation.
## Summary
> Agent fills this on completion.