docs: Phase 0 converged — scope pinned to socks+channels, recommended approach written
- Scope resolution: the quinn/noq AsyncUdpSocket client wrapper (component 3) transfers to the alknet rewrite (its ancestor work — ADR-090, quinn-proxy POC — lives there; it consumes no channels and has no consumers planned here). OQ-SK-06 and would-be POC #3 go with it. alksocks = the producer/consumer pair only. - Convergence section added (Phase 0's output for the Architect): the validated approach pieces (fast-socks5 typestate driven directly for both commands, the handle-swap wire shape, DialFn + EgressFactory egress seam, "both" auth split by the door, alktty/alktunnels layering, vendored-subset fork posture) and the list of Phase 1 ADR decisions with their collected inputs (datagram framing, demux vs phase, params/ALPN, scope convention, door mapping, wasm posture). - Checklist: OQ-SK-06 resolved-by-transfer; POC list complete (#1/#2/#4 passed, #3 dropped); convergence checked off.
This commit is contained in:
+112
-7
@@ -53,6 +53,20 @@ Components 1+2 form the producer/consumer protocol pair (channels in,
|
||||
RFC 1928 inside); component 3 is standalone and composes with any
|
||||
RFC 1928 server. Keep them structurally separate in the crate layout.
|
||||
|
||||
**Scope resolution (2026-09-14, post-POC): component 3 moves to the
|
||||
alknet rewrite.** The QUIC-runtime client wrapper's natural home is
|
||||
alknet — it is alknet's own ancestor (ADR-090 + the quinn-proxy POC
|
||||
live there), it neither produces nor consumes channels, and the
|
||||
planned alknet rewrite is where downstream clients (iroh privacy
|
||||
posture) will actually consume it. That pins alksocks' scope to the
|
||||
producer/consumer pair only: **socks + channels.** Consequence: the
|
||||
OQ-SK-06 noq research (and its would-be POC #3) transfers to alknet's
|
||||
Phase 0; the quinn 0.11 variant is already proven there
|
||||
(quinn-proxy POC). This crate's client-side story reduces to the
|
||||
channels-native consumer session (`Socks5Stream::use_stream` over a
|
||||
`BiStream` — POC #1) plus the wrapper-aware associate session (POC
|
||||
#2) and the optional front doors.
|
||||
|
||||
Guiding principles, inherited from the alk* family:
|
||||
|
||||
1. **"ALPN as a service," not "a server."** The SOCKS5 service is a
|
||||
@@ -737,6 +751,17 @@ Questions:
|
||||
This is a research question first (read noq's endpoint/driver loops;
|
||||
write the trait-shape comparison), then possibly a POC (OQ-SK-07 #3).
|
||||
|
||||
**Resolved by the scope decision (2026-09-14, §Vision): transferred to
|
||||
the alknet rewrite.** The client wrapper is alknet's ancestor-shaped
|
||||
component (ADR-090 + quinn-proxy POC already live there), consumes no
|
||||
channels, and has no consumers planned inside this crate — so its
|
||||
research questions (noq trait-shape comparison, dependency posture,
|
||||
ECN/MTU carry-over) move to alknet's Phase 0 wholesale. This crate's
|
||||
client-side story is complete without it: the channels-native consumer
|
||||
session is POC-validated (POC #1's `use_stream` over a `BiStream`,
|
||||
POC #2's associate session). The noq POC (OQ-SK-07 #3) is dropped from
|
||||
this crate's POC list accordingly.
|
||||
|
||||
### OQ-SK-07: POC scope for what remains unvalidated
|
||||
|
||||
Candidates, in rough priority order (per the SDD process's "validate
|
||||
@@ -789,6 +814,10 @@ promising approaches"):
|
||||
(the `create_sender`/`Box` shape changes) before the client spec is
|
||||
written. (The quinn variant is already proven by the quinn-proxy
|
||||
POC — re-validating it here is optional.)
|
||||
**Dropped from this crate (2026-09-14, the scope decision):** the
|
||||
client wrapper transfers to the alknet rewrite (§Vision) — OQ-SK-06
|
||||
and this POC go with it. This crate's POC list is complete
|
||||
(#1, #2, #4 all passed).
|
||||
4. **fast-socks5 wasm check** — minimal crate, `cargo check --target
|
||||
wasm32-unknown-unknown`, confirm/inflect OQ-SK-04. Cheap; can fold
|
||||
into #1's worktree. **Run 2026-09-13 — fork-minimality verified**
|
||||
@@ -895,11 +924,87 @@ Candidate reading for the research specialist (to be expanded):
|
||||
sense for alksocks?") now reduces to the adapter-story input
|
||||
- [ ] OQ-SK-05 (target policy) — folded into the OQ-SK-01 decision;
|
||||
scope-gate convention pinned in Phase 1
|
||||
- [ ] OQ-SK-06 (noq client) — research pass (trait-shape comparison,
|
||||
dependency posture) + POC #3 if the research is not decisive
|
||||
- [x] OQ-SK-06 (noq client) — **resolved by the scope decision
|
||||
(2026-09-14, §Vision): transferred to the alknet rewrite**
|
||||
(the client wrapper is alknet's ancestor-shaped component,
|
||||
consumes no channels, has no consumers planned here); its
|
||||
research questions move to alknet's Phase 0; this crate's
|
||||
channels-native client story is POC-complete without it
|
||||
- [x] Targeted POC(s) run + summaries in `docs/research/`
|
||||
(OQ-SK-07 #1 + #4 complete, `poc-connect-wasm-findings.md`;
|
||||
#2 UDP ASSOCIATE complete, `poc-udp-associate-findings.md`;
|
||||
#3 noq remains)
|
||||
- [ ] Converge: recommended approach written up, ready to hand to the
|
||||
Architect for Phase 1
|
||||
(all three complete: #1 + #4 in `poc-connect-wasm-findings.md`,
|
||||
#2 in `poc-udp-associate-findings.md`; #3 dropped with the
|
||||
scope decision)
|
||||
- [x] Converge: recommended approach written up, ready to hand to the
|
||||
Architect for Phase 1 (§Convergence, 2026-09-14)
|
||||
|
||||
## Convergence — the recommended approach
|
||||
|
||||
This is Phase 0's output: a clear WHAT/WHY with validated approaches,
|
||||
ready for the Architect.
|
||||
|
||||
### The crate, scoped
|
||||
|
||||
**alksocks = the SOCKS5 producer/consumer protocol pair on alkcall
|
||||
channels (socks + channels, nothing else).** The three-component split
|
||||
resolved: components 1+2 are this crate; component 3 (the quinn/noq
|
||||
`AsyncUdpSocket` client wrapper) moves to the alknet rewrite, where
|
||||
its ancestor work (ADR-090, quinn-proxy POC) already lives. No local
|
||||
binds except the two explicit, optional, feature-gated assembly shapes
|
||||
(producer's local backend; consumer's front door).
|
||||
|
||||
### The recommended approach (validated pieces → crate shape)
|
||||
|
||||
- **Protocol base: fast-socks5's explicit typestate API** — the
|
||||
`T: AsyncRead + AsyncWrite + Unpin` genericity carries both
|
||||
substrates (POC #1: a channels `BiStream` drops in directly; the
|
||||
local backend would feed a `TcpStream`). Drive the typestate
|
||||
directly for UDP ASSOCIATE (`run_udp_proxy_custom` is unusable —
|
||||
unconditional kernel bind; file the upstream ask).
|
||||
- **Wire shape: the handle swap** (POC #2-validated) — one ALPN
|
||||
(`alk/socks5`), one open op (`channels/socks5/sub`), trivial
|
||||
params; the RFC conversation is the data plane; CONNECT =
|
||||
`pump_bidi` pass-through post-reply (POC #1); ASSOCIATE = the
|
||||
`select!`-driven datagram stage over `[len: u16 BE][addr + data]`
|
||||
frames (alktunnels' length codec; RSV/FRAG only at front doors;
|
||||
channel EOF ends the association; per-datagram addressing, no flow
|
||||
table).
|
||||
- **Egress seam: the dial-callback shape, extended** — `DialFn` for
|
||||
CONNECT (POC #1's command-read interception point) +
|
||||
`EgressFactory` for ASSOCIATE (POC #2), both function-not-trait,
|
||||
both returning boxed halves. Local-socket and composed
|
||||
(per-target alktunnels udp-tunnels) providers are assembly-layer
|
||||
policies; the composed variant's per-destination open cost is
|
||||
measured (~0.8 ms) and its per-target-ACL-for-free benefit is
|
||||
validated.
|
||||
- **Auth: "both," split by the door** (OQ-SK-02's settled posture) —
|
||||
producer side: the alkcall identity seam only (the in-band
|
||||
conversation runs NoAuth); the consumer's front door owns RFC 1929
|
||||
for vanilla clients and maps credentials to the channel identity.
|
||||
- **Layering: the alktty/alktunnels precedents** — substrate-agnostic
|
||||
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
|
||||
fork posture for fast-socks5 is vendoring the `T`-generic subset
|
||||
into this crate gated behind a `net`-shaped feature (POC #4:
|
||||
~120 cfg lines, wasm-clean subset functionally complete).
|
||||
- **Open for Phase 1 ADRs** (inputs collected, decisions pending):
|
||||
the demux-vs-phase extensibility trade (evidence now favors the
|
||||
phase model — no in-band control vocabulary was needed across both
|
||||
POCs); the params-format/ALPN naming ADRs (wire-stable once
|
||||
published, no consumers exist yet); `SOCKS5_OPEN_SCOPE` convention;
|
||||
the door's credential→identity mapping shape; the wasm decision
|
||||
(Case 1 vs Case 2) once the adapter story is confirmed.
|
||||
|
||||
### What Phase 0 could NOT answer (handed to Phase 1)
|
||||
|
||||
- The datagram-framing ADR (the one-way door) — now has empirical
|
||||
ground: framing validated, LRU/dedup semantics pinned, open cost
|
||||
measured. Decide with the first consumer in sight.
|
||||
- The wasm root question (OQ-SK-04) — mechanism de-risked; the
|
||||
adapter-story input is a product decision, not a research one.
|
||||
- Target-policy shape (OQ-SK-05) — the dialer-refuses shape is
|
||||
evidence-backed; the declarative-allowlist variant stays a Phase 1
|
||||
choice.
|
||||
- BIND — RFC-refused in both POCs, out of scope until a use case
|
||||
exists (the no-bind principle makes it structurally odd here; a
|
||||
producer-side BIND wants the accept-side shape, not a dial).
|
||||
Reference in New Issue
Block a user