docs: record the upstream graduation landing (alkcall 0.8.0, alktunnels 0.2.0)

The ask ledger's two alktunnels items landed 2026-09-18/20 — superseded
in shape, not implemented as posed. The graduation (alktunnels
tunnels-graduation.md -> ADRs 007/008) adopted the ssh
forwarded-tcpip-shaped alternative over the per-ask carriers.

phase-0.md:
- settled-foundations: establishment gains the reply-projection note
  (ADR-049 amendment 3); the relay/hub note records the in-tree
  ChannelRelay/HubLegTemplate (ADR-051); identity-seam note marked
  current at 0.8.0
- OQ-SK-01: Option A updated — the direct op (channels/tunnel/direct,
  ADR-007) is the dynamic-target channel; POC #5's scope-gate +
  ADR-007 rationale point the same way (separation lives at the ACL)
- OQ-SK-03: composed egress's vehicle is open_direct +
  Substrate::Udp; the ~0.8 ms measurement carries over; the stale
  POC-candidate hunch paragraph updated
- OQ-SK-08: the landed note — ask #1 dissolved (bind-first establisher;
  the real bound rides the open reply; POC #5's open-rides-the-accept
  workaround + the 10s-bound finding retire), ask #2 landed at the
  wire's native moment (forwarded op's {listen, substrate, peer}
  params), correlation token per ADR-008 Amendment 1
- convergence: egress seam composes against 0.2.0; the upstream-asks
  bullet records the landing per crate; the BIND hand-off bullet notes
  variant 2 is now fully vanilla-fidelity
- checklist OQ-SK-08 item + POC #5 register entry point at the landed
  note

poc-bind-findings.md: ledger statuses appended (superseded in shape;
evidence stands as the alktunnels-0.1.0 record)

AGENTS.md: alkcall pin 0.7.1 -> 0.8.0 (reply projection noted);
architecture context: alktunnels v0.2.0 entry added, alkcall 0.8.0
surface listed

Verified against the repos: alkcall 0.8.0 changelog (U-1/U-2/ADR-051),
alktunnels 0.2.0 changelog + ADR-007/008 + exports
(bindfirst_establisher producer.rs:641, register_tunnel_bindfirst_
openable :924), fast-socks5 still 1.0.0 with no net feature (the
courtesy tail). Docs-only change; no build surface affected.
This commit is contained in:
glm-5.3-flash committed 2026-09-20 09:49:08 +00:00
1 parent cb4d58a2bf
commit cb553ea033
3 files changed
+230 -51

No files matched your search

