# 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: 1. **The crate's own local backends** (dial/listen/egress providers touching real sockets, ADR-008's local variants). 2. **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](../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 `net` feature**: 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 `-D` local exposure; the producer's local backend). Brings `tokio/net` + `socket2` into 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 = false`** with the wasm-clean subset (`rt`, `sync`, `io-util`, `macros`, `time`); **never `features = ["full"]`** (AGENTS.md convention 4); `net`-shaped additions ride `local` alone. ## 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 legacy `Socks5Server`/`Incoming` API, `Socks5Datagram`'s kernel path, the DNS-resolve helper, the net-only tests), the `socks4` module, and the legacy `Config`/`Authentication` layer 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; brings `tokio/net` + `socket2` into the graph itself) and **`composed`** (the alktunnels providers). `local` no longer implies a separate `net` feature; 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-unknown` and native `--no-default-features` both 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_reply` publication) 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-party `local` module. ## 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's `local` feature (the posture precedent), alktunnels ADR-004 + overview.md (the same feature split)