- New tests/producer_forwarded_gate.rs (the establisher variant's pins;
the base shape's tests/producer_forwarded.rs untouched):
- gate miss: typed channel:open_failed with details.reason ==
unknown_resource, no phantom channel, the pump handler never runs
(the gate's invocation witness IS set — the miss is at the gate)
- gate pass: the base serving flow unchanged — parsed params
witnessed verbatim + full byte round-trip through the
establisher-registered variant
- residual race: gate pass + route gone at handler time → the
handler's error path reaps via teardown-at-birth (the base
correlation-miss semantics re-pinned under the established shape)
- scope-gate ordering: tunnel:forwarded-less identity is FORBIDDEN
and the gate closure is never invoked (ACL precedes the
establishment phase)
- the establisher malformed-params delta pinned: schema gates
unchanged (INVALID_INPUT); an unknown top-level field becomes a
typed channel:open_failed (reason handler_error) and the parse
precedes the gate
- No harness changes (wire_with + Topology.consumer_registry as-is)
- Verification: cargo test green (14 suites, 0 failures); clippy
--all-targets -D warnings native + wasm-target clippy clean (wasm
--all-targets cannot compile on this baseline — pre-existing,
mio/socket2 dev-deps do not target wasm; see the task Notes);
cargo fmt --check clean; cargo check --target
wasm32-unknown-unknown clean; --all-features test run green
Tasks: tunnels/corrmiss-gate-tests (status → completed)
Implements plan 003 W1's API item (ADR-008 Amendment 2, task
tunnels/corrmiss-forwarded-gate): the assembly-injected correlation
gate wrapped into the alkcall OpenEstablisher dance for the forwarded
op's serving half.
- ForwardedGate: sync gate closure over the parsed
TunnelForwardedParams; a gate Err → typed channel:open_failed
before the channel is born (no phantom channel)
- register_tunnel_forwarded_openable_with_establisher: reuses
make_forwarded_op_handler unchanged (additive-only; the base
registration stays byte-for-byte compatible as the
compatibility + residual-race-fallback posture)
- ForwardedPlan: empty marker plan payload (typed-opaque posture,
payload choice pinned); no reply-field contribution
- Establisher parse failure maps TunnelEstablishError::HandlerError
→ channel:open_failed (deliberately pinned improvement over the
base shape's silent birth-teardown for malformed ingress); gate
errors pass through the existing From<TunnelEstablishError> table
(no new variants; stale token = unknown_resource); timeout: None;
wrapper order (schema → ACL → allocate → establisher → handler)
pinned in the establisher doc
- Two-shape posture doc updates: make_forwarded_op_handler's
correlation-miss block, register_tunnel_forwarded_openable's doc;
wire.md §The Forwarded Op + tunnel_forwarded_spec() doc synced
per Amendment 2's "syncs with the API task's in-code doc updates"
Verification: cargo test (85 green, existing suite untouched);
clippy --all-targets -D warnings (native + wasm32); cargo fmt --check;
cargo doc --no-deps (0 warnings); --all-features test run green
- The serving side of the forwarded op gains an establisher variant:
an assembly-provided gate closure (over TunnelForwardedParams) the
crate wraps into the alkcall OpenEstablisher dance via
register_openable_with_establisher; a stale/missing listen token
fails the open as a typed channel:open_failed with
details.reason = unknown_resource — never a phantom channel
(ADR-049's posture extended to the forwarded op's serving side)
- unknown_resource reused as-is; the wire vocabulary is unextended
and wire.md is untouched (the empty wire delta stated explicitly)
- Gate order pinned: the tunnel:forwarded ACL precedes the
establisher (alkcall's open-op wrapper order)
- The residual post-open race keeps teardown-at-birth; canonical
event name correlation-miss at debug (assembly-side convention);
the producer-side generic arm stays warn with the typed reason
- Additive-only surface: the base register_tunnel_forwarded_openable
stays; the establisher variant is the recommended default posture
- Tri-vocabulary history recorded (alkssh correlation-miss/debug,
alksocks prose/warn, alktunnels handler_error-class generic
arm/warn + the fabric-side silence) with sources
- The amended §3 sentence is marked inline, not silently replaced
Resolves review 003 via docs/plans/003-correlation-miss-resolve.md
§Decisions 1-4 (W1's ADR bullet). Doc-only; review 003's status block
and wire.md belong to other tasks and are untouched.
Verification: md renders coherently (read back); alkcall 0.10.1
EstablishmentError/reason() mapping and wrapper order verified in the
registry source before pinning
- tunnels/corrmiss-adr: the ADR ink (establishment phase for the
forwarded op's serving side; unknown_resource reused; correlation-miss
adopted + level posture; the tri-vocabulary history recorded)
- tunnels/corrmiss-forwarded-gate: the additive API — ForwardedGate +
register_tunnel_forwarded_openable_with_establisher (candidate shape
verified against alkcall 0.10.0's establisher surface); the two-shape
doc posture
- tunnels/corrmiss-gate-tests: the four pins (typed gate miss / gate-pass
flow / residual race reaping / scope-gate-before-establisher order)
- tunnels/corrmiss-review: the checkpoint before the consumer waves
adopt the surface (the {W2, W3} fork's critical point)
- tunnels/corrmiss-doc-sync: review 003 status + plan checkboxes close-out
- tunnels/corrmiss-alkssh-adopt / corrmiss-alksocks-adopt: cross-repo
pointer tasks (executed in alkssh / alksocks), gated on the review
Ordering W1 → {W2, W3} per the plan; no cycles; W1's doc-sync closes
after the review checkpoint.
- N-3: parse-before-accept telemetry note on make_forwarded_op_handler
(the accepted-flag reads false for a malformed-params open by design)
- N-4: ADR-007 Consequences lines — the untagged-leniency-is-
schema-gated paragraph + the overlapping-variants caution
- N-2: ADR-008 §1 widened to name the any-byte idle-read posture
(the Ok(0)-only reading hangs on a write-happy peer)
- N-5: mint_token's doc comment records the 256-channel cap analysis
- The N-1/N-6/N-7 + G-1/G-3 no-action dispositions recorded in the
task file (the tracker the task asked for)
Verified: fmt, clippy (native + wasm32), test, cargo doc — all green
- D-1: wire.md's Direct Op + Forwarded Op sections record the shipped
schema constraints (port bounds, additionalProperties: false per
branch, listen minimum: 1) and the registry-side gate ordering
- D-2: ADR-007 §2 corrected in place + a dated erratum (oneOf was
wrong-shaped; validation is registry-side, not establisher-time);
wire.md's mirrored sentence corrected
Verified: cargo doc --no-deps clean; cargo fmt --check
- D-3: inline the serde-layer check into the renamed
serde_rejects_unknown_substrate_value; delete the overpromising
jsonschema_valid helper (the registry's real schema gate stays
pinned end-to-end by the integration probes)
- D-4: trim the stale Unreleased preamble to a one-liner (written
before the six graduation implementation commits landed)
Verified: cargo fmt --check; cargo clippy --all-targets -D warnings;
cargo test (86 + 2 doc-tests) green
- G-4: drive UnixListenerHalves::accept_loop — bind_unix + temp path,
the loop exits on the queue-closed handler error after one unix
client accept (the unix parity twin of the TCP accept-loop test;
closes the largest single uncovered block, local/mod.rs 591-609).
- G-5: pin ADR-008 §3's two fail-loud sentences — bind_unix("") is
the kernel autobind (no filesystem path) so local_addr fails loud
(578-583), and a socket2 autobind client against a NAMED listener
is refused by accept_pair's unnamed-peer guard (626-633; Linux —
abstract addresses/autobind are Linux-shaped, mio maps any
abstract-namespace peer to unnamed).
Verification: cargo test --features local green (162 tests);
clippy --all-targets -D warnings clean (native + wasm32-unknown-
unknown); cargo fmt --check clean.
- G-2: observe TunnelListener::close's explicit shutdown sentinel at
the far accept dispatcher — the accept loop cancels, the pushed
accept is never consumed, the serving-side listen channel reaps
(ADR-008 §1's teardown contract, graceful half).
- N-2 residue: pin the write-happy-peer teardown posture — a
non-empty read on the idle listen stream tears the listener down
(the fail-closed Ok(_) arm; driven via the raw client surface
since the typed listener holds its write half idle by contract).
Verification: cargo test --features local green (163 tests + 2
doc-tests); clippy --all-targets -D warnings clean (native +
wasm32-unknown-unknown); cargo fmt --check clean.
- BindFirstPlan gains substrate: Substrate, stamped at establisher
time from the one successful TunnelParams parse (one parse, one
source of truth; the plan-payload change is pre-consumer)
- make_bindfirst_accept_handler drops the second params re-parse and
the silent unwrap_or(Substrate::Tcp) fallback entirely — the
dispatcher reads plan.substrate; no fallback branch remains, so a
future drift cannot silently stamp Tcp into a UDP listen tunnel's
forwarded opens (the raw-vs-framed data-plane mismatch class)
- tests: forwarded_opens_carry_plan_stamped_substrate pins the plan
as the substrate's source over a real UDP bind-first wire flow
(a substrate-recording forwarded stub observes substrate: udp);
the unit downcast + establisher-flow tests pin the stamp
- docs: producer.md (the plan carries {listener, token, substrate};
the forwarded open's substrate also comes from the plan),
ADR-008 §1 (the stamp + the removed fallback)
- task review-002-m1-substrate-fallback: completed (Notes filled)
Verification: cargo test (145 pass), cargo test --all-features (153),
clippy --all-targets -D warnings (default + all-features), fmt
--check, doc --no-deps, wasm32 check + clippy -D warnings.
- M-1: the accept dispatcher's silent substrate fallback (plan-stamp
shape recommended; failure-path test required)
- D-3 + D-4: trivial batch (rename the overpromising schema test
helper; trim the stale CHANGELOG Unreleased preamble)
- D-1 + D-2: wire.md schema bounds + ADR-007 oneOf->if/then +
establisher-time -> registry-gate sentence (doc-only, pre-consumer)
- G-2 (+ N-2's write-happy-peer test): observe close()'s EOF sentinel
at the far accept dispatcher
- G-4 + G-5: unix accept-loop coverage + the unnamed unix fail-loud
guards (G-1/G-3/G-6/G-7 explicitly left uncovered per the review)
- N-1..N-7 recorder: the two durable-trail notes (N-3 telemetry
ordering sentence, N-4 ADR lines) + the no-action dispositions
All six independent (no depends_on) so sessions can parallelize;
validated with taskgraph (28 tasks, no cycles).
- src/consumer.rs: `TunnelListener` — the listen-flow sibling of
`TunnelSession`: `open` rides `open_channel_with_reply` (the U-2
surface, alkcall 0.8.0) and projects the bind-first `bound`/`listen`
reply fields via the lenient `listen_reply_fields`; `bound()` /
`listen()` present them (the Option posture — None for dial/
accept-first producers and old producers). Teardown ownership
(ADR-005's posture, listen-flavored): `close` (graceful — `shutdown`
on the held write half, the explicit EOF sentinel, then the sync
reap) and `Drop` (the held write half drops → the mux pump's
implicit-EOF chunk — the far accept dispatcher's teardown signal —
then the sync reap; never leaks). The held stream is the write half
(`MpscSendStream`) only, IDLE and private — a listen channel has no
data-plane role. No `Clone` (compile_fail doc-test).
`forwarded()` decided: NOT provided — the receipt queue is
assembly-side bookkeeping; the type hands the assembly the token.
- src/lib.rs: re-exports `TunnelListener`; crate docs mention the
listen-flow session.
- src/producer.rs: doc-fix drive-by — two pre-existing broken
intra-doc links (cargo doc is now 0-warning clean).
- tests/harness.rs: `wire_listener_bindfirst` + `ListenerTopology` —
the opener-dials shape (client + serving on the opener; bind-first
serving + the call-plane forwarded-open caller on the producer).
- tests/consumer_listener.rs: 5 integration tests — the bind-first
gate (reply fields + forwarded round-trip through the REAL
forwarded-openable registration + the teardown cascade), the Option
posture on a dial producer, close/Drop reaping (the leak-free
guarantee), the adopt-path pin (`adopt` gains nothing — a forwarded
channel presents the ordinary session semantics), and the scope
interaction (`tunnel:open`-only opener opens the listen channel;
forwarded opens to it fail FORBIDDEN).
- CHANGELOG: Unreleased → Added.
Verification: cargo test 132 passed (157 --all-features; doc tests
2/2 incl. both compile_fail asserts), clippy --all-targets -D warnings
clean (native + wasm32), fmt clean, wasm32-unknown-unknown check
passes (the default crate stays wasm-clean), cargo doc --no-deps clean.
- BindFn + BoundListener: the platform-boundary bind seam (the
protocol never binds, OQ-TN-04); the opaque listener rides the plan
- bindfirst_establisher: registry namespace gate -> token mint
(non-zero-seeded AtomicU32, per-open fresh, per-producer unique,
token 0 never minted — the wrap shape unit-pinned) -> bind ->
`bound` + `listen` reply fields -> the BindFirstPlan plan; the
typed errors pass through (bind failure dial_failed, exhaustion
resource_shortage, registry miss unknown_resource)
- BindFirstAcceptLoop: the type-erased accept closure (receives the
opaque listener; yields (peer, halves) per accept; Err is
loop-critical)
- ForwardedOpener: the per-accept forwarded-open caller — the call
plane (call_with_payload on channel 0 + manager.adopt_channel; the
reverse POC's open_reverse_channel shape)
- make_bindfirst_accept_handler: the accept dispatcher — accept_bi
first (R-02 telemetry), the idle listen-stream EOF sentinel cancels
the loop + tears the listener down (select!), per-accept pump_bidi
tasks tracked by the handler's JoinHandle (awaited on loop exit —
a forwarded pump never outlives its listener), per-accept failure
isolation (log + drop; v1 no retry), loop-critical accept errors
end the loop
- register_tunnel_bindfirst_openable: same spec + tunnel:open scope
gate (the per-registration establisher posture); the injected
seams ride BindFirstInjections {bind, accept_loop, open_forwarded}
(8-arg sketch -> the bundle; clippy too_many_arguments) + the
optional CF-006 identity witness (witness_establisher wrapper)
- harness: RegistrationMode::BindFirst + wire_bindfirst; the consumer
hook gained the accept-side identity propagation + a shared serving
registry (Topology.consumer_registry exposed); the forwarded-op
serving stub (make_forwarded_stub_handler — correlate by token,
accept the BiStream, pump_bidi against the correlated halves; the
opener-side registration lands with tunnels/forwarded-receipt)
- tests: 6 new integration tests (the full flow e2e — the acceptance
gate incl. the byte round-trip through the whole path, the
dial-open neither-field projection, EOF teardown, per-accept
isolation, typed establishment errors, token discipline) + 6 unit
tests (the mint discipline, the establisher flow at the
Establishment surface, the witness wrapper)
Verified: cargo test green (118 default; 138 --all-features), clippy
--all-targets -D warnings clean (native + wasm32), fmt clean,
wasm32-unknown-unknown check passes, cargo doc --no-deps clean.
tunnels/tunnel-listener + tunnels/forwarded-receipt used `scope: medium`
(not a valid variant — single/narrow/moderate/broad/system), which made
taskgraph silently drop both from the graph (validate failed; topo/
list missed them). tunnels/coverage-weak-spots used `status: done`
(pre-existing; valid variants are pending/in-progress/completed/failed/
blocked).
Verified: taskgraph validate (22 tasks), topo, cycles (none),
parallel, critical all resolve with the full graph.
Verification pass against the landed alkcall 0.8.0 surface surfaced one
design gap: ADR-008 §3 pinned the forwarded op's correlation key as the
listen channel's ID, but (1) the serving-side OpenHandler/establisher
surface never exposes the allocated channel ID, and (2) the in-tree
generic ChannelRelay forwards open-op params untouched (it rewrites
only the reply's channel_id), so a spoke's forwarded open would carry
an id the end opener never allocated. Amended (wire still unconsumed —
alksocks is docs-only — so pre-consumer and legal):
- ADR-008 Amendment 1: the bind-first establisher mints a fresh u32
correlation token per open — carried in the plan (for the accept
dispatcher) and contributed as the additive `listen` reply field
(the same projection carrier `bound` rides); the forwarded op's
params rename `channel` -> `listen` with token semantics. Tokens
ride reply fields + params through hubs untouched (relay-transparent
by construction, alkcall ADR-051). Consumer-minted tokens and a new
upstream handler surface were considered and rejected (rationale in
the amendment).
- Spec docs synced: wire.md (the `bound`+`listen` reply section, the
forwarded params), producer.md (bind-first shape + forwarded op),
consumer.md (TunnelListener gains `listen()`; correlation registry
posture), overview.md, OQ ledger (OQ-TN-16 updated),
tunnels-graduation.md.
Task decomposition (tasks/tunnels/, Phase 2 of the graduation — the
alkcall prerequisites are gone):
- direct-op — params/spec/establisher/open_direct (ADR-007)
- bindfirst-params — forwarded-op spec, TunnelListenReply, the
BindFirstPlan + token mint (wire types first, the params.md
ordering precedent)
- bindfirst-producer — bind-first establisher, accept dispatcher,
register_tunnel_bindfirst_openable
- forwarded-receipt — the opener-side serving op + reply-field reader
- tunnel-listener — the listen-flow consumer session (ADR-008 §4)
- local-bind-halves — the `local` TCP bind + accept-pairs loop,
unix parity decision, direct-op DialFn reuse pin
Dependency order: direct-op and bindfirst-params are independent
roots; bindfirst-producer -> {bindfirst-params}; forwarded-receipt ->
bindfirst-params; tunnel-listener -> {bindfirst-params,
forwarded-receipt}; local-bind-halves -> bindfirst-producer.
Verification: cargo test 71 passed; clippy --all-targets -D warnings;
fmt --check; wasm32-unknown-unknown check + clippy clean (docs + task
files only — no code change).
- DatagramReader::feed is infallible (the oversize bound is enforced
at frame time; the same zombie category as 4014ba6's InvalidLength).
The Vec<Result> shape, the local adapter's dead InvalidData mapping,
and consumer.rs's `?` drop.
- The sender-block machinery test (root-gated veth fixture, auto-skip
without root): the peer address unassigned + the neighbor table
flushed pins the connected sender in a persistent WouldBlock/ENOBUFS
state; the test drives the WouldBlock stash, the readiness-Pending
arms, AND the accepted-byte high-water Pend in one behavior, then
resolves (addr assign + peer bind) and asserts the queued datagrams
drain and deliver. Jumbo MTU (65535) keeps IP fragmentation out of
the way; the block-state probe runs on a throwaway socket (an
oversized probe's partially-built skb chain stays corked on EAGAIN
and poisons the socket).
- pump_queue_to_socket's stash arm now matches ENOBUFS(105) alongside
WouldBlock — the blocked-neighbor state reports 105, and both mean
"the socket cannot take this datagram now".
- connect_udp's resolve-failure arm covered (an RFC 6761 .invalid
target maps to dial_failed; rootless).
- The no-witness tunnel_establisher wrapper covered (a harness
DialNoWitness mode + a full open round-trip through the wrapper).
Negative result pinned in the task doc: tokio 1.53 structurally masks
UDP ICMP errors out of the poll drive (poll_recv_ready/try_io mask
ERROR out of the read direction), so the recv-side ECONNREFUSED
mapping arm is unreachable through the pump's drive — it joins the
defensive list.
Coverage: 92.86% -> 93.91% lines (50 -> 41 uncovered, all deliberate).
Verification: cargo test + cargo test --all-features (91 tests),
clippy --all-targets --all-features, fmt, wasm32 check+clippy,
cargo doc — all clean.
Closes the behavioral test gaps the 2026-09-09 coverage review found
(88.28% → 92.86% lines; details in tasks/tunnels/coverage-weak-spots.md):
- Datagram EOF paths (consumer.rs:377-382, 255) — previously
zero-covered documented contracts: a clean stream EOF resolves
`Ok(None)` (the pump-less session's shutdown signal), a mid-datagram
EOF fails loud with `TruncatedDatagram` (OQ-TN-13), both over a new
closable UDP echo dial (`closing_udp_echo_dial`, both shapes).
- UDP `take_halves` (consumer.rs:201-205) — pins the N-3 framing
contract: taken halves carry raw `[len: u16 BE]` wire bytes, and
the data-plane accessors fail `ChannelTaken` after the take.
- Reverse UDP `pump_against` (consumer.rs:289) — the framed side
round-trips end-to-end (payload + the F-2 empty datagram `len=0`
survives the pump), the N-11 boundary contract.
- `AcceptQueue::push` after close returns `Err(handle)`, closed pop
resolves `None`, and the accept loop's queue-closed mapping ends
the loop with the handler error (producer.rs:279-288, local
accept_loop).
- `establishment_reason` wrapper (params.rs) — unit test over the
typed surface (open_failed reason / non-establishment /
AdoptFailed); plus the schema-gate preemption probe in
producer_open_op (missing substrate is `INVALID_INPUT` before the
establisher runs).
- `UdpHalf` write machinery (local/mod.rs) — four poll-driven tests:
queue accept + flush drain to the wire + shutdown best-effort,
repeated flush cycles, the unconnected-socket error mapping
(deterministic EDESTADDRREQ), and the shutdown-drain-swallows-
errors posture. Host probes recorded in the task doc: no UDP
sender-blocking shape is reachable on this host (loopback/veth
drop silently; the fresh-socket try_send quirk is timing-tolerated,
never asserted), so the stash/high-water paths stay uncovered by
host limitation, not by oversight.
Verified: cargo test (default + --all-features), clippy --all-targets
-D warnings, fmt --check, wasm32 check + clippy, llvm-cov 92.86%.
The coverage review found `InvalidLength {declared, have}` is a
zombie: `DatagramReader::feed` never returns `Err` — it buffers
partial frames indefinitely, and the truncated-stream contract is
carried by `is_mid_datagram` (the codec diagnostic) plus
`TunnelIoError::TruncatedDatagram` (the session surface). The
variant's doc claimed it was the truncated-stream error; no spec
(ADR-003, wire.md, bast.md) names it, and no external consumer
exists (verified 2026-09-08 per ADR-005's N-3 amendment), so the
API window is open — removed before the first consumer pins it.
Also removes the `unreachable!` arm its removal strands in the
`local` adapter's recv mapping (a no-panic path; single-variant
destructure now), and records the planned-shape correction in the
completed wire-codec task doc.
Verified: cargo test (--all-features and default), clippy
--all-targets -D warnings, fmt --check, wasm32 check + clippy — all
clean.
Review 001 N-3 (tasks/tunnels/decide-take-framed-halves), decided
before the first external consumer:
- Option 1 (keep as-is, docs carry it), recorded as ADR-005
§Amendment. No external consumer exists (window open — the breaking
reshape was available but undemonstrated); one take_halves semantic
across substrates beats per-substrate divergence; pump_against
composes the framed adapter (UdpHalf), not framed halves; and the
take_framed_halves convenience is additive — it can land after the
first consumer defines its shape.
- consumer.md's datagram section states the posture; review 001 §N-3
resolution note landed; task marked completed.
Docs-only (no code change). Verified: fmt --check, doc --no-deps
warning-free, 63 default / 76 local tests green.
Review 001 remediation (tasks/tunnels/fix-udp-framed-adapter):
- U-1 [major]: UdpHalf now composes the ADR-003 codec at the
substrate boundary — poll_write de-frames channel bytes (incremental
DatagramReader) and sends each payload as one raw datagram;
poll_read frames raw target datagrams and hands frame bytes to the
pump. Targets see payload-only bytes; empty datagrams round-trip
(the F-2 fix end-to-end); >8 KiB datagrams arrive as ONE datagram.
Mechanics the verification gates forced beyond the sketch:
poll_write accepts all offered bytes (tokio copy re-offers a full
window unsatisfied — partial-frame holds deadlock >8 KiB frames),
backpressure is an accepted-byte high-water mark, socket drain
pumps on write/flush/shutdown; >caller-buffer frames stage across
reads (the truncation probe's assertion surface updated per the
re-validation correction).
- U-2 [minor]: connect_udp resolves the target and binds the
unspecified address of the matching family (v6 targets dial from
[::]:0); bind_tcp gains the wildcard-exposure doc warning.
- U-3 [minor]: the 65535 recv scratch allocates lazily on first recv
(full-size read kept — try_recv truncates silently; the MTU-shrink
idea confirmed unsafe in re-validation).
- N-1: the module/connect_udp/UdpHalf docs now describe the composed
codec truthfully.
Gates (permanent tests in tests/local_halves.rs): recording-target
suite (payload-only at the target, empty-datagram round-trip, 9000-
byte single datagram, unframed-target resolution), the 65507-byte
max-datagram staging probe, and the v6 dial gate.
Docs: ADR-003 §Amendment (the boundary mechanics), wire.md truncation
bullet, consumer.md adopt sketch (substrate param). Review 001
resolution notes on U-1/U-2/U-3/N-1; task marked completed.
Verified: 63 default / 76 local tests ×3 repeat runs; clippy
-D warnings (all-targets + wasm32), fmt --check, doc --no-deps
(warning-free), wasm check, publish dry-run.
- All findings re-validated (fresh executable probes for U-1 over
real sockets — all four behaviors reproduced; fixed-in-review
items confirmed in-tree; battery green 63/70).
- U-1 amendment: the review's fix sketch was direction-inverted
(frame-on-write describes the TARGET face; UdpHalf's caller is the
pump, so poll_write DE-frames channel bytes and poll_read FRAMES
target datagrams). Gate 4 and U-3 corrected: the truncation test's
assertion surface may change; the 65535 recv scratch is
correctness-load-bearing (tokio try_recv truncates silently).
- Task fix-udp-framed-adapter updated to the corrected mechanics.
- New task decide-take-framed-halves (N-3): the datagram
take_halves API posture, to decide before the first external
consumer.
Verification: cargo test 63/70 both configs, clippy -D warnings
(all-targets + wasm32), fmt, cargo doc --no-deps (0 warnings),
publish dry-run, taskgraph validate (15 tasks, acyclic).
Sharpened from 'v6 blind spot' into a general bind-posture rule after
follow-up discussion: no implicit wildcard binds (0.0.0.0 / :: — note
::1 is loopback, not a wildcard); connect_udp is a client socket so
the floor fix is family-correct binding, never a loopback default;
bind_tcp keeps its caller-supplied address (the correct posture) with
a wildcard-bind doc warning. Executable rider sharpened on the
remediation task.
Findings + review doc: docs/reviews/001-implementation-review.md (the
alkcall house pattern). Closes tunnels/review-core-crates and
tunnels/review-impl.
Findings:
- U-1 [major, NOT fixed] — the local UDP adapter is not the framed
adapter ADR-003 mandates: codec-framed bytes reach real targets,
empty datagrams are EOF-shaped at the adapter (tunnel teardown),
>8 KiB datagrams split, unframed target-initiated datagrams are
dropped. Executable-pinned by real-socket probes (temporary test,
deleted after the run). Remediation task: tunnels/fix-udp-framed-adapter.
- C-1 [major, fixed] — AcceptQueue::pop lost wakeup in the
check→register window (open op hangs to the establishment bound);
fixed via the tokio notify_waiters contract (Notified created before
the check each iteration) + multi-thread regression test.
- N-4/N-5/N-7/N-8/N-9/N-10/N-11 [minor, fixed] — serialize TunnelParams
in open_reverse_channel; stale doc ref; broken doc link; root
re-exports (TunnelParams/Substrate/tunnel_open_spec/OP_TUNNEL_OPEN);
README (publish dry-run was failing on the missing readme); harness
comment; pump_against UDP framing doc note.
- N-2 retracted by executable falsification (codec buffering is
bounded by construction); N-6 non-finding with rationale.
Verified: 63 tests default / 70 with --features local, 3x repeat-run
clean both configs; clippy -D warnings (all-targets + wasm32); fmt;
doc warning-free; wasm32 check; cargo publish --dry-run passes.
- src/local/mod.rs (feature = "local" -> tokio/net): dial_tcp (5s
timeout), connect_udp (ephemeral bind + connect + the FRAMED UdpHalf
adapter), dial_unix (OQ-TN-14 in v1), bind_tcp +
TcpListenerHalves::accept_loop (the listen shape's assembly half),
local_dial() (one DialFn covering all three substrates).
- UdpHalf truncation fails loud (OQ-TN-13): poll_read recvs into a
scratch buffer first and size-checks against the caller's buffer —
an over-size datagram is io::ErrorKind::InvalidData, never a silent
truncation (tokio's poll_recv-into-ReadBuf would truncate).
- No socket type appears outside src/local/ (convention 16); the
default crate stays wasm-clean; stdio bridging is NOT here (alktty
owns process stdio).
- Tests (tests/local_halves.rs, 7, feature-gated): TCP/UDP/unix dial
round-trips through the real establisher path, the 1400-byte MTU
datagram, the truncation fail-loud probe, dial-refusal ->
dial_failed, listen producer over a real TCP listener end-to-end.
Verified: cargo test green (default + --all-features, 44 + 7),
clippy -D warnings (default + all-features + wasm32), fmt clean,
cargo check --target wasm32-unknown-unknown passes.
- AcceptFn: the injected accepted-connection source (the assembly
layer owns the listener + accept loop; the protocol never binds —
OQ-TN-04).
- AcceptQueue: the protocol-side queue contract (async push/pop/
close; FIFO always-before-take ordering; close-while-waiting
resolves None). Empty-queue posture is assembly-owned (a late
accept is legitimate; resource_shortage is the closure's mapping;
the wrapper's 10s establishment timeout is the backstop).
- listen_establisher: same open op, same params, same typed errors —
registry namespace gate → accept() → Establishment::new(plan);
the pump handler is untouched (plan-flow with a different source).
- register_tunnel_listen_openable: same spec/pump registration with
the listen establisher (the honest shape vs a dial/accept enum:
the establisher is the only difference; one establisher per op id
per session registry — documented).
- Tests (tests/producer_listen.rs, 6): listen flow end-to-end, FIFO
ordering across two opens (R-01 plan-flow, listen-flavored), empty
queue -> resource_shortage, closed listener -> dial_failed,
unknown resource -> unknown_resource, late-push wait-then-resolve.
- Harness: RegistrationMode enum + wire_listen.
- TargetHandle gains a structural Debug impl (test ergonomics).
Verified: cargo test green (44), clippy -D warnings (native + wasm32),
fmt clean, wasm32 check passes.
Split the last open substrate-placement question:
- Unix: ships with the local feature v1 (dial_unix — same halves
shape as TCP; the wire enum already carried unix per ADR-001;
the params task's schema list includes all three values)
- Stdio: OUT of scope — a spawned process's stdin/stdout/stderr IS
alktty's pipe mode (LocalTtyBackend + tokio::process + Stdio::piped,
alktty tty-local.md): three multiplexed logical streams + the
exit-code control chunk (alktty ADR-004) + signal forwarding
(REQ-TTY-02). A stdio bridge here would be alktty's runner mode
with the terminal stripped out — a strictly worse duplicate that
also drops the semantics that matter (a byte tunnel has neither
exit codes nor signals). Remote command execution composes via
alktty on the same channels substrate.
Updated: open-questions.md OQ-TN-14 (resolved), overview.md feature
gate + deps + OQ summary, producer.md OQ ref, OQ-TN-10 promotion
(#3 split), phase-0-findings + both POC summaries' resolution notes,
params task (schema enum includes unix), local-socket-halves task
(unix ships, stdio does NOT — with the composition rationale),
oq-tn-14-tracker task repurposed (boundary-maintenance: re-opens only
if a consumer needs stdio-without-process-semantics — which would
need its own ADR, or if the alktty/alktunnels boundary needs
sharpening).
Verified: taskgraph valid (12 tasks, no cycles)
tasks/architecture/:
- oq-promotion-sync (planning): back-pointers from the phase-0 ledger
+ AGENTS.md to the promoted OQ tracker (the convergence checklist's
final half)
- oq-tn-14-tracker: the Safe-Exit external-trigger tracker task for
OQ-TN-14 (unix/stdio placement; [external-trigger, deferred-oq],
risk trivial, level research per the two-halves rule)
tasks/tunnels/ (the implementation graph, 8 generations):
- crate-init: module skeleton per overview.md's module map
- params: TunnelParams + open-op spec (ADR-001 wire-stable surface)
- wire-codec: frame_datagram/DatagramReader + the 8 POC-pinned test
families (ADR-003)
- producer-open-op: establisher (dial, plan flow R-01) + pump handler
(pump_bidi inline R-02) + registration; POC-ported integration tests
- consumer-session: TunnelSession (open/adopt, data planes, teardown
matrix — ADR-005); generalizes the reverse POC's ReverseTunnel
- producer-listen: the listen establisher + AcceptQueue contract
(ADR-004 shape 2)
- local-socket-halves: the local feature (TCP/UDP/unix halves
functions; truncation fail-loud per OQ-TN-13; unix ships per
OQ-TN-14's lean-yes, stdio deferred)
- review-core-crates: review-injection point before the downstream
tasks build on the high-risk producer/consumer shapes
- end-to-end-suite: 6 suites / >=20 tests consolidating both POC
suites against the public API (the spec's executable form)
- review-impl: the phase-gate review (wire/API/conventions/docs sync;
findings doc per the alkhttp/alkcall house pattern)
Graph verified with taskgraph: 12 tasks valid, no cycles, 8
generations; critical path = oq-promotion-sync -> crate-init ->
params -> wire-codec -> producer-open-op -> consumer-session ->
review-core-crates -> review-impl; risk concentrated in the two
session tasks (both POC-validated); parallel groups available at
generations 1 and 6