- 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
4.9 KiB
ADR-009: Feature-Gate Layout: local and the Composition Boundary
Status
Accepted (2026-09-20, Phase 1; the wasm-clean default-crate invariant
is the alk* family posture, AGENTS.md convention 4). Amended
2026-09-21 (pre-decomposition): the vendor's net gate dissolves
under ADR-011's extraction amendment; the vendor is
wasm-clean by construction; features collapse to local +
composed; see §Amendment.
Context
The default crate must compile to wasm32-unknown-unknown (the
alktty/alktunnels precedent; the wasm shape is a sandboxed
SOCKS5 consumer (pure byte framing, no local sockets needed
client-side; phase-0 OQ-SK-04's analysis). Two groups of
platform-specific or sibling-dependent code need gating:
- The crate's own local backends (dial/listen/egress providers touching real sockets, ADR-008's local variants).
- The composed providers (the alktunnels-composed egress/accept helpers, ADR-008's composed variants), which need the alktunnels dependency.
The vendor originally contributed a third gate: its kernel-net
region was to ride a default-on net feature (POC #4's measured
shape, ~120 cfg lines across 5 files). ADR-011's 2026-09-21
amendment pins the vendor as extraction; the kernel-net region is
not copied, so that gate no longer exists (see §Amendment). POC #4's
gate map survives as the extraction recipe, not as in-tree cfg.
Decision
- The default crate is protocol-only and wasm-clean. Module placement per overview.md: protocol, wire, producer, consumer, vendor modules at the core; backend modules feature-gated, never imported by the protocol layer.
- The default build has no
netfeature: the extracted vendor contains zero kernel-net code, so the wasm-clean subset is the whole crate; there is nothing to gate (ADR-011 §Amendment). local(default-off): the crate's first-party local backends, namely the TCP dial, the UDP egress socket, the BIND listener, and the front doors (the consumer's ssh-Dlocal exposure; the producer's local backend). Bringstokio/net+socket2into the graph. Non-wasm by design (enabling it on wasm is a build error, the alktty posture).composed(default-off): the composed providers over alktunnels 0.2.0 (direct-op egress, bind-first listen accept), the only feature that adds the alktunnels dependency. The protocol layer never references alktunnels types; the composed module does, injected at the assembly layer (ADR-004/ADR-008).- tokio stays
default-features = falsewith the wasm-clean subset (rt,sync,io-util,macros,time); neverfeatures = ["full"](AGENTS.md convention 4);net-shaped additions ridelocalalone.
Amendment (2026-09-21, pre-decomposition: the vendor's net gate dissolves)
The original decision carried a third feature, net
(default-on), the vendored subset's kernel-net gate, with local
implying it. ADR-011's extraction amendment dissolves it:
- The vendor is an extraction of the
T-generic inventory only; the kernel-net region (run_tcp_proxy,run_udp_proxy*, the legacySocks5Server/IncomingAPI,Socks5Datagram's kernel path, the DNS-resolve helper, the net-only tests), thesocks4module, and the legacyConfig/Authenticationlayer are not copied into the tree; the extraction is wasm-clean by construction, with no in-tree cfg gate. - Features collapse to two:
local(first-party socket providers + front doors, ADR-008; bringstokio/net+socket2into the graph itself) andcomposed(the alktunnels providers).localno longer implies a separatenetfeature; it is the sole gate for socket/platform I/O. - POC #4's gate map survives as the extraction recipe (its ungated inventory is what to copy), not as in-tree cfg.
- The wasm verification is a hard gate with no feature toggles:
cargo check --target wasm32-unknown-unknownand native--no-default-featuresboth compile the same complete crate.
Consequences
- Wasm consumers (the sandboxed adapter story; a product input, nothing waits on it) build the default crate clean; the protocol substance is the wasm-relevant surface.
- The verification commands cover the gates:
cargo test(default),cargo test --all-features, and both wasm checks (cargo check/clippy --target wasm32-unknown-unknown), the structural guard for the invariant. - The vendor's carried changes (BIND,
new_replypublication) live in the extracted region where they touch codecs/typestate; nothing vendored is gated; the only feature-gated socket code is the crate's own first-partylocalmodule.
References
- OQ-SK-04 (resolved: the extracted-and-forked base; ADR-011/ ADR-013), OQ-SK-01/03/08 (the providers the features gate)
- POC #4
poc-connect-wasm-findings.md(the measured gate, now the extraction recipe), alktty'slocalfeature (the posture precedent), alktunnels ADR-004 + overview.md (the same feature split)