+171 -40
View File
@@ -1,7 +1,9 @@
---
status: draft
last_updated: 2026-09-15 (POC #5 BIND passed — OQ-SK-08 POC-validated,
POC register closed, alktunnels ask ledger pinned at two items)
last_updated: 2026-09-20 (the graduation landed upstream: alkcall 0.8.0
— reply projection, flavor-form discovery, ADR-051 relay; alktunnels
0.2.0 — ADR-007 direct op + ADR-008 bind-first/forwarded, superseding
the BIND ask ledger's shape; ask-ledger statuses updated)
---
# alksocks — Phase 0 (Exploration)
@@ -134,28 +136,43 @@ not start from zero. It inherits:
two-pump shape; `alkcall::channels::pump_bidi` (ADR-050) is pinned
upstream and alktunnels-validated. Use it; do not hand-roll.
- **The establishment story** — session opens use
`register_openable_with_establisher` (alkcall ADR-049 + amendment 2):
`register_openable_with_establisher` (alkcall ADR-049 + amendments):
the establisher runs as an awaited, bounded establishment phase; a
refused session is a typed `channel:open_failed` call error
(`reason ∈ dial_failed / unknown_resource / resource_shortage /
handler_error / timeout`), never a phantom channel. The negotiate/
auth half of the RFC conversation still runs in-stream over the
`BiStream` — establishment covers only the producer's accept policy,
not the RFC handshake.
not the RFC handshake. **Updated 2026-09-18 (alkcall 0.8.0, ADR-049
amendment 3): the establisher can project reply fields** —
`Establishment::with_reply_field(s)` merged into the open reply,
consumable via `ChannelClient::open_channel_with_reply`. This is the
carrier alkcall review 008 built for alktunnels' bind-first `bound`
address; a SOCKS5 establisher that ever needs to return open-time
metadata has the same seam (additive; absent fields leave the reply
byte-identical).
- **The producer/consumer model** — producer registers openable channels
(authorization for free via `AccessControl`); consumer opens them via
`ChannelClient` (alkcall ADR-037, ADR-043). Connection direction is
independent of service direction.
- **The relay/hub story** — a SOCKS5 resource traverses alkcall hub
relays like any produced resource; the hub's terminate-and-re-produce
proxy (alktunnels' refinement of alkcall ADR-042) applies per hop, and
a SOCKS5 resource is exactly the "further downstream" shape alktunnels
described. No socks5-specific relay work.
- **The identity seam** — alkcall 0.7.0's CF-005/CF-006: the per-call
proxy applies per hop, and a SOCKS5 resource is exactly the "further
downstream" shape alktunnels described. No socks5-specific relay
work. **Updated 2026-09-18: the relay machinery is in-tree** —
alkcall 0.8.0 ships `ChannelRelay` + `HubLegTemplate` (ADR-051, the
review-008 bonus), so a hub leg is an install-template composition,
not assembly-layer hand-rolling; relayed replies carry extra fields
through per-hop-truthfully (the bind-first `bound` flows
end-to-end), and flavor-form ops (the direct op's
`channels/tunnel/direct` shape) re-produce as channels, not
forwarding stubs.
- **The identity seam** — alkcall's CF-005/CF-006 (0.7.0): the per-call
opener identity arrives on the open-op hooks. Auth mapping (identity →
SOCKS5 credentials/ACL, if any) happens there, not via in-band SOCKS
auth, unless RFC-facing username/password is needed for vanilla SOCKS5
clients (OQ-SK-02).
clients (OQ-SK-02). Still current at alkcall 0.8.0 — the 0.8.0
additions (reply projection, relay) are additive and do not touch it.
- **The backend inversion point pattern** — substrate-specific types
confined to feature-gated backend modules, injected at the assembly
layer (alktty `TtyBackend` / alktunnels no-trait precedent).
@@ -376,6 +393,16 @@ target dial must happen *somewhere*. Options:
channel naming the target, and the two-pump data plane is
tunnel-channel ↔ SOCKS5-`BiStream`. Maximum composition ("further
downstream" made literal), but adds a runtime dependency and a hop.
**Updated 2026-09-16 (alktunnels 0.2.0, ADR-007): the dynamic-target
channel exists** — the direct op (`channels/tunnel/direct`,
`{substrate, target}` params, the ssh `direct-tcpip` shape,
`tunnel:direct` a separate ACL grant). Option A no longer needs a
pre-registered per-target resource: the SOCKS5 handler's dial
callback opens one direct-op channel per CONNECT target (per the
graduation research, this is exactly what the direct op was
graduated *for*). The udp substrate rides the same op — which also
simplifies OQ-SK-03's composed-egress vehicle below (one op, both
substrates).
- **Option B: dial directly** — the producer dials the target itself
(`TcpStream` behind the `local` feature, or an injected dial
callback). No alktunnels dependency; the dial policy (allowlists,
@@ -395,7 +422,14 @@ whatever is decided must not *prevent* A when composing. Hunch: a dial
callback/trait at the protocol layer, with alktunnels and local-TCP
providers feature-gated — but alktunnels' no-trait precedent warns
against a trait unless two real implementations converge; decide with
the Phase 1 spec.
the Phase 1 spec. POC #1 resolved the shape empirically in this
crate's layer (dial callback at the command-read interception point,
boxed halves, no trait); the A/B choice above it is now an
assembly-layer policy question — POC #5's scope-gate finding
(`socks5:bind` ≠ `socks5:open`) plus ADR-007's own rationale
("dial `postgres-primary`" vs "dial anything" are different grants)
both point the same way: separation lives at the ACL, not in the
protocol.
### OQ-SK-02: Auth mapping — identity seam vs in-band SOCKS auth
@@ -567,6 +601,19 @@ what gets each datagram to `addr`?
governing the udp-tunnel resource governs egress per destination
(dissolving most of OQ-SK-05 for the composed path), and hub
relaying is per-target terminate-and-re-produce.
**Updated 2026-09-16 (alktunnels 0.2.0, ADR-007): the composed
form's vehicle is now the direct op** — `TunnelSession::open_direct`
with `Substrate::Udp` dials a real UDP target through the same
dynamic-target op (`channels/tunnel/direct`), pinned by alktunnels'
own `open_direct` + `Substrate::Udp` test (a real UDP echo through
the establisher path). The lazy
destination→tunnel table's shape is unchanged — each entry is a
direct-op channel instead of a named-resource channel; the
per-destination ACL question shifts to the `tunnel:direct` grant +
the dialer's target policy (the ACL governs the capability, the
dial callback governs per-destination checks). POC #2's ~0.8 ms
per-destination open-cost measurement carries over (same op
mechanics; the direct op adds no round trip).
Both variants are dial-callback policy (OQ-SK-01's shape) — nothing in
the fork or the protocol layer sees the difference. **No upstream ask
@@ -609,17 +656,18 @@ datagrams. Hunch: phase model (simpler, RFC-shaped); the extensibility
argument is the honest case for the demux if Phase 1 wants the
vocabulary. Decide via ADR with the first consumer in sight.
Hunch (datagram stage, updated 2026-09-13 by the handle swap):
Hunch (datagram stage, updated 2026-09-13 by the handle swap;
POC #2-validated 2026-09-14; composed-egress vehicle updated
2026-09-16 — see variant 2 above):
wrapper-aware client halves ride the same-channel `{addr, data}` frame
shape (one channel per association, per-datagram addressing in-band,
channel EOF = association lifetime); vanilla clients get UDP ASSOCIATE
only via the optional local front-door bridge. The remaining choice is
producer-egress policy (local socket vs per-target alktunnels
producer-egress policy (local socket vs per-target direct-op
composition) — a dial-callback question owned by OQ-SK-01, with the
composed variant's ACL benefit making it the hunch for the base crate's
composed story. But this is still the crate's largest unknown — a POC
candidate (OQ-SK-07 #2), decided by an ADR before the first consumer
(the datagram framing is wire-stable once published).
composed story. The datagram-framing ADR (the one-way door) is Phase
1's, with the first consumer in sight.
### OQ-SK-04: fast-socks5 wasm posture (blocks the wasm-clean invariant)
@@ -915,7 +963,9 @@ Candidates, originally in rough priority order (the order is historical
accept variants implemented, the scope gate works, the
address-first-vs-accept-first deadlock is resolved in shape
(reply#1 first, the tunnel open rides the accept future), and the
alktunnels ask ledger is pinned at two items).
alktunnels ask ledger is pinned at two items. **Ledger statuses
updated 2026-09-20** — see OQ-SK-08's landed note below: both
items superseded in shape by the bind-first/forwarded graduation.)
POC placement conventions (inherited from alktunnels): a POC that needs
code from this repo runs in a worktree/branch (`.worktrees/research/
@@ -927,11 +977,12 @@ regardless of where the code lives.
### OQ-SK-08: BIND — the accept-side command (use case found)
**Status: POC-validated (2026-09-15, POC #5 —
`poc-bind-findings.md`).** The shape space below is written as it
stood pre-POC; the POC resolved the design question (variants 1 + 2
implemented; the sequencing pinned) and pinned the ask ledger. The
remaining decision is Phase 1's ADR (ship in base crate? default
accept variant?).
`poc-bind-findings.md`); the ask ledger landed, superseded in shape
(2026-09-20, alkcall 0.8.0 + alktunnels 0.2.0 — see the landed note
below).** The shape space below is written as it stood pre-POC; the
POC resolved the design question (variants 1 + 2 implemented; the
sequencing pinned) and pinned the ask ledger. The remaining decision
is Phase 1's ADR (ship in base crate? default accept variant?).
**The gap, precisely:** fast-socks5 parses `TCPBind`
(`Socks5Command::TCPBind`, `lib.rs:91`) but every handler refuses it
@@ -958,7 +1009,8 @@ framing change — no one-way-door exposure).
**The mechanism — accept-side resources (the `-R` far-side listener
shape).** The consumer's `-R` path in alktunnels
(`register_tunnel_listen_openable` + `listen_establisher` +
`AcceptQueue`, `alktunnels/src/producer.rs:207,392`) proves accept-side
`AcceptQueue`, alktunnels 0.1.0's `producer.rs:207,392`; line numbers
shifted in 0.2.0 with the bind-first addition) proves accept-side
resources exist without forced binds; SOCKS5 BIND is their mirror
image: the producer-side listener (network B — the app server must
reach it) is the accept resource, each popped accept two-pumps against
@@ -1008,6 +1060,56 @@ scope gate (`socks5:bind`, checked at command dispatch from the
per-call opener identity) distinguishes ingress from egress and is
POC-validated.
**The asks landed — superseded in shape (2026-09-20, alkcall 0.8.0 +
alktunnels 0.2.0).** The graduation (alktunnels
`docs/research/tunnels-graduation.md` → ADRs 007/008) took the
ledger's *two asks* as evidence and adopted the ssh
`forwarded-tcpip`-shaped alternative over the per-ask carriers:
- **Ask #1 (learn the bound address without consuming an accept) is
dissolved, not implemented.** The bind-first establisher
(`bindfirst_establisher`, ADR-008 §1) binds during the
establishment phase — fast, no app-server dependency — so the
open-op reply natively carries the real OS-chosen bound address
(the `bound` reply field, projected via alkcall 0.8.0's
`Establishment::with_reply_field`, ADR-049 amendment 3; consumed
via `open_channel_with_reply` / `TunnelListener::bound()`). There
is no accept to avoid consuming: establishment = bind. This
*replaces* POC #5's pinned workaround ("reply#1 first, the tunnel
open rides the accept future") — the accept-first sequencing was a
workaround for the accept-first establisher, and the bind-first
shape removes the workaround's reason to exist. It also dissolves
POC #5's establishment-bound finding: the accept wait now lives in
the teardown-governed pump phase, so FTP-length BIND waits stop
resolving as spurious 10s-establishment refusals (ADR-008's stated
second win). The old accept-first surface (`listen_establisher` +
`AcceptQueue`) stays for the accept-as-open shape; both live in
alktunnels 0.2.0.
- **Ask #2 (peer metadata on accepted handles) landed at the wire's
native moment.** The forwarded op (`channels/tunnel/forwarded`,
ADR-008 §3) carries `{listen, substrate, peer}` params per accept —
the peer address rides the open-op params (deny-unknown,
schema-gated) rather than a `TargetHandle` field; `ForwardedOpener`
+ `make_forwarded_op_handler` are the serving side. `TargetHandle`
itself gained no peer field — the graduation chose the
forwarded-op shape over the §3 option-i carrier, superseding the
ledger's original framing.
- **Correlation key refinement (ADR-008 Amendment 1, 2026-09-18):**
the key binding forwarded opens to listeners is a producer-minted
u32 token (`listen` reply field + forwarded param), not the
originally-planned channel-ID key (unimplementable against the
landed handler surface).
Consequence for this crate's variant 2: the composed BIND path is
now *fully vanilla-fidelity* with no interim stand-ins — the factory
no longer carries an expected `bind_addr`, reply#1 advertises the
real `bound`, reply#2 carries the real peer, and no establishment
bound threatens long BIND waits. POC #5's findings remain accurate as
the record of what was validated against alktunnels 0.1.0; the
Phase 1 shape composes against 0.2.0 (`register_tunnel_bindfirst_
openable` + `BindFirstInjections`, or `TunnelListener` on the
opener side).
**Security boundary note:** BIND is an *inbound* listener — the
accept-side twin of arbitrary egress. Whatever ACL governs the socks5
resource now also governs who can mint listeners on the producer's
@@ -1171,8 +1273,10 @@ Candidate reading for the research specialist (to be expanded):
accept-side mechanism written; **POC #5 run 2026-09-15 —
passed** (the phase model extends end to end; both accept
variants implemented; the scope gate works; the ask ledger is
pinned); the Phase 1 ADR (ship in base crate? default accept
variant?) has empirical ground under it
pinned); **the ask ledger landed 2026-09-18/20 — superseded in
shape by the bind-first/forwarded graduation (see OQ-SK-08's
landed note)**; the Phase 1 ADR (ship in base crate? default
accept variant?) has empirical ground under it
- [ ] OQ-SK-09 (channel capacity) — new (2026-09-14): the proxy-
workload analysis written (wire change rejected; config is the
mechanism; in-channel port multiplexing considered and
@@ -1228,11 +1332,16 @@ binds except the two explicit, optional, feature-gated assembly shapes
- **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.
both returning boxed halves. Local-socket and composed 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. **Updated 2026-09-20: the composed providers
compose against alktunnels 0.2.0** — the direct op
(`channels/tunnel/direct`, ADR-007) is the dynamic-target channel
for CONNECT, and `open_direct` + `Substrate::Udp` is the composed
ASSOCIATE vehicle (both substrates, one op, one grant:
`tunnel:direct`); the hub-leg for relaying them is alkcall 0.8.0's
in-tree `ChannelRelay`/`HubLegTemplate` (ADR-051).
- **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
@@ -1255,16 +1364,30 @@ binds except the two explicit, optional, feature-gated assembly shapes
BIND's base-crate inclusion + default accept variant (OQ-SK-08);
the proxy-workload channel-cap recommendation (OQ-SK-09); the
virtual-subnet translation-layer shape (OQ-SK-05 addendum).
- **Upstream asks (we own both upstreams; file early, land there):**
fast-socks5 — the `net` feature gate (POC #4's ~120-line change),
the `run_udp_proxy_custom` unconditional-bind seam, and the
courtesy `new_reply` publication (the reply encoder is private;
POC #5 re-encoded it by hand). alktunnels — the one-version bump
ledger (POC #5's evidence, `poc-bind-findings.md` §Upstream-ask
ledger): (1) listen-addr inspection without consuming an accept
(OQ-SK-08 variant 2's address half), (2) accepted handles carrying
peer metadata (reply#2's fidelity half). First-real-consumer asks,
the alkcall E-01/E-02 precedent.
- **Upstream asks — landed (the first-real-consumer sweep paid off).**
The graduation (`alktunnels docs/research/tunnels-graduation.md`,
alkcall review 008) took every ask at once, in one-version bumps:
- **alkcall 0.8.0**: the establisher reply projection
(`Establishment::with_reply_field(s)` + `open_channel_with_reply`,
ADR-049 amendment 3 — the `bound` carrier) and flavor-form
open-op ids in discovery (ADR-047 amendment 3 —
`channels/tunnel/direct`-shaped ops re-produce through hub relay
as channels); plus the bonus in-tree `ChannelRelay` +
`HubLegTemplate` (ADR-051) — the hub re-produce machinery is
in-tree, not assembly-layer.
- **alktunnels 0.2.0 (ADRs 007/008)**: the direct op (dynamic-target
egress — reshapes OQ-SK-01 Option A and OQ-SK-03's composed
egress), the bind-first establisher + forwarded op (dissolving
both BIND asks in shape — see OQ-SK-08's landed note),
`TunnelListener`, and the `local` bind-first substrate half.
- **fast-socks5 (still open, courtesy)**: the `net` feature gate
(POC #4's ~120-line change), the `run_udp_proxy_custom`
unconditional-bind seam, and the `new_reply` publication (POC #5
re-encoded the reply wire form by hand). The BIND ledger never
had a fast-socks5 ask — the typestate fit with zero changes.
No asks remain blocking for this crate; the fast-socks5 items are
the courtesy tail (we own the upstream; POC #4's fork posture
covers them if wasm picks Case 1).
### What Phase 0 could NOT answer (handed to Phase 1)
@@ -1290,4 +1413,12 @@ binds except the two explicit, optional, feature-gated assembly shapes
ledger, and the scope gate. Deciding whether BIND ships in the base
crate (and which accept variant is default) is a Phase 1 ADR —
support is additive (old consumers still get the RFC refusal), so
nothing here is a one-way door.
nothing here is a one-way door. **Updated 2026-09-20:** the
upstream substrate for the composed variant landed — alktunnels
0.2.0's bind-first establisher + forwarded op (ADR-008) *dissolves*
both ask-ledger items in shape (the real `bound` rides the open
reply natively; the peer rides the forwarded params; the accept
wait is pump-phase, so no establishment bound). The pinned
"open rides the accept future" sequencing is retired as the
accept-first workaround it was; the Phase 1 ADR composes variant 2
against 0.2.0 with full vanilla fidelity.
+39 -1
View File
@@ -1,6 +1,7 @@
---
status: complete
last_updated: 2026-09-15
last_updated: 2026-09-20 (ledger statuses updated — the graduation
landed; both alktunnels asks superseded in shape)
---
# alksocks POC findings — channels-native SOCKS5 BIND
@@ -197,6 +198,43 @@ end-to-end (the same ownership lesson as POC #2's egress, mirrored).
## Upstream-ask ledger (the one-version alktunnels bump)
**Ledger statuses (2026-09-20 — the graduation landed).** The user's
standing note held: alktunnels 0.2.0 (ADRs 007/008, over alkcall
0.8.0) shipped in one version bump — but adopted the ssh
`forwarded-tcpip`-shaped alternative over the per-ask carriers, so
both asks are **superseded in shape**, not implemented as posed:
1. **Listen-addr inspection without consuming an accept — dissolved.**
The bind-first establisher (`bindfirst_establisher`, ADR-008 §1)
binds during establishment, so the open-op reply natively carries
the real OS-chosen bound address (the `bound` reply field via
alkcall 0.8.0's `Establishment::with_reply_field`, ADR-049
amendment 3; consumed via `open_channel_with_reply` /
`TunnelListener::bound()`). There is no accept to avoid consuming;
this ask's stand-in (the factory's carried `bind_addr`) is retired,
as is the POC's "open rides the accept future" sequencing
workaround — and the 10s establishment-bound finding dissolves with
it (the accept wait lives in the pump phase now). The
accept-first surface (`listen_establisher` + `AcceptQueue`) remains
in 0.2.0 unchanged for the accept-as-open shape.
2. **Accepted handles carrying peer metadata — landed at the wire's
native moment.** The forwarded op (`channels/tunnel/forwarded`,
ADR-008 §3) carries `{listen, substrate, peer}` params per accept;
`TargetHandle` gained no peer field — the graduation chose the
forwarded-op shape over this item's option-i carrier. Correlation
is a producer-minted u32 token (Amendment 1, 2026-09-18), not the
originally-planned channel-ID key.
3. **(fast-socks5, courtesy)** `new_reply` is private — publish it
(or a constructor) so embedders don't re-encode the reply wire
form. Also still open from POC #4: the `net` feature gate and the
`run_udp_proxy_custom` unconditional-bind seam. (Unchanged — the
courtesy tail; no fast-socks5 release has landed these as of
2026-09-20.)
The POC's evidence stands as the record of what was validated against
alktunnels 0.1.0; the Phase 1 shape composes variant 2 against 0.2.0
(`register_tunnel_bindfirst_openable` + `BindFirstInjections`).
The user's standing note: collect alktunnels additions so one version
bump ships them all. The POC ran against published alktunnels 0.1.0
(no fork needed — the listen surface is complete there), and the asks