---
name: m11-w3-progress
description: "M11-W3 shell tunnel (REQ-SHELL-4) — GATE PASS (doyle, CI 27595180782 green both runners + code-read); cleared to W4 Gateway-owner capstone (REQ-SHELL-5), bring shape for design-gate"
metadata: 
  node_type: memory
  type: project
  originSessionId: f6396b18-8552-45fc-a0e0-b42e4a96b2ae
---

**STATUS: W3 BUILD COMPLETE + pushed PR#16 @221c0e7, CI run 27595180782 (both runners).** 8 commits: T3.1 manifest @88a9548 · gate-fold @6462f16 · T3.2a hub @692f810 · T3.2b close-hook @fa9aa62 · T3.2c retentive backpressured NetHost streams @7bf91bd (doyle's lossless gate condition) · T3.2d broker-homed byte bridge Option-A @6f3065a · T3.2e open-hook+surfaces @41b715f · T3.3 E2E+int @221c0e7. REQ-SHELL-4 [doc,impl,unit,int] traceable EXIT 0; clippy/xtask green; FULL suite green local (spt-daemon 309 lib+integration, spt 157+E2E, zero regression). Evidence-land sent to doyle → AWAITING impl-gate on CI-green, then W4 (Gateway capstone, REQ-SHELL-5). W5 carries: tunnel + drive [twohost] rungs, ADR-0020 EVENT-exemption enumeration, on-LAN docs, subnet how-to. Design/build detail below is historical reference.

M11-W3 = shell TUNNEL (REQ-SHELL-4): opaque reliable-ordered byte stream, a 5th surface (NOT a typed channel), first consumer usbip URB. Branch `m11-shell-substrate`. doyle DESIGN-GATE = **GO** (2026-06-15).

**doyle gate (locked):** Q1 SINGLE tunnel per link (multiplex deferred). Q2 dedicated `spt shell tunnel <id>` (owner write-in/subscribe-out) + shell-side `api tunnel` raw-duplex verb. Q3 NEW raw `api tunnel` verb, NOT child-relay `api poll`. R1: online-gen/link-token stamp on held stream_id = crash-proof load-bearing leg (close_shell drop = mere cleanup); prove open→break→relink-fresh-gen→old stream_id inert in T3.3. R2: W3 same-node loopback proves MECHANISM only; cross-node-on-LAN real-Iroh = a W5 `[twohost]` rung beside the drive rung (NO loopback overclaim; docs say "mechanism proven same-node; cross-node-on-LAN is W5 [twohost]"). DOC: add tunnel to ADR-0020 `<EVENT>`-exemption enumeration (light, not new ADR). All logged in M11-PLAN T3.x/T5.x.

**Substrate = D4 net-stream** (exists, fits): `NetHost::open_stream(conn_id)` = broker-OWNED bidi QUIC stream (survives brain restart, ADR-0004 B); `brain.net_open_stream/net_stream_send/net_stream_subscribe`. Loopback conn cross-wires operator+peer rows in-process. Same machinery `request_shell_link` rides; tunnel keeps it open + opaque. Shell-link itself is REQUEST/REPLY per-action (no held link-conn).

**LANDED (commits on branch):** T3.1 manifest `[shell.tunnel]` (enable+protocol label, validate) @88a9548 · plan gate-fold @6462f16 · T3.2a broker `TunnelHub` registry + control channel (`crates/spt-daemon/src/tunnelhub.rs`, holds owner_stream+shell_stream+token per shell, token-gated resolve = R1, 5 unit tests) @692f810 · T3.2b `close_shell` fires `tunnel_clear` @fa9aa62. REQ-SHELL-4 active `[doc,impl,unit]`, traceable EXIT 0, clippy workspace green. (Plus @8efaf76 W5 subnet how-to carry.)

