diff --git a/AGENTS.md b/AGENTS.md index 472a10b..f90b8f3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -90,10 +90,14 @@ implementation agents. (`rt`, `sync`, `io-util`, `macros`, `time`) — **do NOT use `features = ["full"]`** — and keep socket/platform I/O feature-gated. Note: `fast-socks5` uses `tokio::net` and `socket2` unconditionally as - published; the posture is the inline vendor (OQ-SK-04, resolved - 2026-09-20 — convention 17): vendor the `T`-generic subset, gate - native-net pieces behind a default-on `net`-shaped feature. Run - the wasm check whenever a non-backend module changes. + published; the posture is the inline vendor as an **extraction** + (OQ-SK-04, resolved 2026-09-20 — convention 17; extraction pinned + 2026-09-21, ADR-011 §Amendment): extract the `T`-generic subset + only — the kernel-net handlers are not copied, so the vendor is + wasm-clean by construction with no `net`-shaped feature; socket + I/O rides `local` alone. Run the wasm check whenever a non-backend + module changes; it is a hard gate (no dependency-graph failure is + expected — the extraction contains no `tokio::net`). 5. **Wire format is stable** — the SOCKS5 protocol itself is RFC 1928 (fixed); this crate's wire surface is the ALPN + the channel open-op @@ -238,12 +242,14 @@ implementation agents. sweep landed in alkcall 0.8.0 / alktunnels 0.2.0). `fast-socks5` is NOT ours — it is third-party upstream (`/workspace/fast-socks5` is a read-only reference checkout, v1.0.0, MIT). The posture is - the **inline vendor** (OQ-SK-04, resolved 2026-09-20): vendor the - `T`-generic subset into this crate, gated behind a default-on - `net`-shaped feature, and carry the wrapper's needs in-tree (the - wasm gate, BIND, the `run_udp_proxy_custom` bind seam, the - `new_reply` publication). Offering the net-gate upstream as a - courtesy PR stays optional; never wait on it. Keep + the **inline vendor as an extraction** (OQ-SK-04, resolved + 2026-09-20; extraction pinned 2026-09-21, ADR-011 §Amendment): + extract the `T`-generic subset only — the kernel-net handlers and + the `socks4` module are not copied — and carry the wrapper's + needs in-tree (BIND, the `new_reply` publication; the `net` gate + and the `run_udp_proxy_custom` bind seam dissolve with the + kernel-net region). Offering the net-gate upstream as a courtesy + PR stays optional; never wait on it. Keep `/workspace/fast-socks5` for differential testing of RFC edge cases; note the vendor point (v1.0.0) in the vendored code. @@ -264,9 +270,9 @@ cargo publish --dry-run --allow-dirty # before a release The wasm check is the structural guard for the "default crate is wasm-clean" invariant (same as alktty/alktunnels) — run it whenever a -non-backend module changes. Until OQ-SK-04 (fast-socks5 wasm posture) is -resolved, the wasm check may fail on the dependency graph; that failure -is expected and is exactly what the OQ tracks. +non-backend module changes. It is a hard gate: the vendor is an +extraction with no kernel-net code (ADR-011 §Amendment), so no +dependency-graph failure is expected. ## Architecture Context @@ -309,10 +315,11 @@ is expected and is exactly what the OQ tracks. `run_tcp_proxy` / `run_udp_proxy_custom` / `transfer` are the interception points; client side has `Socks5Stream` (generic over the backing socket) and `Socks5Datagram` (UDP associate). The - posture is the inline vendor (OQ-SK-04, resolved 2026-09-20 — - convention 17): the `T`-generic subset is vendored into this - crate behind a `net`-shaped feature, with BIND and the seam fixes - carried in-tree. + posture is the inline vendor as an extraction (OQ-SK-04, resolved + 2026-09-20; extraction pinned 2026-09-21, ADR-011 §Amendment — + convention 17): the `T`-generic subset is extracted into this + crate with no kernel-net code and no `net` feature; BIND and the + `new_reply` publication are the two carried changes. - **alknet's SOCKS5 client** — `/workspace/@alkdev/alknet/crates/alknet-client/src/socks5.rs` (ADR-090): the client-side example need — `Socks5UdpSocket` diff --git a/docs/architecture/README.md b/docs/architecture/README.md index 5341c8a..5ba7489 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -1,7 +1,8 @@ --- status: draft -last_updated: 2026-09-20 (Phase 1 initial draft — the OQ-SK ledger -promoted into ADRs 001-012 and open-questions.md) +last_updated: 2026-09-21 (the vendor extraction amendment — ADR-011 +§Amendment, ADR-009 §Amendment; Phase 1 initial draft 2026-09-20 — +the OQ-SK ledger promoted into ADRs 001-012 and open-questions.md) --- # alksocks — Architecture @@ -34,7 +35,7 @@ decomposition phase. | [wire.md](wire.md) | draft | The wire format: the open op (trivial params — ADR-001), the phase model, the data planes (CONNECT pass-through / ASSOCIATE frames / BIND phases), sentinels | | [producer.md](producer.md) | draft | The producer half: the session-gate establisher, command dispatch, the three seams (dial/egress/accept), scope gates, the local backend | | [consumer.md](consumer.md) | draft | The consumer half: the channels-native sessions (connect/associate/bind), the front doors, door auth (ADR-005), teardown ownership | -| [vendor.md](vendor.md) | draft | The inline vendor: the vendored fast-socks5 subset's scope, the four carried changes, the maintenance posture | +| [vendor.md](vendor.md) | draft | The inline vendor: the extracted fast-socks5 subset's scope (extraction, not wholesale copy), the two carried changes, the maintenance posture | | [bast.md](bast.md) | draft | The BAST document for the ASSOCIATE datagram frame (ADR-003); pass-through stages have no binary framing to describe | | [open-questions.md](open-questions.md) | draft | Centralized OQ tracker (OQ-SK-01..09 promoted; new questions as OQ-SK2-06.. — the SK2 numbering is not contiguous from 01, working-draft numbers were consumed) | @@ -50,9 +51,9 @@ decomposition phase. | [006](decisions/006-access-control.md) | Access-Control Posture — the Open Gate Plus the Command Gate | Accepted | | [007](decisions/007-bind-in-base.md) | BIND in the Base Crate — the Phase Model Extended | Accepted | | [008](decisions/008-provider-defaults.md) | Egress/Accept Provider Defaults — Local Socket and Composed (Direct Op) | Accepted | -| [009](decisions/009-feature-gates.md) | Feature-Gate Layout — `net`, `local`, and the Composition Boundary | Accepted | +| [009](decisions/009-feature-gates.md) | Feature-Gate Layout — `local` and the Composition Boundary | Accepted (amended 2026-09-21) | | [010](decisions/010-channel-capacity.md) | Channel Capacity — Proxy-Workload Recommendation, Not a Wire Change | Accepted | -| [011](decisions/011-inline-vendor.md) | the Inline Vendor — fast-socks5's `T`-Generic Subset, In-Tree | Accepted | +| [011](decisions/011-inline-vendor.md) | the Inline Vendor — fast-socks5's `T`-Generic Subset, In-Tree | Accepted (amended 2026-09-21) | | [012](decisions/012-target-policy.md) | Target Policy and the Virtual-Subnet Translation Layer | Accepted | Upstream ADRs (alkcall/alktunnels/alknet) are referenced by their own @@ -90,14 +91,15 @@ format, `pump_bidi`, identity seam, the channel caps). convention holds for all three commands; the proxy-workload cap posture is ADR-010 (config, not wire). 7. **Wasm-clean default crate** (ADR-009): the default crate is - protocol-only; the vendored subset rides the default-on `net` - gate (ADR-011); `local` is opt-in and non-wasm; `composed` rides - alktunnels' wasm-clean default (verified with the wasm check at - implementation). + protocol-only; the vendor is an extraction with zero kernel-net + code — there is no `net` feature (ADR-011 §Amendment); `local` is + opt-in and non-wasm; `composed` rides alktunnels' wasm-clean + default (verified with the wasm check at implementation). 8. **The vendor is first-class** (ADR-011): the `T`-generic subset - in-tree with the four carried changes; `/workspace/fast-socks5` - stays the differential-testing reference; nothing waits on - upstream. + extracted in-tree with two carried changes (BIND, `new_reply`); + `/workspace/fast-socks5` stays the differential-testing reference + and the only place the full upstream surface (the kernel-net + region) exists; nothing waits on upstream. ## Document Lifecycle diff --git a/docs/architecture/decisions/002-protocol-base.md b/docs/architecture/decisions/002-protocol-base.md index 917ab4e..4a2dc5c 100644 --- a/docs/architecture/decisions/002-protocol-base.md +++ b/docs/architecture/decisions/002-protocol-base.md @@ -30,10 +30,11 @@ functionally complete (a full RFC 1928 CONNECT conversation passes `Socks5Server`/`Socks5Socket`/`Incoming` bind-based API is deprecated upstream and is out — never vendored into the default path. -- **Base = v1.0.0, inline-vendored** (see ADR-011 for the vendor - mechanics and the four carried changes). `/workspace/fast-socks5` - remains the read-only reference for differential testing of RFC - edge cases; the vendor point is noted in the vendored code. +- **Base = v1.0.0, inline-vendored as an extraction** (see ADR-011 + for the vendor mechanics and the two carried changes). + `/workspace/fast-socks5` remains the read-only reference for + differential testing of RFC edge cases; the vendor point is noted + in the vendored code. - **Refusals map faithfully per RFC 1928** — `ReplyError` codes (`as_u8`/`from_u8`) are the error vocabulary at the command plane; refusals are never collapsed into generic errors (AGENTS.md @@ -41,9 +42,8 @@ functionally complete (a full RFC 1928 CONNECT conversation passes ## Consequences -- The crate owns its protocol code in-tree (the vendor), so the - wasm gate, BIND, and the seam fixes ride the same tree — no - upstream waits. +- The crate owns its protocol code in-tree (the vendor), so BIND and + the `new_reply` publication ride the same tree — no upstream waits. - The typestate's interception points are the layering seams: command-read (the dial/accept dispatch), `transfer` (the raw two-pump), and — where the default handlers are unusable (UDP diff --git a/docs/architecture/decisions/009-feature-gates.md b/docs/architecture/decisions/009-feature-gates.md index cddb1ac..67d1ec0 100644 --- a/docs/architecture/decisions/009-feature-gates.md +++ b/docs/architecture/decisions/009-feature-gates.md @@ -1,35 +1,34 @@ -# ADR-009: Feature-Gate Layout — `net` (the Vendor's Gate), `local`, and the Composition Boundary +# 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) +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). Three groups of +client-side; phase-0 OQ-SK-04's analysis). Two groups of platform-specific or sibling-dependent code need gating: -1. **The vendored fast-socks5 subset's kernel-net touches** — POC #4 - measured the gate at ~120 cfg lines across 5 files, keyed on one - feature (`net = ["tokio/net", "dep:socket2", "dep:tokio-stream"]`, - default-on for native; wasm users build with - `default-features = false`). -2. **The crate's own local backends** (dial/listen/egress providers +1. **The crate's own local backends** (dial/listen/egress providers touching real sockets — ADR-008's local variants). -3. **The composed providers** (the alktunnels-composed egress/accept +2. **The composed providers** (the alktunnels-composed egress/accept helpers — ADR-008's composed variants), which need the alktunnels dependency. -One design constraint from OQ-SK-04's resolution: the vendored -subset's `net` gate and the crate's own backend gate are -*mechanically the same boundary* (tokio::net + socket2), but their -*ownership* differs — the vendor's gate ships with the vendored -code (v1.0.0-faithful + carried changes), the crate's local backends -are first-party code. +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 @@ -37,15 +36,15 @@ are first-party code. 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. -- **`net` (default-on)**: the vendored subset's kernel-net gate - (POC #4's shape, carried into the vendor). Turning it off yields - the wasm-clean functional protocol subset (a full RFC 1928 - conversation passes — POC #4's verification). +- **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 — 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). Implies `net`. Non-wasm by design - (enabling it on wasm is a build error, the alktty posture). + 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 @@ -53,8 +52,32 @@ are first-party code. 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` and - `process`-shaped additions ride the features above. + `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 @@ -65,17 +88,16 @@ are first-party code. `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, the `run_udp_proxy_custom` - bind seam, `new_reply` publication) live inside the `net`-gated - region where they touch kernel sockets and in the ungated - `T`-generic region where they don't (the BIND typestate driving - is `T`-generic; only the local-socket accept variant is - `net`-gated). +- 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: inline vendor — see ADR-011), OQ-SK-01/03/08 (the providers the features gate) -- POC #4 `poc-connect-wasm-findings.md` (the measured 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 three-way split) \ No newline at end of file + ADR-004 + overview.md (the same feature split) \ No newline at end of file diff --git a/docs/architecture/decisions/011-inline-vendor.md b/docs/architecture/decisions/011-inline-vendor.md index 500d9bd..cd1589a 100644 --- a/docs/architecture/decisions/011-inline-vendor.md +++ b/docs/architecture/decisions/011-inline-vendor.md @@ -3,7 +3,9 @@ ## Status Accepted (2026-09-20, Phase 1; OQ-SK-04's resolution — the ownership -premise corrected the same day) +premise corrected the same day). Amended 2026-09-21 (pre-decomposition): +the vendor scope is pinned as **extraction** — the kernel-net handlers +are not copied; see §Amendment. ## Context @@ -35,18 +37,21 @@ Two facts settled the posture: the ownership premise was wrong (no cheap "file asks / PR" path), and the carried needs (2–4) exist regardless of the wasm question — so the vendor pays for itself without leaning on the adapter story. The change set is exactly the -shape POC #4 measured as minimal. +shape POC #4 measured as minimal. (Need 1 later dissolves — +§Amendment; needs 3's handler is not extracted with it.) ## Decision -- **Vendor the `T`-generic subset into this crate** (the codecs, the - typestate machinery, the client `use_stream` path — the parts - already generic over `T: AsyncRead + AsyncWrite + Unpin`), gated - behind the default-on `net` feature (ADR-009; POC #4's gate - shape). +- **Extract the `T`-generic subset into this crate** (see §Amendment + for the mechanical reading of "extract"): the codecs, the typestate + machinery, the client `use_stream` path — the parts already generic + over `T: AsyncRead + AsyncWrite + Unpin`. The extraction contains + zero kernel-net code and is wasm-clean by construction. - **Carry the four needs in the same vendor**: the net gate, BIND (the typestate-driven shape, ADR-007), the `run_udp_proxy_custom` - seam fix, and the `new_reply` publication. + seam fix, and the `new_reply` publication. (Post-Amendment: the + net gate dissolves — see §Amendment; BIND and `new_reply` are the + two that touch extracted code.) - **Note the vendor point (v1.0.0) in the vendored code**; keep the MIT license obligations (upstream is MIT; preserve the license header per file or a bundled notice). @@ -63,12 +68,84 @@ shape POC #4 measured as minimal. - The crate owns its protocol code in-tree: no upstream release cadence, no feature waits, and the vendored code co-evolves with the wrapper (the carried changes are first-class, not patches). -- The cost is maintenance of the vendored subset (~4k LoC upstream; - the vendored subset is the smaller `T`-generic region + codecs). - The vendor's diff vs upstream is deliberate and bounded: the four - carried changes + the license/provenance notes. +- The cost is maintenance of the extracted subset (the `T`-generic + region + codecs — a fraction of upstream's ~4k LoC; POC #4's + ungated inventory is the shopping list). The diff vs upstream is + deliberate and bounded: the extraction cut + the carried changes + + the license/provenance notes. +- **Nothing in the crate routes through the kernel-net handlers**; + if a future need surfaces (e.g. a standalone vanilla-server + example), the fix is re-vendor that piece then, as an additive + decision. - Differential testing against `/workspace/fast-socks5` guards the - RFC edge cases the vendored code must keep passing. + RFC edge cases the extracted code must keep passing. + +## Amendment (2026-09-21, pre-decomposition — "extract" pinned, the `net` gate dissolves) + +The decision's wording ("vendor the `T`-generic subset") supported +two mechanical readings; this amendment pins the intent so the +decomposition task is unambiguous: + +- **Extraction, not wholesale-copy-plus-gate.** Copy *only* the + `T`-generic inventory into `src/vendor/`; the kernel-net handlers + (`run_tcp_proxy`, `run_udp_proxy*`, `udp_bind_random_port`, the + legacy `Socks5Server`/`Incoming` API, `Socks5Datagram`'s kernel + socket path, the DNS-resolve helper, the net-only tests), the + `socks4` module (upstream's separate default-off `socks4` cargo + feature, which POC #4 never compiled; out of this crate's RFC 1928 + scope), and the legacy `Config`/`Authentication` auth layer + (ungated upstream, but consumed only by the cut legacy/net region) + are **not copied into the crate**; they remain available in + `/workspace/fast-socks5`, the differential-testing reference. + The kernel-net region is carried only as the cfg *map* (POC #4's + five-file inventory), recorded in `vendor.md` so a future + re-vendor knows the cut. +- **Why**: convention 17's letter ("vendor the `T`-generic subset"); + no crate consumer routes through the kernel-net region (the + producer/consumer/doors drive the typestate and the pure codecs; + the local backends are first-party tokio code — ADR-004/ADR-008); + and the BIND + `new_reply` needs touch only the extracted region + (BIND's driving is wrapper-side code per POC #5 — "zero upstream + ask for BIND itself"). +- **The `net` feature gate dissolves.** With no kernel-net code + in-tree, the extraction is wasm-clean by construction — no + `#[cfg]` gate needed inside the vendored files. Features collapse + to two: `local` (the crate's first-party socket providers and + front doors, ADR-008) and `composed` (the alktunnels providers). + POC #4's gate map survives as the *extraction recipe* (its ungated + inventory is exactly what to copy), not as in-tree cfg. tokio + stays `default-features = false` with the wasm-clean subset + (AGENTS.md convention 4); `tokio/net` rides `local` alone. +- **The carried-changes list re-reads under extraction**: (1) the + net gate — dissolves (no net code); (2) BIND — stays (the typestate + driving + reply#2 writer are in-tree; ADR-007); (3) the + `run_udp_proxy_custom` bind seam — dissolves (the handler isn't + extracted; the typestate-driving shape POC #2 validated is the + crate's ASSOCIATE path); (4) `new_reply` publication — stays + (it is inside the extracted codec region). Net: **two carried + changes** touch extracted code. +- **Extraction completeness is compiler-checked**: a missed + transitive dependency is a build error, and the wasm check + (`cargo check --target wasm32-unknown-unknown`, plus + `--no-default-features` native) is the structural guard. The + extracted crate must compile clean with no `net`-shaped feature. +- **The extraction's dependency surface is adjusted, not absorbed**: + upstream's `log` calls in the extracted region are dropped or + re-pointed at the crate's `tracing` (the alk* convention); the + extracted region's `anyhow::Context` error wrapping is dropped + (error surface is the crate's `thiserror` types — the vendored + `SocksError`/`SocksServerError` stay the wire-level vocabulary); + `async-trait` is dropped (its four upstream uses are all on the + legacy `Authentication` layer, which is cut — the typestate's + `AuthMethod` traits are native async-fn-in-trait); the + `socks4` module and the legacy `Config`/`Authentication` layer are + out (above). These are extraction-time mechanical adjustments to + the copied code, not new carried changes. + +The verification commands in AGENTS.md that mention the wasm check +failing on the dependency graph are stale for this crate (that +caveat predated OQ-SK-04's resolution); the extraction makes the +wasm check a hard gate as in alktty/alktunnels. ## References diff --git a/docs/architecture/decisions/012-target-policy.md b/docs/architecture/decisions/012-target-policy.md index 4f1928e..4eea8ed 100644 --- a/docs/architecture/decisions/012-target-policy.md +++ b/docs/architecture/decisions/012-target-policy.md @@ -39,7 +39,9 @@ against a per-identity resource table). have no resolver at all, and the composed variant's targets ride the alktunnels direct op (producer-side resolution there, per alktunnels ADR-007's own posture). fast-socks5's `dns_resolve` - config stays off — it is a kernel-net concern, gated with `net`. + config (and its `resolve_dns` step) is not part of the extracted + vendor region at all — the crate's producer never resolves + (ADR-006/ADR-012), so the extraction drops both. - **The virtual-subnet translation layer is assembly-layer policy, not a crate feature.** The crate ships no translation-table helper in v1: the dial callback is the seam, and a deployment diff --git a/docs/architecture/open-questions.md b/docs/architecture/open-questions.md index a35863b..c1aa6b7 100644 --- a/docs/architecture/open-questions.md +++ b/docs/architecture/open-questions.md @@ -1,7 +1,8 @@ --- status: draft -last_updated: 2026-09-20 (Phase 1 initial draft — the OQ-SK ledger -OQ-SK-01..09 promoted; new questions continue as OQ-SK2-06..) +last_updated: 2026-09-21 (OQ-SK-04's resolution updated to the +extraction posture; the OQ-SK ledger OQ-SK-01..09 promoted 2026-09-20; +new questions continue as OQ-SK2-06..) --- # alksocks — Open Questions @@ -84,10 +85,11 @@ sequence starts at the numbers in use. Format per - **Origin**: [phase-0.md](../research/phase-0.md) (OQ-SK-04) - **Status**: resolved — [ADR-011](decisions/011-inline-vendor.md) - **Priority**: high -- **Resolution**: 2026-09-20 (Phase 0's final resolution, promoted). - The inline vendor: the `T`-generic subset in-tree behind the - default-on `net` feature; the four carried changes (net gate, - BIND, the udp-bind seam, `new_reply` publication); v1.0.0 noted; +- **Resolution**: 2026-09-20 (Phase 0's final resolution, promoted; + amended 2026-09-21 by ADR-011 §Amendment). The inline vendor as + **extraction**: the `T`-generic subset in-tree with zero kernel-net + code (wasm-clean by construction, no `net` feature); two carried + changes (BIND, `new_reply` publication); v1.0.0 noted; differential testing against `/workspace/fast-socks5`. - **Cross-references**: ADR-002, ADR-009, ADR-011 diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md index 40de4a3..d897ad6 100644 --- a/docs/architecture/overview.md +++ b/docs/architecture/overview.md @@ -1,6 +1,7 @@ --- status: draft -last_updated: 2026-09-20 (Phase 1 initial draft — the OQ-SK ledger promoted +last_updated: 2026-09-21 (the vendor extraction amendment — no `net` +feature; Phase 1 initial draft 2026-09-20 — the OQ-SK ledger promoted into ADRs 001-012 and open-questions.md) --- @@ -126,12 +127,9 @@ alksocks (default — wasm-clean) ├── serde/serde_json (params schema), thiserror (error surface), tracing └── (no backend deps — sockets live in feature-gated modules) -alksocks (net feature, default-on) — non-wasm -└── adds: tokio/net, socket2, tokio-stream (the vendored subset's - kernel-net gate; ADR-009) - alksocks (local feature) — non-wasm by design -└── adds: the first-party local backends + front doors (implies net) +└── adds: tokio/net + socket2 (the feature's own socket providers) and + the first-party local backends + front doors alksocks (composed feature) └── adds: alktunnels 0.2.0 (the direct op egress; the bind-first @@ -141,18 +139,19 @@ alksocks (composed feature) ``` Same posture as alktty/alktunnels: the default crate is -protocol-only and wasm-clean; the vendored fast-socks5 subset rides -the `net` gate (ADR-011); substrate I/O is feature-gated -(ADR-009). `fast-socks5` is NOT a Cargo dependency — it is vendored -in-tree (ADR-011). +protocol-only and wasm-clean — the vendor is an *extraction* of +fast-socks5's `T`-generic subset, containing zero kernel-net code, +so there is no `net` feature at all (ADR-011 §Amendment); +substrate I/O rides `local` alone (ADR-009 §Amendment). +`fast-socks5` is NOT a Cargo dependency — it is extracted in-tree +(ADR-011). ## Feature Gates | Feature | Contents | Wasm | |---------|----------|------| -| *(default)* | the vendored `T`-generic subset (codecs, typestate), wire codec, open-op spec, the three seams' traits/types, producer + consumer session types — protocol only | yes | -| `net` *(default-on)* | the vendored subset's kernel-net pieces (`tokio/net`, `socket2`): the local-socket default handlers, DNS resolve helper, `Socks5Datagram` kernel socket path | no (wasm builds use `default-features = false`) | -| `local` | the crate's first-party local backends: TCP dial, UDP egress socket, BIND `TcpListener` accept, the front doors (consumer + producer local shapes) — implies `net` | no (build error on wasm, the alktty posture) | +| *(default)* | the extracted `T`-generic subset (codecs, typestate), wire codec, open-op spec, the three seams' traits/types, producer + consumer session types — protocol only; zero kernel-net code, wasm-clean by construction | yes | +| `local` | the crate's first-party local backends: TCP dial, UDP egress socket, BIND `TcpListener` accept, the front doors (consumer + producer local shapes); brings `tokio/net` + `socket2` into the graph | no (build error on wasm, the alktty posture) | | `composed` | the composed providers over alktunnels 0.2.0: direct-op egress (lazy destination→tunnel table), bind-first listen accept — adds the alktunnels dep | yes (alktunnels' default crate is wasm-clean; the composed providers use only its ungated channels surface — verify with the wasm check at implementation) | ## Module Map @@ -160,10 +159,10 @@ in-tree (ADR-011). ``` src/ lib.rs — re-exports; crate docs - vendor/ — the vendored fast-socks5 T-generic subset (ADR-011; + vendor/ — the extracted fast-socks5 T-generic subset (ADR-011; vendor point v1.0.0 noted in-tree): codecs, typestate, - client use_stream path, carried changes (BIND reply - writer, new_reply publication, the udp-bind seam) + client use_stream path; two carried changes (BIND reply + writer, new_reply publication); no kernel-net code params.rs — the trivial params schema + SOCKS5_OPEN_SCOPE/ SOCKS5_BIND_SCOPE constants (ADR-001/006) wire.rs — the ASSOCIATE datagram frame codec, re-implemented @@ -207,9 +206,9 @@ All design decisions are documented as ADRs in [decisions/](decisions/). | [006](decisions/006-access-control.md) | Access-control posture | `socks5:open` gate + `socks5:bind` command gate; target policy = the dialer | | [007](decisions/007-bind-in-base.md) | BIND in the base crate | phase model extended (reply#1 → quiet wait → accept → reply#2 → pass-through); additive | | [008](decisions/008-provider-defaults.md) | Provider defaults | local-socket + composed (direct op) providers, both feature-gated; no implicit dialer | -| [009](decisions/009-feature-gates.md) | Feature gates | `net` (default-on, the vendor's gate), `local`, `composed`; default crate wasm-clean | +| [009](decisions/009-feature-gates.md) | Feature gates | `local` + `composed`; no `net` feature (the vendor is wasm-clean by construction — ADR-011 §Amendment); default crate wasm-clean | | [010](decisions/010-channel-capacity.md) | Channel capacity | no wire change; assembly-layer config + the documented proxy-workload recommendation | -| [011](decisions/011-inline-vendor.md) | The inline vendor | the `T`-generic subset vendored in-tree; the four carried changes; v1.0.0 noted | +| [011](decisions/011-inline-vendor.md) | The inline vendor | the `T`-generic subset extracted in-tree; two carried changes (BIND, `new_reply`); v1.0.0 noted | | [012](decisions/012-target-policy.md) | Target policy | dialer-refuses; domain targets pass through unresolved; virtual subnets = assembly policy | ## Open Questions diff --git a/docs/architecture/vendor.md b/docs/architecture/vendor.md index 02929ea..aa29bf4 100644 --- a/docs/architecture/vendor.md +++ b/docs/architecture/vendor.md @@ -1,6 +1,8 @@ --- status: draft -last_updated: 2026-09-20 (Phase 1 initial draft) +last_updated: 2026-09-21 (the extraction amendment — ADR-011 §Amendment: +extraction not wholesale copy, the net gate dissolves, two carried +changes; Phase 1 initial draft 2026-09-20) --- # alksocks — The Inline Vendor (fast-socks5 subset) @@ -12,71 +14,131 @@ vendor's scope, the carried changes, and the maintenance posture. The protocol base decision is ADR-002; the feature gating is ADR-009. -## What is Vendored +## The Mechanism: Extraction, Not Wholesale Copy (ADR-011 §Amendment) + +The vendor is an **extraction**: copy *only* the `T`-generic +inventory from fast-socks5 v1.0.0 into `src/vendor/`; the kernel-net +handlers are **not copied** — they stay in `/workspace/fast-socks5` +(the read-only reference checkout). Concretely: POC #4's cfg map +(its five-file inventory of what is kernel-net-gated) is the base of +the extraction recipe — copy what POC #4 left *ungated*, minus the +two recorded exclusions (the `socks4` module and the legacy +`Config`/`Authentication` layer — see the cut table). The extraction +contains zero kernel-net code, so it is wasm-clean by construction; +there is no in-tree `net`-shaped feature gate (that part of POC #4's +change dissolves — ADR-011 §Amendment). + +## What is Extracted From fast-socks5 **v1.0.0** (MIT, third-party upstream — `/workspace/fast-socks5` is the read-only reference checkout; the -vendor point is noted in the vendored code): +vendor point is noted in the extracted code): -| Piece | Why it rides | Gating | -|-------|--------------|--------| -| The server typestate (`Socks5ServerProtocol`, negotiate/auth/command-read/reply) | the producer's conversation driver (ADR-002) | `T`-generic — ungated | -| The auth traits (`AuthMethod`/`AuthMethodSuccessState`) | the negotiation machinery (the crate uses NoAuth in-band; the traits stay for fidelity) | ungated | -| `transfer` (the generic two-pump) | the interception-point shape (the crate's data plane is `pump_bidi`, but `transfer` is the typestate's own seam) | ungated | -| The codecs: `new_udp_header`/`parse_udp_request`, `TargetAddr`/`to_be_bytes`/`read_address`, `new_reply` (published — carried change #4), `ReplyError`/`SocksError`/`SocksServerError` | the RFC wire vocabulary everywhere (front doors, associate frames, reply#2 reader) | ungated | -| The client types: `Socks5Stream::use_stream` + the `AsyncRead/AsyncWrite` impls | the consumer half's stream session (ADR-002; POC #1's fit) — the first-party associate session in `consumer.rs` was informed by this shape (upstream's `Socks5Datagram` kernel path is the net-gated row) | ungated | -| Kernel-net pieces (the local-socket default handlers, `Socks5Datagram`'s kernel socket path, the DNS resolve helper, the legacy `Socks5Server`/`Incoming`) | upstream surface kept for fidelity where `net` is on | **`net`-gated** | +| Piece | Why it rides | Notes | +|-------|--------------|-------| +| The server typestate (`Socks5ServerProtocol`, negotiate/auth/command-read/reply, `accept_no_auth`/`finish_auth`/`accept_password_auth`) | the producer's conversation driver (ADR-002) | `T`-generic | +| The auth traits (`AuthMethod`/`AuthMethodSuccessState`) | the negotiation machinery (the crate uses `accept_no_auth` in-band; the traits stay for fidelity) | `T`-generic | +| `transfer` + `wait_on_tcp` | the typestate's own two-pump seam (the crate's data plane is `pump_bidi`; `transfer` is the interception-point shape) | `T`-generic | +| The codecs: `new_udp_header`/`parse_udp_request`, `TargetAddr`/`to_be_bytes`/`read_address`, `ReplyError`/`SocksError`/`SocksServerError` | the RFC wire vocabulary everywhere (front doors, associate frames, reply#2 reader) | pure; `new_reply` published in-tree (carried change) | +| The client types: `Socks5Stream::use_stream` + the `AsyncRead/AsyncWrite` impls | the consumer half's stream session (ADR-002; POC #1's fit) — the first-party associate session in `consumer.rs` was informed by this shape | `T`-generic | +| The non-net test modules (where extractable as unit tests) | RFC edge-case coverage rides in-tree | adjusted to the crate's test layout | -Not vendored: the deprecated `Socks5Server`/`Socks5Socket`/`Incoming` -bind-based API as a *default path* (it exists upstream and stays -behind `net`; the crate never routes through it). The vendored subset -is functionally complete without `net` (POC #4: a full RFC 1928 -CONNECT conversation passes `--no-default-features`). +## What is NOT Extracted (the cut — POC #4's gated inventory + two recipe additions) -## The Four Carried Changes (ADR-011) +These stay in `/workspace/fast-socks5` (the differential-testing +reference); the cut table below records the boundary, so a future +re-vendor knows the cut. Rows 1–5 are POC #4's five-file cfg map +(what POC #4 gated is what is not extracted); the socks4 row and the +legacy `Config`/`Authentication` layer are this recipe's two +additions — the socks4 module is out of RFC 1928 scope, and the +legacy auth layer was left ungated by POC #4 (it compiles without +net) but no extraction consumer reaches it. None of it is copied: -The vendor's diff vs upstream v1.0.0 is deliberate and bounded: +| Upstream file | Region NOT in `src/vendor/` | +|---|---| +| `src/server.rs` | `run_tcp_proxy`, `run_udp_proxy`/`run_udp_proxy_custom`, `udp_bind_random_port`, the legacy `Socks5Server`/`Incoming`/`Socks5Socket` (struct + impls), `DnsResolveHelper` trait + impl, `handle_udp_*`/`transfer_udp`, the net-only test module — plus the legacy `Config` + `Authentication` trait + impls (`SimpleUserPassword`/`DenyAuthentication`/`AcceptAuthentication`, `authenticate_callback`), which POC #4 left ungated but which only this cut region consumes (rows 1–5 are POC #4's gate map; the `Config`/`Authentication` layer and the socks4 row are this recipe's two additions) | +| `src/client.rs` | `Socks5Datagram` (struct + impl), the `Socks5Stream` convenience impl (`connect`/`connect_with_password`/`connect_raw`) | +| `src/util/stream.rs` | `tcp_connect*` fns (the `read_exact!`/`ready!` macros + `ConnectError` stay) | +| `src/util/target_addr.rs` | the `resolve_dns` method (the codec stays) | +| `src/lib.rs` | the net-heavy test module (consts/errors/UDP-header codec stay) | +| `src/socks4/` | the whole module (upstream's separate default-off `socks4` cargo feature; out of RFC 1928 scope) | -1. **The `net` feature gate** — ~120 `#[cfg]` insertions across 5 - files, exactly POC #4's measured shape - (`poc-connect-wasm-findings.md` §The gating change: server.rs - ~8 insertions; client.rs 87 diff lines (whitespace-inflated); - util/stream.rs, util/target_addr.rs, lib.rs ≤3; Cargo.toml's - `net = ["tokio/net", "dep:socket2", "dep:tokio-stream"]`). -2. **BIND** — absent upstream (every handler refuses +**Why none of it is needed in-tree** (ADR-011 §Amendment): no crate +consumer routes through the kernel-net region — the producer drives +the typestate directly (the ASSOCIATE path is the POC #2 +typestate-driving shape; `run_udp_proxy_custom` is unusable on +channels regardless), the consumer sessions use `use_stream` plus +the first-party associate session, the doors are pure codecs + +first-party bridges, and the local backends are first-party tokio +code (ADR-008). The "producer-side local backend" is a bridge *onto +the channels-served service* (POC #1's door shape), not a standalone +vanilla server. If a future need surfaces (e.g. a standalone +vanilla-server example), the fix is re-vendor that piece then, as an +additive decision. + +## The Carried Changes (ADR-011, re-read under extraction) + +The extraction's diff vs upstream v1.0.0 is deliberate and bounded — +**two changes touch extracted code**; the other two of the original +four dissolve with the kernel-net region: + +1. **BIND** — absent upstream (every handler refuses `Socks5Command::TCPBind`). The crate drives the typestate itself for the BIND shape (ADR-007); the vendor carries the shape in-tree (`reply_success`'s `sock_addr` as the reply#1 carrier; the reply#2 writer using the published `new_reply`). -3. **The `run_udp_proxy_custom` bind seam** — the seam is narrower - than it looks (`udp_bind_random_port` unconditionally; the reply - port derives from that kernel socket). In-tree fix: make the bind - optional / accept a caller-supplied socket. (The channels path - drives the typestate directly regardless; the fix serves the - `net`-gated path's embedders.) -4. **`new_reply` publication** — the reply encoder becomes public +2. **`new_reply` publication** — the reply encoder becomes public (a `reply(code, addr)`-shaped constructor) so the BIND reply#2 writer doesn't re-encode the 10/22-byte reply form. +Dissolved: the `net` feature gate (no net code in-tree) and the +`run_udp_proxy_custom` bind seam (the handler isn't extracted). + Plus the provenance notes: the vendor point (v1.0.0) and the license headers (MIT; preserve per-file headers or a bundled notice — ADR-011's license obligation). +Plus the **extraction-time adjustments** (not carried changes — +mechanical edits to the copied code, ADR-011 §Amendment): + +- The `socks4` module is out entirely (upstream's separate + default-off `socks4` cargo feature, which POC #4 never compiled; + out of RFC 1928 scope). `SocksError`'s `ReplySocks4Error` variant + (also `#[cfg(feature = "socks4")]` upstream) goes with it. +- The legacy `Config`/`Authentication` auth layer is out + (ungated upstream, but consumed only by the cut legacy/net region + — `Socks5Server`/`Socks5Socket`/the `run_*` handlers; the + typestate's own `accept_no_auth`/`accept_password_auth` are the + crate's in-band auth surface). With it go `async-trait` (its four + upstream uses are all on this layer), the example auth impls + (`SimpleUserPassword`/`DenyAuthentication`/`AcceptAuthentication`), + and `SocksError`'s `AuthenticationRejected`-consuming legacy + plumbing that only they exercise. +- Upstream `log` calls in the extracted region are dropped or + re-pointed at the crate's `tracing`. +- Upstream `anyhow` error wrapping (`Context` / `Other(#[from] + anyhow::Error)`) is dropped — the crate's error surface is + `thiserror`-typed; the vendored `SocksError`/`SocksServerError` + stay the wire-level vocabulary. + ## Maintenance Posture - **The vendor is first-class code, not a patch stack**: the carried - changes live in-tree and co-evolve with the wrapper; the vendored + changes live in-tree and co-evolve with the wrapper; the extracted subset's RFC fidelity is the crate's own test suite's job. - **Differential testing**: `/workspace/fast-socks5` stays the reference for RFC edge cases (reply-code mapping, domain addressing, fragmentation). The crate's test suite covers the - edge cases the vendored code must keep passing; when in doubt, - diff behavior against the reference checkout. + edge cases the extracted code must keep passing; when in doubt, + diff behavior against the reference checkout. The kernel-net + region lives there too — the reference checkout is the only place + the full upstream surface exists. - **Upstream posture**: fast-socks5 is third-party; nothing waits on - it. Offering the `net` gate upstream as a courtesy PR is optional - (POC #4: small enough to offer as-is); a future upstream release - may be re-based against deliberately, never absorbed silently - (the carried changes would need re-verification). + it. Offering a net-gate PR upstream is optional courtesy (POC #4: + small enough to offer as-is) and unrelated to this crate's build — + the extraction doesn't need it. A future upstream release may be + re-based against deliberately, never absorbed silently (the + extraction cut + carried changes would need re-verification). - **No second codec, ever**: the vendored codecs are the only RFC wire vocabulary in the crate (ADR-011's rationale; the alknet anti-prior-art record is in phase-0 §Anti-prior-art). @@ -86,8 +148,8 @@ ADR-011's license obligation). | ADR | Decision | Summary | |-----|----------|---------| | [002](decisions/002-protocol-base.md) | Protocol base | the explicit typestate API only | -| [009](decisions/009-feature-gates.md) | Feature gates | `net` default-on; wasm builds use `default-features = false` | -| [011](decisions/011-inline-vendor.md) | The inline vendor | the subset in-tree; the four carried changes; v1.0.0 noted | +| [009](decisions/009-feature-gates.md) | Feature gates | `local`, `composed`; the default crate is wasm-clean with no `net` feature (ADR-011 §Amendment) | +| [011](decisions/011-inline-vendor.md) | The inline vendor | the extraction in-tree; two carried changes (BIND, `new_reply`); v1.0.0 noted | ## Open Questions diff --git a/docs/research/phase-0.md b/docs/research/phase-0.md index a2521a4..ffdbb7d 100644 --- a/docs/research/phase-0.md +++ b/docs/research/phase-0.md @@ -168,9 +168,11 @@ not start from zero. It inherits: layer (alktty `TtyBackend` / alktunnels no-trait precedent). - **The wasm-clean default crate** — protocol-only code should compile to `wasm32-unknown-unknown` (alktty/alktunnels precedent). The - vendored fast-socks5 subset is wasm-clean: the inline vendor gates - kernel-net behind a default-on `net`-shaped feature (OQ-SK-04 - resolved; POC #4 verified the subset is functionally complete). + extracted fast-socks5 subset is wasm-clean by construction: the + inline vendor is an extraction (the `T`-generic subset only; the + kernel-net handlers are not copied — OQ-SK-04 resolved; ADR-011 + §Amendment, 2026-09-21; POC #4 verified the subset is functionally + complete). - **The upstream substrate this crate composes against** — alkcall 0.8.0 (reply projection; `ChannelRelay`/`HubLegTemplate` per ADR-051; flavor-form open-op ids in discovery per ADR-047 amendment 3) and @@ -219,13 +221,15 @@ load-bearing conclusions this crate inherits: ### fast-socks5 — the vendored implementation `/workspace/fast-socks5` (v1.0.0, MIT — third-party upstream, not ours; -read-only reference checkout). **The posture is the inline vendor -(OQ-SK-04, resolved 2026-09-20): vendor the `T`-generic subset into this -crate behind a default-on `net`-shaped feature, carrying the wrapper's -needs in-tree.** `/workspace/fast-socks5` remains the differential-testing -reference for RFC edge cases (reply-code mapping, domain addressing, -fragmentation); note the vendor point (v1.0.0) in the vendored code. Key -surface points, verified: +read-only reference checkout). **The posture is the inline vendor as an +extraction (OQ-SK-04, resolved 2026-09-20; extraction pinned +2026-09-21, ADR-011 §Amendment): extract the `T`-generic subset into +this crate — the kernel-net handlers and the `socks4` module are not +copied — carrying the wrapper's needs in-tree.** +`/workspace/fast-socks5` remains the differential-testing reference +for RFC edge cases (reply-code mapping, domain addressing, +fragmentation); note the vendor point (v1.0.0) in the vendored code. +Key surface points, verified: - **Explicit typestate server API** (`src/server.rs`): `Socks5ServerProtocol`, @@ -284,15 +288,17 @@ surface points, verified: proxy, refuse, or handle in-process. Structurally the shape of the channels open handler (inspect params → dial or refuse) and of the alknet ADR-090 client (hand the established stream to quinn). -- **What the vendor must add (the four carried needs):** the - kernel-net feature gate (POC #4: ~120 cfg lines, wasm-clean subset - functionally complete); **BIND** (absent upstream — fast-socks5 - parses `Socks5Command::TCPBind` but every handler refuses it, - `lib.rs:384-386` / `server.rs:813-816`; the wrapper drives the - typestate itself); the `run_udp_proxy_custom` bind seam (above); and - the publication of `new_reply` (the reply encoder is private; the - BIND reply#2 writer otherwise hand-rolls the 10-byte reply — - `poc-bind-findings.md`). +- **What the vendor must add (the carried needs; re-read under the + 2026-09-21 extraction amendment — ADR-011 §Amendment):** **BIND** + (absent upstream — fast-socks5 parses `Socks5Command::TCPBind` but + every handler refuses it, `lib.rs:384-386` / `server.rs:813-816`; + the wrapper drives the typestate itself) and the publication of + `new_reply` (the reply encoder is private; the BIND reply#2 writer + otherwise hand-rolls the 10-byte reply — `poc-bind-findings.md`). + The other two of the original four needs — the kernel-net feature + gate (POC #4: ~120 cfg lines, wasm-clean subset functionally + complete) and the `run_udp_proxy_custom` bind seam — dissolve with + the kernel-net region, which the extraction does not copy. ### iroh-socks5 — the structural sibling (evaluated, not the base) @@ -783,7 +789,7 @@ drives the command dispatch itself — implementing BIND is wrapper-side code, carried in the vendor (no upstream ask). POC-confirmed: `reply_success`'s `sock_addr` parameter carries reply#1's `BND.ADDR` verbatim; the courtesy item is publishing `new_reply` (rides the -vendor — see §Prior art's four carried needs). +vendor — see §Prior art's carried needs). **The shape (convergent precedent: iroh-socks5's channels-native BIND — server relays raw bytes post-reply for CONNECT/BIND, `docs/research/ @@ -1102,14 +1108,15 @@ except the two explicit, optional, feature-gated assembly shapes protocol modules at the crate core; feature-gated backend modules (local binds) never imported by the protocol layer; producer + consumer + params modules mirroring POC #1/#2's structure. **The - fast-socks5 posture is the inline vendor (OQ-SK-04, resolved - 2026-09-20)**: vendor the `T`-generic subset into this crate (the - codecs, typestate machinery, client `use_stream` path), gated behind - a default-on `net`-shaped feature (POC #4: ~120 cfg lines, wasm-clean - subset functionally complete) — and carry the four wrapper needs in - the same vendor: BIND (absent upstream; POC #5's typestate-driven - shape), the `run_udp_proxy_custom` bind seam, the `new_reply` - publication, and the wasm gate. `/workspace/fast-socks5` stays the + fast-socks5 posture is the inline vendor as an extraction (OQ-SK-04, + resolved 2026-09-20; extraction pinned 2026-09-21, ADR-011 + §Amendment)**: extract the `T`-generic subset into this crate (the + codecs, typestate machinery, client `use_stream` path; the + kernel-net handlers and `socks4` are not copied, so there is no + `net` feature — POC #4's gate map survives as the extraction + recipe) — and carry the two extracted-region needs in the same + vendor: BIND (absent upstream; POC #5's typestate-driven shape) and + the `new_reply` publication. `/workspace/fast-socks5` stays the differential-testing reference; note the vendor point (v1.0.0) in the vendored code. - **Open for Phase 1 ADRs** (inputs collected, decisions pending): the diff --git a/docs/research/poc-bind-findings.md b/docs/research/poc-bind-findings.md index 9a0652f..4b1de64 100644 --- a/docs/research/poc-bind-findings.md +++ b/docs/research/poc-bind-findings.md @@ -231,7 +231,10 @@ both asks are **superseded in shape**, not implemented as posed: `run_udp_proxy_custom` unconditional-bind seam. (Posture note, 2026-09-20: fast-socks5 is third-party upstream and these are no longer asks — all three move into the inline vendor, OQ-SK-04 - resolved.) + resolved. 2026-09-21: under the extraction — ADR-011 §Amendment — + `new_reply` is the one that rides in-tree; the `net` gate and the + bind seam dissolve with the kernel-net region, which is not + copied.) The POC's evidence stands as the record of what was validated against alktunnels 0.1.0; the Phase 1 shape composes variant 2 against 0.2.0 @@ -261,7 +264,10 @@ are additive surface, discovered in priority order: 3. **(fast-socks5, courtesy)** `new_reply` is private — publish it (or a constructor) so embedders don't re-encode the reply wire form. Also still open from POC #4: the `net` feature gate and the - `run_udp_proxy_custom` unconditional-bind seam. + `run_udp_proxy_custom` unconditional-bind seam. (2026-09-21: under + the extraction — ADR-011 §Amendment — `new_reply` is the one that + rides in-tree; the `net` gate and the bind seam dissolve with the + kernel-net region, which is not copied.) No asks block the POC's conclusions; 1–2 shape variant 2's *full* fidelity, and the POC's stand-ins (carried `bind_addr`; sentinel diff --git a/docs/research/poc-connect-wasm-findings.md b/docs/research/poc-connect-wasm-findings.md index 151b151..b5335b4 100644 --- a/docs/research/poc-connect-wasm-findings.md +++ b/docs/research/poc-connect-wasm-findings.md @@ -181,7 +181,10 @@ were recorded as "asks" under the wrong ownership premise and move into the vendor with it. 1. **Feature-gate kernel-net behind a default-on `net` feature** - (POC #4's change, ~120 lines of `#[cfg]`). + (POC #4's change, ~120 lines of `#[cfg]`). (2026-09-21: dissolved + under the extraction — ADR-011 §Amendment; the kernel-net region + is not copied, and POC #4's gate map survives as the extraction + recipe, not in-tree cfg.) 2. **`run_udp_proxy_custom` binds a kernel socket unconditionally** (noted in phase-0 §Prior art, verified again here): the customizable seam covers the relay closure and reply IP only; the