alksocks 0.3.2

SOCKS5 (RFC 1928) proxy protocol over alkcall channels: targeted-forked fast-socks5 typestate core plus producer/consumer sessions. Producer/consumer protocol crate.
Documentation
# ADR-002: Protocol Base: the Vendored fast-socks5 Typestate Subset

## Status

Accepted (2026-09-20, Phase 1; the extracted-and-forked posture is
OQ-SK-04's resolution: the extraction mechanics in
[ADR-011](011-inline-vendor.md), the ownership posture in
[ADR-013](013-targeted-fork.md))

## Context

Phase 0 evaluated the protocol-base candidates: fast-socks5 (the
full-fidelity RFC 1928 implementation, explicit typestate server API,
generic over `T`), iroh-socks5 (structurally the closest sibling, but
iroh-coupled and an RFC subset), and a hand-rolled codec (rejected as
anti-prior-art; alknet's client hand-rolls, and it is the known
weakness). POC #1 confirmed the load-bearing property: fast-socks5's
`Socks5ServerProtocol<T, states::*>` accepts a channels `BiStream`
directly (`T: AsyncRead + AsyncWrite + Unpin`), and POC #4 measured
the wasm gating at ~120 cfg lines with the wasm-clean subset
functionally complete (a full RFC 1928 CONNECT conversation passes
`--no-default-features`).

## Decision

- **The protocol layer is built on fast-socks5's explicit typestate
  API**: `Socks5ServerProtocol<T, …>` (negotiate/finish_auth/
  read_command/reply_success/reply_error), the client side
  `Socks5Stream<S>::use_stream` / the associate session, and the
  pure codecs (`new_udp_header`/`parse_udp_request`).
- **Only the explicit API is used.** The legacy
  `Socks5Server`/`Socks5Socket`/`Incoming` bind-based API is
  deprecated upstream and is out; never forked into the default
  path.
- **Base = v1.0.0, extracted in-tree and forked** (ADR-011 for the
  extraction mechanics and the two carried changes; ADR-013 for the
  targeted-fork ownership posture).
  `/workspace/fast-socks5` remains the read-only reference for
  differential testing of RFC edge cases; the fork point is noted
  in the module docs and the bundled license notice.
- **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
  convention 2). POC #1 validated the mapping (dial refusal → 0x05).

## Consequences

- The crate owns its protocol code in-tree (the fork), 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
  ASSOCIATE's unconditional bind), direct typestate driving. The
  interception-point map is spec'd in [producer.md]../producer.md.
- iroh-socks5's design ideas (the `{addr, data}` frame, control-EOF
  association lifetime, FRAG≠0 refusal) were adopted at the design
  level, not the code level (`docs/research/iroh-socks5-eval.md`).

## References

- OQ-SK-04 (resolved: the extracted-and-forked base), OQ-SK-03 (the
  `run_udp_proxy_custom` caveat)
- `docs/research/iroh-socks5-eval.md` (the base comparison),
  POC #1 + POC #4 (`poc-connect-wasm-findings.md`)
- Sibling precedent: alktunnels ADR-002 (one-ALPN option A)