Files
alkssh/tasks/implementation/w3-tunnel-direct.md
T
glm-5.3-flash 6443feac3e feat(tunnel): land the route-1 bridge — direct-tcpip + streamlocal served for real (w3-tunnel-direct)
- The route-1 bridge (ADR-006 decision 1, the POC-3 stage-C recipe
  re-landed as contract): per accepted `direct-tcpip` /
  `direct-streamlocal` open, the target/substrate are constructed from
  the SSH open arguments and the spawned task runs
  `TunnelSession::open_direct` over the held `Arc<ChannelClient>` →
  accept only after the fabric open succeeds → `take_halves()` pumped
  against the taken channel (`pump_bidi`) — the open hook returns fast;
  a fabric failure answers the explicit `ConnectFailed` reject (the
  wave-2 stub's reason surviving as the real decline; the stub retired
  from the direct rows, kept on `forwarded-tcpip` for w3-tunnel-listen).
- The cap across the fabric window (recorded): the admission is taken
  at the hook and held across the fabric open; a fabric failure
  releases the count inside the spawned task — the admitted-but-
  rejected shape no `channel_close` can ever fire for. `ChannelCap`
  became a mutex-backed `Arc`: admissions stay packet-loop-only,
  releases have exactly two disjoint sites (close hook, bridge task),
  both saturating.
