Files
alksocks/docs/architecture/decisions/002-protocol-base.md
T
glm-5.3-flash b0cfc26065 docs: pin the vendor scope as extraction — the net gate dissolves
Complete the ADR-011 §Amendment (extraction, not wholesale-copy-plus-
gate) across every doc that stated the pre-amendment posture:

- ADR-011: add the two extraction-recipe exclusions the amendment
  missed (the socks4 module — upstream's separate default-off cargo
  feature, out of RFC 1928 scope; the legacy Config/Authentication
  auth layer — ungated but consumed only by the cut region) and the
  dependency-surface adjustments (log -> tracing, anyhow dropped,
  async-trait dropped with its legacy-layer uses)
- ADR-009: amend — the vendor's net gate dissolves; features collapse
  to local + composed; local carries tokio/net + socket2 itself
- vendor.md: replace the contradictory old "four carried changes"
  section with the two-change reading + extraction-time adjustments;
  extend the cut table (socks4 row, legacy auth layer)
- overview.md: dependency diagram + feature table drop the net
  feature; module map reflects two carried changes
- README.md: principles 7/8 + doc/ADR tables updated
- ADR-002/012, open-questions.md (OQ-SK-04), phase-0.md current-state
  sections, AGENTS.md conventions 4/17 + stale wasm-caveat sentence,
  POC findings posture notes: aligned with the extraction

Verification: repo-wide grep for stale "four carried"/default-on net/
implies-net statements returns only amendment-context matches;
extraction recipe re-verified against POC #4's gate map and the
fast-socks5 v1.0.0 source (async-trait usage confined to the cut
legacy layer; AuthMethod<T> traits are native async-fn-in-trait).
2026-09-21 03:15:04 +00:00

2.9 KiB

ADR-002: Protocol Base — the Vendored fast-socks5 Typestate Subset

Status

Accepted (2026-09-20, Phase 1; the inline-vendor posture is OQ-SK-04's resolution, recorded in ADR-011)

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 vendored into the default path.
  • 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 convention 2). POC #1 validated the mapping (dial refusal → 0x05).

Consequences

  • 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 ASSOCIATE's unconditional bind) — direct typestate driving. The interception-point map is spec'd in 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: inline vendor), 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)