- Rewrote em dash prose across the whole tree outside docs/reviews/ (the historical reviews stay verbatim, matching the alktunnels and alktty precedent): src doc comments and inline comments (587), docs/architecture (319), docs/research + sdd_process (484), tests (361), tasks (899), fuzz (28), README/CHANGELOG/Cargo.toml (77), AGENTS.md (85), and the .opencode/agents prompts (109) - Fenced content follows the precedent: comments, ASCII-diagram label separators, and template placeholders rewritten; wire data, JSON/BAST documents, byte diagrams, and transcripts survive verbatim; assert, expect, panic, error-display, and format message literals rewritten as prose; no code, fixture, or test data change - src/rfc1928/LICENSE: the two dashes in alksocks' own provenance header rewritten; the MIT legal text untouched - AGENTS.md adds Project Convention 18: no em dashes in prose; varied restructure, no spaced-hyphen substitutes, fenced prose rule, en dash numeric ranges exempt, docs/reviews/ exempt from the greps - tasks/*.md frontmatter: the name values rewritten by the sweep are now quoted (a raw colon inside an unquoted YAML scalar parsed as null); taskgraph validate reports 37 tasks, no issues Verification: cargo test; cargo clippy --all-targets -D warnings; cargo fmt --check; cargo doc --no-deps; fuzz corpus replay (cargo test --manifest-path fuzz/shared/Cargo.toml); wasm check and clippy for wasm32-unknown-unknown with -D warnings; em dash grep over the repo returns matches only in docs/reviews/ and the bast.md BAST JSON data fence
3.4 KiB
3.4 KiB
ADR-001: ALPN, Open Op, and Trivial Params
Status
Accepted (2026-09-20, Phase 1)
Context
The crate rides alkcall channels: a produced SOCKS5 resource is an
openable ALPN-op, opened by consumers via ChannelClient (alkcall
ADR-037/043). The ALPN string is wire-stable once published
(AGENTS.md conventions 5/16: decide via ADR before the first
consumer). Phase 0's POCs (#1, #2, #5) all ran one ALPN
(alk/socks5), one open op (channels/socks5/sub), with trivially
empty params, the natural reading of "the RFC conversation is the
data plane": the SOCKS5 target is unknown at open time (it arrives
in-stream post-negotiation), so there is nothing for params to carry
(poc-connect-wasm-findings.md §Wire/API notes).
Decision
- ALPN:
alk/socks5(provisional → stable on first publish; the alk/ prefix per the alkcall ADR-004 ALPN-string convention; AGENTS.md convention 16's "ADR-004/ADR-006" shorthand cites the naming family, of which ADR-004 is the operative one). One ALPN per protocol. - One open op:
channels/socks5/sub: the SOCKS5 session op, flavor-form like alktunnels' (…/sub; alkcall ADR-047: openable ALPNs are operations). All three RFC 1928 commands (CONNECT, BIND, UDP ASSOCIATE) ride this one op, selected in-stream at command dispatch (the command is an RFC-1928 wire fact, not a wire-format choice of ours). - Params: the trivial object
{}(schema{type: object}, additionalProperties false). Nothing else is needed at open time (the establisher is a session gate, not a dial; the target is unknown). Extensibility: if a later need surfaces per-session options (e.g. a requested local bind hint), that is an additive params schema change while no params were ever required; consumers that send{}stay valid. Params are a self-contained JSON object identifying the produced resource (alkcall ADR-039's shape, following alktunnels ADR-001's template). - Reply:
{"channel_id": <u32>}: the Sub-typed operation reply, as with alktunnels. No extra reply fields in v1 (the establishment phase is a session gate and has nothing to project; the alkcall 0.8.0with_reply_fieldseam remains available additively if a future need appears).
Consequences
- The wire surface is minimal and stable: one ALPN + one op + empty params + one reply field. The one-way-door surface is the ALPN string, the op id, and the (trivial) params shape, all frozen at first publish.
- Command-level differentiation (CONNECT vs ASSOCIATE vs BIND) lives in the RFC 1928 stream and in the ACL scope check at command dispatch (see ADR-006), not in the op set. No per-command ops: that would re-encode the RFC's own command byte in our wire format for no benefit.
- POC-validated: all three POCs served CONNECT/ASSOCIATE/BIND on
the same registration (
connect_still_served_on_the_same_ registration, POC #2; test 7, POC #5).
References
- OQ-SK-01 (params context), OQ-SK-03 (the handle swap, why no correlation params), OQ-SK-08 (BIND rides the same op)
- POC #1
poc-connect-wasm-findings.md(the trivial-params finding), POC #2poc-udp-associate-findings.md(one-op regression guard), POC #5poc-bind-findings.md(one-registration-three-commands) - Upstream: alkcall ADR-037 (channel open ops), ADR-039 (params is ALPN-specific), ADR-047 (flavor-form op ids)
- Sibling template: alktunnels ADR-001/ADR-002