**NEXT (resume here):** T3.2 OPEN-hook + the bridge. Open hook at `api bind-shell` (`crates/spt/src/api/mod.rs:327`, shell-online site) — if manifest tunnel-enabled, open the loopback stream + register in TunnelHub. THE HARD PART: dispatch (`dispatch.rs:206-214`) claims peer rows by FIRST-RECORD content demux (`kind=request`→shell-link); a bytes-less peer row isn't claimed. Tunnel needs (1) a new first-record classification `kind=tunnel`, (2) a `serve_tunnel` relay loop that BRIDGES the held QUIC stream to the EXTERNAL `api tunnel` surface (mock shell-side is an api caller, not an internal serve) — broker-buffered in/out byte queues per shell. serve_attach (`attach.rs`) is the closest bridge template. Then `spt shell tunnel` CLI (mirror cli.rs shell drive ~5660) + `api tunnel` verb (mirror api drive-poll). Then T3.3 same-node mock E2E (opaque `<EVENT`-looking bytes byte-exact round-trip + link-break close + R1 stale-stream-inert) → activate REQ-SHELL-4 int. Then W4 Gateway capstone, W5 rig+docs (incl tunnel+drive [twohost] rungs, ADR-0020 cross-ref, subnet how-to).

Pre-flight every commit: `cargo clippy --workspace --all-targets -D warnings` + `traceable-reqs check` (EXIT 0) + `cargo run -p xtask -- check`; schema regen = `SPT_BLESS=1 cargo test -p spt-runtime checked_in_schema_is_current` (NOT the `manifest_schema` filter — that misses the bless test). Any CLI add → `cargo run -p xtask -- gen` + no milestone/REQ codes in clap help. See [[m11-w2-progress]] [[broker-is-daemon-state-anchor]] [[cli-command-docs-drift]].

---
**doyle GATE VERDICT (2026-06-15): W3 PASS.** Independently verified — read tunnel code @221c0e7 + confirmed CI run 27595180782 myself (conclusion=success, all 5 jobs both runners; test Linux 5m4s post-reflake). All conditions hold: broker-homed TunnelHub (Option A); R1 no-stale via opening-link-token stamp (crash-proof, mirrors W2 drive); frame-loss fix exactly as conditioned (retentive append never evicts + await_ring_room parks pump at retentive_cap → flow-control lags SENDER → lag-never-loss/bounded/no-OOM; non-tunnel no-op); close_shell tunnel_clear; tunnel_e2e 200KB multi-write byte-exact BOTH dirs + NUL/<EVENT-opacity + link-break close + R1 no-stale-across-relink; backpressure unit bounded+lags+lossless. **FLAKE:** first CI RED = attach_survives timeout 240s on kitsubito (slow shared box, contention incl my docs ci.yml) — W3-independent, all tunnel tests green both runners; todlando FLAKE-LEDGER #7; rerun --failed cleared. **W5 CARRIES (5):** drive [twohost] + tunnel [twohost] rungs + how-to subnet + ADR-0020 tunnel-exemption enumeration + on-LAN docs. **todlando CLEARED to W4** (Gateway-as-owner capstone REQ-SHELL-5, proof-not-change ownership audit) — brings SHAPE → I design-gate. M11 waves still ride next merge+tag (counter 15, unreleased).

**W4 DESIGN-GATE = GO (doyle, 2026-06-15).** Q1 same-node · Q2 distinct unit + int · Q3 new file `tests/gateway_owner_shell_e2e.rs`. CRUX REFINEMENT (gate-blocking): exclusivity negative = SAME-TYPE DIFFERENT-ID owner (gateway-B refused), NOT a different-type refusal — that's what isolates id-from-type. Positive = gateway-A succeeds on spawn/bind/cmd/drive/tunnel/relink. Proof-not-change (expect 0 prod diff; a real type-gate on any path → surface loud + fix). Optional: one REQ-CONSENT-3 gated cmd under gateway-A keys grant on owner id. Reuse tunnel_e2e's broker-with-NetHost harness (W4 tunnel path needs broker.net()). Full gated build plan in the commune handoff + this session's project-context. Build NEXT (fresh context).