- The identity ride recorded (the `w2-auth-bridge` parked item): the
  alkhub `hub_leg.rs` one-time-set precedent is a serving-side set; the
  client-side `take_call_connection()` seam is rejected for this door
  (one-shot detach of the shared assembly handle's open surface — a
  fortiori the relay note's "wrong for hubs"); the identity the fabric's
  `AccessControl::check` consults is the dial identity (CF-005), the
  composition is assembly policy, and the door structurally refuses
  anonymous serving (`no-identity`, unreachable on the wire). Upstream
  ask booked for the gate.
- The OQ-11 runtime-Unix gate: `direct-streamlocal` compiles wherever
  `tunnel` compiles; off-Unix a clean open-decline before any fabric
  call (dial-call witness at zero), on-Unix the real bridge.
- Decline classes recorded: policy → `AdministrativelyProhibited`
  (unfeatured/cap/`no-identity`); cannot-bridge → `ConnectFailed`
  (failed fabric open, absent handle under the feature, invalid
  target, off-Unix streamlocal); the event vocabulary gains
  `invalid-target` and `unix-unavailable`.
- The optional dep lands: `alktunnels 0.4.1` (pin re-verified against
  crates.io — max stable, MIT OR Apache-2.0, rust_version 1.88, alkcall
  0.10.1 exact), wired `tunnel = ["dep:alktunnels"]`, `local` never
  enabled.
- The fabric double (`tests/tunnel_mapping.rs`): the POC-3 §C.4
  in-process recipe — `ChannelsAdapter` + `InstallChannelZero` + the
  alktunnels openables + a hand-rolled dial/dial-fail seam (in-process
  duplex targets keyed by the rendered string; the smoke's dial is real
  TCP). Rows: both-substrate serve round trips, fabric-failure,
  cap refusal + release + recovery, the fabric-ACL composed-gate
  witness, the CF-006 identity witness, the OQ-11 gate, and the
  `ssh -L` + curl real-tool smoke (conditional-skip posture, ran green).

Verification: `cargo test` rows green per feature build (default,
tunnel, git, session, git+session, tunnel+git, tunnel+session,
--all-features); `cargo clippy --all-targets -- -D warnings` ×2
(default + --all-features) clean; `cargo fmt --check`; `cargo doc
--no-deps` 0 warnings; `taskgraph validate` (26 tasks).
2026-10-29 03:23:20 +00:00

14 KiB
Raw Blame History

id, name, status, depends_on, scope, risk, impact, level
id name status depends_on scope risk impact level
w3-tunnel-direct Wave 3 — tunnel leg 1 (the route-1 bridge — direct-tcpip + streamlocal) completed
w3-tty-session
moderate medium phase implementation

Description

Land the tunnel branch's proven leg (ADR-006 decision 1) — the adapter-side route-1 bridge for direct-tcpip and direct-streamlocal (POC-3 stage C's shape, re-landed as contract):

  • The route-1 bridge — the tunnel_row_stub replaced with the real flow: per accepted open, the target/substrate are constructed from the SSH open arguments (direct-tcpip(host, port) → SubstrateAddr::HostPort + Substrate::Tcp; direct-streamlocal (socket path) → SubstrateAddr::Path + Substrate::Unix) and spawn the flow POC-3 proved: TunnelSession::open_direct(& channel_client, target, substrate) → accept only after the fabric open succeeds (accept consumes the handle — the reject shape is only possible pre-accept) → on fabric failure the explicit ConnectFailed reject (the stub's reason survives as the real decline; tunnel_seam_stub_decline retires into it) → on success take_halves() pumped against the taken channel's stream (pump_bidi — the alkcall primitive the POC recipe used) on the spawned task, per spawn-and-return. The open hook returns fast with the fabric open in flight.
  • The cap admission across the fabric window — the wave-2 stub declined without consuming a count; the real flow admits. Mechanics to get right (record): the admission is taken at the hook (the packet-loop single-writer site — no race window against the cap check) and held across the fabric open; a fabric failure must release the count inside the spawned task (the channel_close-hook release point only fires for established channels — a rejected open never established one), so a failed bridge cannot leak budget. Decide the release mechanism and record.
  • Identity propagation to the family fabric (auth.md §Server direction step 4 — the visible-surface invariant's gate): the resolved identity rides the channels connection so the fabric's AccessControl::check(peer_identity) gates the mapped opens. The parked wave-2 auth_succeeded item lands here: on auth completion the handler propagates once via alkcall's Connection:: set_identity — mechanics decided and recorded (the alkhub hub_leg.rs one-time-set precedent: ChannelClient:: take_call_connection() → set_identity(identity); check the take semantics against alkcall 0.10.1's docs — the relay note says the detach is wrong for hubs; verify a door's reading and hook placement, auth_succeeded vs the first seam call).
  • The runtime-Unix gate (OQ-11 — universal compile, clean open-decline off-Unix): direct-streamlocal compiles wherever tunnel compiles; off-Unix a clean open-decline before any fabric call (never a partial bridge); on-Unix the real bridge.
  • Contract rows through the harness, per build (the wave-2 gate's booked acceptor vocabulary note is the listen leg's — this task's rows ride plain client opens): a git/session build with tunnel off declines the tunnel opens (unfeatured, AdministrativelyProhibited); the featured rows: a configured tunnel handle (feature + Arc< ChannelClient>) serves, an absent handle declined with a clean error even under the feature (the unchanged unset-declines posture — the wave-1 config note), the cap rows (cap-gated before spawn — never a leaked count over a failed bridge: the release mechanism pinning row), and the ConnectFailed row over a refusing fabric double. The fabric double is the POC-3 §C.4 in-process recipe as test composition (ChannelsAdapter + InstallChannelZero + the alktunnels openables + a hand-rolled dial/dial-fail seam) — hand-rolled in tests/, never a sibling-checkout path.
  • The optional dep lands here (alktunnels = "0.4.1", wired tunnel = ["dep:alktunnels"] — first consuming code; crates.io pin re-verified before committing).
  • The real-tool smoke — one ssh -L (+ curl) through the harness against the fabric double (tooling posture decided like the git task — required vs conditional-skip, recorded).

Acceptance Criteria

  • direct-tcpip serves through the route-1 bridge: fabric open → accept → take_halves() pump on the spawned task; failure → the explicit ConnectFailed reject, the stub retired; the open hook returns fast
  • The cap admission across the fabric window pinned (admit at the hook, release on fabric failure inside the spawned task — no leaked count, no double-admit)
  • The identity propagates to the channels connection once (set_identity mechanics + hook placement decided and recorded); the wave-2 auth_succeeded item discharged
  • direct-streamlocal carries the runtime-Unix gate (compile-everywhere, clean open-decline off-Unix before any fabric call)
  • The per-build decline-matrix rows green through the harness (unfeatured/unset/fabric-failure/cap/serve classes), each with its contract stamp; the ssh -L smoke row
  • The alktunnels optional dep lands, pin re-verified; tunnel-off builds carry no alktunnels types in code paths
  • cargo test (+ per-feature + --all-features rows), clippy ×2 (-D warnings), fmt, cargo doc --no-deps pass

References

  • docs/architecture/mapping.md (the direct-tcpip / direct- streamlocal channel-type rows; §the structural constraint)
  • docs/architecture/decisions/006-mapping-bridge-and-dispatch.md (decision 1 — route 1; the reject shape; the wiring recipe pointer)
  • docs/architecture/decisions/003-feature-graph.md (the tunnel row, the OQ-11 runtime-Unix gate)
  • docs/architecture/auth.md §Server direction step 4 (set_identity, once), §Open questions (all resolved)
  • docs/research/poc-3-mapping-bakeoff.md §Stage C (the bridge + the failure shapes + §C.4 the fabric recipe + the identity witness)
  • alktunnels 0.4.1: consumer.rs:89-148 (TunnelSession::open, open_direct), consumer.rs:235-260 (take_halves), params.rs:105-126 (SubstrateAddr/TunnelDirectParams), error.rs (TunnelOpenError)
  • alkcall 0.10.1: channels/client.rs (take_call_connection), core/types.rs:541 (Connection::set_identity), channels/hub_leg.rs:217-220 (the one-time-set precedent)

Notes

Recorded at implementation time (2026-10-29). All decisions live in the module docs (src/tunnel_map.rs, src/channel_cap.rs, src/handler.rs) and are summarized here for the gate.

  • The cap release mechanism (the task's first decide-and-record) — ChannelCap became a parking_lot::Mutex<usize> shared as an Arc: admissions stay packet-loop-only (every admit call site is an open hook — the check-and-increment is one atomic section against the shared writer), while releases have exactly two disjoint sites — the channel_close hook for established channels, and inside the spawned bridge task on a fabric-open failure (the admitted-but-rejected shape: ADR-006 decision 1 rejects the open, so no CHANNEL_CLOSE can ever cycle back, and the count must be released where the failure is known — before the reject is answered, so the very next open observes the recovered budget). Both release sites saturate. Pinning rows: a_failed_bridge_releases_the_cap_count_before_the_next_open (failure-then-serve under max_concurrent_channels: 1 — a leaked count would answer AdministrativelyProhibited) and the_cap_refuses_beyond_the_ceiling_and_recovers_on_close (refusal + close-hook recovery).

  • set_identity mechanics (the task's second decide-and-record; the w2-auth-bridge parked item discharged) — the alkhub hub_leg.rs one-time-set precedent is a serving-side set (the hub resolves the peer identity and sets it on its accept-side channel-0 Connection inside the channel-0 install, before any dispatch). The client-side surface the task named (ChannelClient::take_call_connection() → CallConnection::connection() → Connection::set_identity) was checked and rejected for this door, verified against alkcall 0.10.1's docs: the take is a one-shot single-slot detach ("taking it detaches the client's own calling surface" — every later call_open_op, and with it every TunnelSession::open_direct, errors "channel client closed"), and the slot is the shared assembly handle (SshAdapter hands one Arc<ServeConfig> to every mounted session), so the first session's take would detach the open surface for every later session of the whole serving direction — the relay note's "the detach is wrong for hubs" applies a fortiori. The identity that alkcall's protocol consults at the fabric's serving dispatch is the channels connection's dial identity (CF-005: set once at dial, propagated to channel 0 at from_connection) — identity crossing the alkcall wire is not a protocol concept. Decision: the composition — which identity the fabric leg dials with, against which the fabric's ACL gates alkssh's mapped opens — is assembly policy (the assembly supplies both the injected IdentityProvider and the fabric leg); alkssh structurally refuses anonymous serving (the no-identity open guard, unreachable on the wire — russh authorizes before channels exist — fail-closed like the git/tty rows) so no SSH-shaped exception to the visible-surface invariant exists, and the harness rows witness the composed gate end to end: the_fabric_acl_refuses_an_unscoped_channels_identity (the fabric's AccessControl::check refusing a scopeless channels identity — the establisher never dialed) and direct_tcpip_serves_through_the_route_1_bridge's identity-witness assertion (the establisher's per-call auth seeing the channels identity — POC-3 §C.3). Hook placement: the identity store stays the auth_publickey ride-along in handler state; the tunnel rows' dispatch reads it; auth_succeeded stays unimplemented (russh default) — nothing rides it that the store does not carry. Upstream ask booked for the wave-3 gate: a non-detaching post-construction identity seam on ChannelClient (or per-session fabric legs) would let the door attach per-peer identities to a shared leg; nothing is silently absorbed.

  • Wire decline classes (recorded) — two vanilla-observable classes at the open: policy refusals → AdministrativelyProhibited (unfeatured, cap-exceeded, the no-identity guard) vs cannot-bridge → ConnectFailed ([dispatch::connect_failed_open_decline] — the wave-2 stub's reason surviving as the real decline): the failed fabric open, the absent fabric handle under the feature (seam-unconfigured, the unset-declines posture), an impossible wire target (invalid-target, an out-of-range port), and the off-Unix direct-streamlocal OQ-11 gate (unix-unavailable). The classes are distinguishable in the event vocabulary, which gained invalid-target and unix-unavailable.

  • Admission mechanics — the pre-admit decline classes are checked in order (unset handle → no-identity → invalid target), so every pure-decline path consumes nothing; the admission is taken at the hook and held across the fabric open; the success release rides the established channel's close. forwarded-tcpip kept its pre-admit has_room cap gate and stub — its -R data-leg flow is w3-tunnel-listen material (the harness's russh client cannot initiate the type; its wire rows are acceptor vocabulary).

  • The fabric double — the POC-3 §C.4 in-process recipe as test composition (wire_fabric in tests/tunnel_mapping.rs): ChannelsAdapter + InstallChannelZero + ChannelOperations + register_tunnel_direct_openable + Dispatcher::serve_single_stream over a tokio duplex, the connect side the Arc<ChannelClient> the serve-config holds. The hand-rolled dial/dial-fail seam is an in-process map of duplex halves keyed by the establisher-rendered target string (consume-once — the cap-recovery row reads the consume-once dial as its release signal), with an atomics call counter for the "never called" assertions (the ACL row and the OQ-11 row); the smoke's dial seam is a real-TCP closure (alktunnels' local feature stays off everywhere — the shipped crate and the tests).

  • The real-tool smoke — tooling posture decided like the git task (conditional skip with a printed reason when ssh/curl is absent), and it ran green here: one ssh -N -L (OpenSSH client) through a TCP-mounted adapter → the route-1 bridge → the fabric double with a real-TCP dial → a local HTTP endpoint, curled through the forwarded port (body parity asserted). 8/8 rows green in tests/tunnel_mapping.rs.

  • Pins re-verified against crates.io (2026-10-29): alktunnels 0.4.1 is max_stable_version/newest_version, MIT OR Apache-2.0, rust_version = 1.88 ≤ ours 1.89, alkcall 0.10.1 exact (single-versioned against our alkcall = "0.10"); wired tunnel = ["dep:alktunnels"], default-features = false (the local feature never enabled). tunnel-off builds carry no alktunnels types in code paths (dep-to-feature gating; verified by the per-feature test rows).

  • Verification (all green): cargo test (default + --features tunnel / git / session / git,session / tunnel,git / tunnel,session / --all-features), cargo clippy --all-targets -- -D warnings ×2 (default + --all-features), cargo fmt --check, cargo doc --no-deps 0 warnings, taskgraph validate (26 tasks).