# ADR-013: The Targeted Fork: fast-socks5's `T`-Generic Subset Is Owned, Not Vendored ## Status Accepted (2026-09-22, post-extraction-review; supersedes the ADR-011 maintenance posture; ADR-011 stays for the extraction mechanics and the cut table; the ADR-011 §Amendment is subsumed here) ## Context ADR-011 pinned the inline-vendor posture as **extraction** (the `T`-generic subset copied in-tree, kernel-net region not copied; the net gate dissolving), and the vendor group (five implementation tasks plus the review gate) landed it in commits `57b107b..5b18d4d`, with the review (`tasks/implementation/ review-vendor-extraction.md`) as the fidelity gate: the file-by-file diff vs `/workspace/fast-socks5` v1.0.0 categorizes every hunk, and every review criterion passed. The review also made the maintenance posture's cost visible. The tree is now permanently diverged from upstream in five categories: 1. **The extraction cut**: the kernel-net region, `socks4`, the legacy `Config`/`Authentication` layer, `Socks5Datagram`, the convenience dialers, the DNS helper: gone. 2. **The carried changes**: BIND's reply surface, the published `new_reply`. 3. **The panic translations**: `ReplyError::from_u8` (the review's F-1), `use_password_auth`, `reply_error`'s parse. 4. **The error-pruning adjustments**: anyhow/log/async-trait out, error variants pruned, `MissingTargetAddr` added. 5. **The lint-allow posture**: module-level `#[allow]`s preserving upstream style (`u8::max_value()`, needless lifetimes, `match_like_matches_macro`, `io_other_error`, `wrong_self_ convention`, the F-4 verbatim string) to keep the diff mechanical. Category 5 exists solely to keep categories 1–4 reconcilable by a line-based diff. But a future re-base against an upstream release was never going to be a clean mechanical diff again; it was always going to be manual reconciliation across all five categories. The vendor posture's maintenance apparatus (verbatim preservation, the lint allows, the re-vendor/adjustment-list discipline) pays a permanent tax to serve a re-base path that would never be used. The "vendor" framing also produced a real defect: the review's F-1 (`ReplyError::from_u8`'s upstream `unreachable!()` arm kept verbatim; wire-reachable, a misbehaving peer could panic the consumer task) escaped precisely because the vendor posture maintained a second, weaker instruction set ("verbatim + adjustments list" instead of "project conventions, unconditionally"). The fidelity-vs-conventions tension is structural to the vendor framing; the review caught the escape, but the seam itself was the vendor framing's. The fork point is now, post-review and post-F-1, the cleanest line the tree will ever present: the extraction provenance is in git history (`57b107b..5b18d4d`), the review is the recorded fidelity gate, and the five divergence categories are documented in ADR-011, vendor.md, and the review task. "The tree as of the review commit (`5b18d4d`) is the fork point" is a trivially defensible line. ## Decision - **The extracted region is a targeted fork, fully owned by this crate.** The "vendor" framing is retired: there is no upstream tree to stay reconcilable with, no re-vendor, no adjustment-list apparatus, no second instruction set. Project conventions (the AGENTS.md set) apply unconditionally to the forked code. - **The fork point is the tree as of commit `5b18d4d`** (the extraction review's gate commit). The extraction provenance is carried in git history (`57b107b..5b18d4d`), the module docs, and the extended LICENSE notice; the review task is the recorded fidelity gate. - **Module naming: the forked core is `src/rfc1928/`, re-exported as `alksocks::rfc1928`.** "vendor" names an ownership relation (now gone); "socks5" would stutter with the crate name (`alksocks::socks5`) and collide with the future module structure (the producer/consumer/adapter layers are also SOCKS5-shaped). `rfc1928` names what the module *is* (the RFC 1928 wire vocabulary and the state machines), permanent and collision-free. - **The lint-allow posture dissolves.** The module-level `#[allow]`s and the "verbatim lint posture" module-doc paragraphs are removed; the suppressed smells are fixed per project conventions: `u8::max_value()` → `u8::MAX`, needless lifetimes elided, `match_like_matches_macro` applied, `io::Error::new(Other)` → `io::Error::other`, `wrong_self_convention` fixed on `AuthMethod:: new(self, ..)`, the F-4 string re-worded (it no longer names a cut function), and the `#[allow(dead_code)]` on `AuthenticationMethod` swept with actual usage. Upstream's commented-out dead code stays dropped (F-2). - **The license mechanics**: MIT permits sublicensing, so modifications after the fork point are this project's under the crate license (MIT OR Apache-2.0, per Cargo.toml). The bundled notice is **extended, not replaced**: upstream MIT text + copyright (the notice-preservation obligation, perpetual) + a fork-point statement + the modification note. - **The reference checkout survives as a behavioral reference.** `/workspace/fast-socks5` stays for differential testing of RFC edge cases; the differential suite (tests/rfc1928-differential.rs) pins bytes, not upstream text, so it survives the rename untouched. Textual-diff discipline is retired; behavioral differential testing is retained. - **The cut table is re-read as the not-forked inventory**, the map of what to hand-port if a future need surfaces (e.g. the kernel-net region for a standalone vanilla-server example). The hand-port path replaces the re-vendor path: port against the reference checkout, adapt to the crate's conventions, and let the suite guard it. - **The honest cost**: the cheap upstream-fix path closes. A future fast-socks5 fix (a reply-code mapping correction, a codec fix) arrives as a hand-port against the reference checkout, not a diff absorb. Risk is assessed low; fast-socks5 is a quiet project, and the extracted surface is the well-trodden RFC 1928 path. ## Consequences - **Positive**: one instruction set (project conventions, unconditionally); the lint-allow tax and the adjustment-list apparatus dissolve; smells are fixed at the only cost that matters: a one-time cleanup verified by the existing suite. The F-1 seam class (conventions-vs-fidelity gaps) is closed structurally. - **Positive**: the module name is stable for the crate's future (no `alksocks::socks5` stutter, no `socks5::producer` collision pressure). - **Negative (accepted)**: the cheap upstream-fix path closes; a future upstream fix is a hand-port against the reference checkout, guarded by the differential suite. Assessed low-risk (quiet upstream, well-trodden RFC surface). - **Neutral**: the differential suite survives the rename untouched (it pins bytes, not upstream text). `/workspace/fast-socks5` keeps its role as the behavioral reference; the only thing it loses is being the target of a line-based diff. - **Neutral**: the fork-point line (`5b18d4d`) is recorded in git history, the module docs, and the extended LICENSE notice; the extraction provenance (the ADR-011 trail) remains readable. ## References - ADR-011 (the extraction mechanics, the cut table, the carried changes; the mechanics remain authoritative), ADR-002 (the protocol base), ADR-009 (feature gates, no `net` feature) - `tasks/implementation/review-vendor-extraction.md` (the fidelity gate + F-1), `docs/architecture/rfc1928.md` (the owned-core spec) - `/workspace/fast-socks5` (v1.0.0, MIT, the behavioral reference for differential testing)