Files
glm-5.3-flash e196ed43e3 docs: remove em dashes from repo prose and forbid them going forward
- Rewrote em dash prose across the whole tree outside docs/reviews/
  (the historical reviews stay verbatim, matching the alktunnels and
  alktty precedent): src doc comments and inline comments (587),
  docs/architecture (319), docs/research + sdd_process (484), tests
  (361), tasks (899), fuzz (28), README/CHANGELOG/Cargo.toml (77),
  AGENTS.md (85), and the .opencode/agents prompts (109)
- Fenced content follows the precedent: comments, ASCII-diagram label
  separators, and template placeholders rewritten; wire data, JSON/BAST
  documents, byte diagrams, and transcripts survive verbatim; assert,
  expect, panic, error-display, and format message literals rewritten
  as prose; no code, fixture, or test data change
- src/rfc1928/LICENSE: the two dashes in alksocks' own provenance
  header rewritten; the MIT legal text untouched
- AGENTS.md adds Project Convention 18: no em dashes in prose; varied
  restructure, no spaced-hyphen substitutes, fenced prose rule, en
  dash numeric ranges exempt, docs/reviews/ exempt from the greps
- tasks/*.md frontmatter: the name values rewritten by the sweep are
  now quoted (a raw colon inside an unquoted YAML scalar parsed as
  null); taskgraph validate reports 37 tasks, no issues

Verification: cargo test; cargo clippy --all-targets -D warnings;
cargo fmt --check; cargo doc --no-deps; fuzz corpus replay
(cargo test --manifest-path fuzz/shared/Cargo.toml); wasm check and
clippy for wasm32-unknown-unknown with -D warnings; em dash grep over
the repo returns matches only in docs/reviews/ and the bast.md BAST
JSON data fence
2026-11-03 19:31:53 +00:00

3.0 KiB

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, the ownership posture in ADR-013)

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.
  • 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)