diff --git a/tasks/tunnels/corrmiss-adr.md b/tasks/tunnels/corrmiss-adr.md new file mode 100644 index 0000000..3473322 --- /dev/null +++ b/tasks/tunnels/corrmiss-adr.md @@ -0,0 +1,115 @@ +--- +id: tunnels/corrmiss-adr +name: "ADR: the forwarded op's establishment phase + the correlation-miss vocabulary (resolves review 003 — decisions)" +status: pending +depends_on: [] +scope: narrow +risk: medium +impact: phase +level: implementation +tags: [adr, forwarder, correlation-miss, vocabulary, review-003] +--- + +## Description + +Land the ADR ink for the settled decisions in +`docs/plans/003-correlation-miss-resolve.md` §Decisions (1-4): the +forwarded op's serving side gains an establishment phase; a stale/ +missing `listen` token fails the open as a typed `channel:open_failed` +(rewriting plan decision 2 — the wire vocabulary already pins +`unknown_resource`, so no wire-vocabulary extension and no +reason-class ADR); the residual post-open decline (the narrow +establisher-pass/handler-miss race) keeps teardown-at-birth and adopts +**`correlation-miss`** as the canonical event name with alkssh's level +posture (assembly-side declines at `debug`; the producer-side generic +arm keeps `warn` now carrying a typed reason instead of a prose one). + +Also record the tri-vocabulary history the decision retires: +alkssh `correlation-miss` (debug, `decline_arrival`), alksocks prose +("forwarded open with no waiting session", warn, +`src/composed/mod.rs:497`), alktunnels `handler_error`-class generic +arm (warn, the bind-first accept loop's failed-open branch) — review +003's situation section plus the plan's §Verified findings are the +primary sources for it. + +Doc-only change; no code in this task. + +### Shape to decide while writing (the plan's "ADR-008 amendment +### (or a small successor ADR)" choice) + +Recommendation: an **Amendment 2 to ADR-008** — this amends the +forwarded op's serving shape exactly as §3 pins it (that section's +sentence "no establisher — the forwarded channel needs no +establishment; its data plane starts immediately" is the text being +amended), the wire vocabulary is unextended, and the amendment keeps +the whole forwarded-op decision record in one ADR. Take a small +successor ADR instead only if the amendment balloons +(e.g. it forces restating §4/§5 wholesale). Whichever shape: mark the +amended §3 sentence, cross-link the plan and review 003, keep the +existing ADR text's amendment style (the landed Amendment 1 is the +format precedent). + +### The invariants the ADR must pin + +- The gate is injected — the protocol crate cannot hold the assembly's + correlation map; the establisher's check is an assembly-provided + closure the crate wraps into the alkcall `OpenEstablisher` dance + (the plan's W1 decision; assemblies must not hand-roll the alkcall + establisher plumbing). +- The gate rides `register_openable_with_establisher` (alkcall 0.10.0, + verified): establisher failure → typed `channel:open_failed` with + `details.reason`, "never a phantom channel" is ADR-049's posture — + the forwarded op currently rides the phantom-shaped serving side + (establisher-less everywhere), and this closes it for the miss class. +- `unknown_resource` is reused as-is (the waiting session IS a resource + that is gone) — `details.reason`'s wire vocabulary is NOT extended. +- The scope gate (`tunnel:forwarded`) precedes the establisher — pin + the order (the registry runs the ACL before the open op's + establishment phase; alkcall's open-op wrapper order). +- The residual post-open race keeps teardown-at-birth (the fallback + shape — ADR-008 §3's opener-half posture, unchanged) and its event + name is `correlation-miss` at `debug` (assembly-side; the protocol + crate's built-in handler holds no map, so the name is the + assemblies' convention this ADR records, not code this crate runs). +- Additive-only surface: the base `register_tunnel_forwarded_openable` + shape stays for compatibility; the establisher variant is the + recommended posture (new assemblies take it by default posture). + +## Acceptance Criteria + +- [ ] Amendment 2 to ADR-008 (or the successor ADR) lands under + `docs/architecture/decisions/`, covering all four §Decisions + and the tri-vocabulary history +- [ ] The amended/superseded §3 sentence is marked, not silently + replaced +- [ ] Wire-vocabulary non-extension is explicit (`unknown_resource` + reused; `wire.md` §The Open Ops untouched — state that) +- [ ] Status block of + `docs/reviews/003-correlation-miss-arrival-class-alkssh-input.md` + is NOT updated here (the doc-sync task owns it — this task is + the ADR itself) +- [ ] No code changes; doc build clean (`cargo doc --no-deps` clean is + NOT required for pure docs/ edits — verify md renders coherently + instead) + +## References + +- docs/plans/003-correlation-miss-resolve.md §Decisions, §Verified + findings, §W1 (this task is the ADR bullet of W1) +- docs/reviews/003-correlation-miss-arrival-class-alkssh-input.md +- docs/architecture/decisions/008-listen-metadata-forwarded-op.md §3 + (the serving shape being amended; Amendment 1 is the format + precedent) +- docs/architecture/wire.md §The Open Ops (the pinned + `details.reason` vocabulary — unextended) +- alkcall ADR-049 (the establisher posture being extended to the + forwarded op's serving side); alkcall 0.10.0 + `register_openable_with_establisher` (verified present) + +## Notes + +> To be filled by implementation agent + +## Summary + +> To be filled on completion \ No newline at end of file diff --git a/tasks/tunnels/corrmiss-alksocks-adopt.md b/tasks/tunnels/corrmiss-alksocks-adopt.md new file mode 100644 index 0000000..5665eab --- /dev/null +++ b/tasks/tunnels/corrmiss-alksocks-adopt.md @@ -0,0 +1,59 @@ +--- +id: tunnels/corrmiss-alksocks-adopt +name: "W3 (pointer, alksocks repo): adopt the establisher — CorrelationRegistry lookup becomes the gate; the prose warn retires" +status: pending +depends_on: [tunnels/corrmiss-review] +scope: moderate +risk: medium +impact: component +level: implementation +tags: [pointer, cross-repo, alksocks, correlation-miss, review-003, wave-2] +--- + +## Description + +**CROSS-REPO POINTER — executed in the alksocks repo, not here.** +Dependency-graph carrier for the plan's third wave; the work session +is booked in alksocks. Runs in parallel with W2 (alkssh) once W1's +reviewed surface is landed. + +Per plan 003 §W3 (read that section — it is the spec for this session; +this task only carries the dependency + the acceptance summary): + +- Move the `CorrelationRegistry` lookup (alksocks + `src/composed/mod.rs` — `make_forwarded_handler`) into the new + `register_tunnel_forwarded_openable_with_establisher` gate + (consumed from alktunnels at the version W1 landed). +- Retire the prose warn ("forwarded open with no waiting session", + `src/composed/mod.rs:497`) — the miss becomes a typed failure at + the open. +- Residual logging aligns to the canonical `correlation-miss` name at + `debug` (the family one-way vocabulary; alkssh's shipped form). +- Fold alksocks' em-dash doc cleanup into its release for this change + (user-owned, out of plan scope). + +## Acceptance Criteria (alksocks-side; the plan-level §W3 box) + +- [ ] alksocks serves the gate shape (the registry lookup rides the + gate) +- [ ] The prose warn variant is retired +- [ ] Residual logging is `correlation-miss` at `debug` +- [ ] alksocks' release includes its doc cleanup (user-owned) + +## References + +- docs/plans/003-correlation-miss-resolve.md §W3 (THE spec) +- docs/reviews/003-correlation-miss-arrival-class-alkssh-input.md §Verified + findings (the third variant's provenance — + `src/composed/mod.rs:497`) +- The alksocks repo: `src/composed/mod.rs` (`make_forwarded_handler`, + `CorrelationRegistry`) +- This repo's landed surface (W1): tasks/tunnels/corrmiss-forwarded-gate.md + +## Notes + +> To be filled by the executing session (in alksocks) + +## Summary + +> To be filled on completion \ No newline at end of file diff --git a/tasks/tunnels/corrmiss-alkssh-adopt.md b/tasks/tunnels/corrmiss-alkssh-adopt.md new file mode 100644 index 0000000..221a274 --- /dev/null +++ b/tasks/tunnels/corrmiss-alkssh-adopt.md @@ -0,0 +1,61 @@ +--- +id: tunnels/corrmiss-alkssh-adopt +name: "W2 (pointer, alkssh repo): adopt the establisher — pump_forwarded_arrival's lookup becomes the gate" +status: pending +depends_on: [tunnels/corrmiss-review] +scope: moderate +risk: medium +impact: component +level: implementation +tags: [pointer, cross-repo, alkssh, correlation-miss, review-003, wave-2] +--- + +## Description + +**CROSS-REPO POINTER — executed in the alkssh repo, not here.** This +task exists in this repo's decomposition so the dependency graph and +the plan's ordering (`W1 → {W2, W3}`) stay visible; the work session +is booked in alkssh (its wave-3 review gate item 5 lineage — +`tasks/implementation/review-wave-3.md` item 5 and +`docs/plans/implementation.md` "Still booked with their owners"). + +Per plan 003 §W2 (read that section — it is the spec for this session; +this task only carries the dependency + the acceptance summary): + +- Move `pump_forwarded_arrival`'s route lookup (alkssh + `src/tunnel_map.rs` — the `ListenRouter` lookup) into the new + `register_tunnel_forwarded_openable_with_establisher` gate + (consumed from alktunnels at the version W1 landed). +- The residual handler keeps `decline_arrival("correlation-miss", …)` + at its shipped `debug` level for the narrow post-open race only. +- Verify the fabric-side silence fix: a stale-token arrival now fails + the open (alkssh-side typed error; the producer-side generic arm + fires with a parseable reason) — the race window no longer produces + a zero-signal pump. +- Fold alkssh's em-dash doc cleanup into its release for this change + (user-owned, out of plan scope). + +## Acceptance Criteria (alkssh-side; the plan-level §W2 box) + +- [ ] alkssh serves the gate shape (the route lookup rides the gate; + the residual handler is the narrow race only) +- [ ] A stale-token arrival produces a typed call-plane failure (no + zero-signal pump) +- [ ] The residual class is named `correlation-miss` at `debug` +- [ ] alkssh's release includes its doc cleanup (user-owned) + +## References + +- docs/plans/003-correlation-miss-resolve.md §W2 (THE spec) +- docs/reviews/003-correlation-miss-arrival-class-alkssh-input.md +- The alkssh repo: `src/tunnel_map.rs` (`pump_forwarded_arrival`, + `ListenRouter`), `src/observe.rs` +- This repo's landed surface (W1): tasks/tunnels/corrmiss-forwarded-gate.md + +## Notes + +> To be filled by the executing session (in alkssh) + +## Summary + +> To be filled on completion \ No newline at end of file diff --git a/tasks/tunnels/corrmiss-doc-sync.md b/tasks/tunnels/corrmiss-doc-sync.md new file mode 100644 index 0000000..472442e --- /dev/null +++ b/tasks/tunnels/corrmiss-doc-sync.md @@ -0,0 +1,64 @@ +--- +id: tunnels/corrmiss-doc-sync +name: "Doc sync: review 003 status + plan 003 checkboxes + plan-level AC close-out (W1)" +status: pending +depends_on: [tunnels/corrmiss-review] +scope: narrow +risk: trivial +impact: component +level: implementation +tags: [docs, review-003, status, bookkeeping] +--- + +## Description + +Close out W1's remaining doc bookkeeping (the plan-level AC's "review +003 status updated to resolved (W1 absorbed; W2/W3 pointed)" clause): +resolve the review's doc trail once the ADR + API + tests + review +checkpoint are landed. + +- `docs/reviews/003-…alkssh-input.md`: update the Status block — + resolved for W1 (this repo absorbed the ask via the ADR + the + establisher variant); W2/W3 pointed at the sibling repos + (`docs/plans/003-correlation-miss-resolve.md` is the pointer). Match + the status-block format the other reviews use. +- `docs/plans/003-correlation-miss-resolve.md`: tick the W1 share of + §Acceptance criteria (the first checkbox's clauses that are now + true). Leave the W2/W3 checkboxes and the plan-level "W2: …" / + "W3: …" boxes UNTICKED — they are sibling-repo sessions, unticked + until those repos land. +- `docs/plans/003-…` status header: planned → W1 landed (keep the + file; it records the tri-vocabulary decision's ground). +- If any doc comment referencing the miss is stale after the API task + (a `grep` for `correlation miss` / `handler_error`-class across + `src/`, `docs/architecture/`) — align it. Convention: stale + TODOs/comments pointing at superseded designs get removed, not + annotated. + +## Acceptance Criteria + +- [ ] Review 003's Status block reads resolved-for-W1 with the W2/W3 + pointer +- [ ] Plan 003's W1 acceptance clauses ticked; W2/W3 left visibly + open +- [ ] A stale-comment sweep across `src/` + `docs/architecture/` ran + clean (or the stragglers aligned) +- [ ] `cargo doc --no-deps` clean (doc edits touch lib.rs-adjacent + comments only if the sweep found any) + +## References + +- docs/reviews/003-correlation-miss-arrival-class-alkssh-input.md + (the status block) +- docs/plans/003-correlation-miss-resolve.md §Acceptance criteria + (the plan-level boxes) +- tasks/tunnels/review-002-doc-sync.md (the doc-sync precedent — + same job shape for review 002) + +## Notes + +> To be filled by implementation agent + +## Summary + +> To be filled on completion \ No newline at end of file diff --git a/tasks/tunnels/corrmiss-forwarded-gate.md b/tasks/tunnels/corrmiss-forwarded-gate.md new file mode 100644 index 0000000..397ea8a --- /dev/null +++ b/tasks/tunnels/corrmiss-forwarded-gate.md @@ -0,0 +1,143 @@ +--- +id: tunnels/corrmiss-forwarded-gate +name: "API: the forwarded-op establisher variant — ForwardedGate + register_tunnel_forwarded_openable_with_establisher" +status: pending +depends_on: [tunnels/corrmiss-adr] +scope: moderate +risk: medium +impact: component +level: implementation +tags: [api, establisher, forwarded-op, correlation-miss, review-003] +--- + +## Description + +Implement the additive establisher variant for the forwarded op's +serving half (plan 003 W1's API item): an assembly-injected +correlation gate that the crate wraps into the alkcall +`OpenEstablisher` dance, registered via +`register_openable_with_establisher` — a stale `listen` token now +returns a typed `channel:open_failed` before the channel's data plane +is served, instead of succeeding at the call plane and declining +post-open (the phantom-channel shape the review records as +fully silent on the fabric side). + +Candidate shape (the plan's W1 design decision to finalize — this task +finalizes it): + +```rust +/// The injected correlation gate: `Err` at the gate → typed +/// `channel:open_failed` before the channel is born. +pub type ForwardedGate = Arc< + dyn Fn(&TunnelForwardedParams) -> Result<(), TunnelEstablishError> + Send + Sync, +>; + +pub fn register_tunnel_forwarded_openable_with_establisher( + core: &ChannelCore, + on_registry: &Arc, + auth: AuthContext, + gate: ForwardedGate, + handler: ForwardedHandler, +) -> Result<(), String> +``` + +### The design decisions to finalize (and pin in doc comments) + +1. **Gate input vs raw input.** The gate receives the PARSED + `TunnelForwardedParams` — the establisher parses (the params' + serde pins — `deny_unknown_fields`, positive `listen` — are the + loud gates; `parse` failure at the establisher maps through + `EstablishmentError::HandlerError` → a typed `channel:open_failed`, + which is an improvement over the base shape's silent + birth-teardown for a malformed ingress; pin this deliberately, do + not drift it). The handler still receives the raw input and + re-parses as it does today — keep `make_forwarded_op_handler` + unchanged (the double parse is cheap and preserves deny-unknown at + both layers; the handler must stay usable by the base shape). +2. **The establishment answer.** A gate pass produces no resource + handle (the correlation map is assembly state; the handler needs + nothing it does not re-derive) — return `Establishment::new(plan)` + with an empty/marker plan payload (same typed-opaque `ChannelPlan` + posture as ADR-049 amendment 2; `()` or an empty marker struct is + the payload choice to pin). No reply-field contribution (the + forwarded op's reply stays the wrapper's `channel_id`). +3. **Error mapping.** A gate `Err(TunnelEstablishError)` maps through + the EXISTING `From for EstablishmentError` + table (`src/producer.rs:142-154`) — a stale token is + `UnknownResource` → `details.reason == "unknown_resource"` on the + wire. Do not mint new variants. The gate SHOULD document that a + miss is `TunnelEstablishError::UnknownResource` (that is the + canonical reason the ADR pins), but the crate passes whatever the + gate returns through. +4. **No timeout change** — `timeout: None` (the alkcall 10s default) + as the other registrations do; the gate is an in-memory map lookup. +5. **No scope-table change** — the same `tunnel_forwarded_spec()` / + `tunnel:forwarded` gate runs (the registry runs the ACL before the + establishment phase — alkcall's open-op wrapper order; pin the + order in a doc comment + a test, see the tests task). + +### Also in this task (the doc half of W1's API item) + +- Update the in-code docs that describe the miss as + assembly-side-only: `make_forwarded_op_handler`'s + correlation-miss-semantics block (`src/producer.rs:1014-1020`) and + `register_tunnel_forwarded_openable`'s doc (1047-1056) — both gain + the two-shape posture: the establisher variant is the recommended + shape (the miss is a typed failure at the open); the base shape + stays for compatibility and keeps the post-open teardown-at-birth + semantics (still the residual-race fallback under the establisher + variant). +- Re-export the new surface from `lib.rs` (convention 16). +- The base `register_tunnel_forwarded_openable` stays + byte-for-byte compatible (additive-only — plan decision 4). + +NOT in this task: the sibling-repo adoptions (alkssh W2 / alksocks W3 +— pointer tasks exist), the gate-miss tests (the dedicated tests task +— but do not land the API without landing its tests task after). + +## Acceptance Criteria + +- [ ] `ForwardedGate` type + `register_tunnel_forwarded_openable_with_establisher` + landed in `src/producer.rs`, re-exported from `lib.rs` +- [ ] The establisher parse-failure → typed `channel:open_failed` + mapping is deliberate + documented (design decision 1) +- [ ] Gate errors pass through the existing + `From` table; no new error variants +- [ ] `make_forwarded_op_handler` / the base registration are + unchanged in behavior (byte-for-byte compat) +- [ ] The in-code docs updated: the two-shape posture (establisher = + recommended; base = compatibility + residual-race fallback) + replaces the assembly-side-only framing +- [ ] `cargo test` green (existing suite untouched); clippy + `--all-targets -- -D warnings` clean (native + wasm32); + `cargo fmt --check` clean; default crate stays wasm-clean +- [ ] `--all-features` test run green (the `local` feature surface is + untouched) + +## References + +- docs/plans/003-correlation-miss-resolve.md §W1 (the API bullet; + the decisions this finalizes) +- docs/architecture/decisions/008-listen-metadata-forwarded-op.md §3 + + the ADR this task's predecessor lands (Amendment 2 or successor — + cite whichever the ADR task landed) +- src/producer.rs:982-1082 (the base serving shape — `ForwardedHandler`, + `make_forwarded_op_handler`, `register_tunnel_forwarded_openable`); + 142-154 (the `From` table); 641-673 + (the `bindfirst_establisher` — the wrap-into-`OpenEstablisher` + closure pattern to mirror, including the `Box::pin` shape) +- alkcall 0.10.0 `ChannelCore::register_openable_with_establisher` + (src/channels/operations.rs:761 — the establisher runs AFTER + allocation, BEFORE the reply; failure → typed `channel:open_failed`, + no phantom channel; `timeout: None` = the 10s default) +- AGENTS.md conventions 11 (the ADR-049 establishment surface is + load-bearing; typed-opaque plans), 8 (teardown-at-birth posture), + 16 (re-export posture) + +## Notes + +> To be filled by implementation agent + +## Summary + +> To be filled on completion \ No newline at end of file diff --git a/tasks/tunnels/corrmiss-gate-tests.md b/tasks/tunnels/corrmiss-gate-tests.md new file mode 100644 index 0000000..4243c35 --- /dev/null +++ b/tasks/tunnels/corrmiss-gate-tests.md @@ -0,0 +1,97 @@ +--- +id: tunnels/corrmiss-gate-tests +name: "Tests: the forwarded gate — typed miss at the open, gate-pass flow, residual race, scope-gate ordering" +status: pending +depends_on: [tunnels/corrmiss-forwarded-gate] +scope: narrow +risk: low +impact: component +level: implementation +tags: [tests, establisher, forwarded-op, correlation-miss, review-003] +--- + +## Description + +Land W1's test item (plan 003 §W1 "Tests:"): pin the four behaviors +the establisher variant introduces, mirroring the shapes the existing +suite uses (`tests/producer_forwarded.rs` — the serving-half e2e + +scope-gate + malformed-params + correlation-miss tests are the +precedents; the harness's `wire_with` + `Topology.consumer_registry` +shape needs no harness changes per the `forwarded-receipt` task's +notes). + +The four pins: + +1. **Miss at the gate → typed failure, no phantom.** A `listen` token + with no waiting session → the open fails as a + `channel:open_failed` reply with `details.reason == + "unknown_resource"`; the transiently allocated channel is torn + down by the wrapper (ADR-049 §5 — the reply is the typed error, + not a phantom channel); the pump handler NEVER runs. Probe by + opening the forwarded op with a token the gate rejects. +2. **Gate pass → the existing serving flow is unchanged.** A token the + gate accepts → the registration serves exactly like the base + shape: the injected `ForwardedHandler` receives the parsed params + + the `BiStream`, the byte round-trip works end to end (the + `producer_forwarded.rs` round-trip shape, driven through the + establisher-registered variant). +3. **The residual race shape still reaps cleanly.** Gate passes, route + gone at handler time → the injected handler's error path drops the + stream and returns → teardown-at-birth reaps the forwarded channel + (the base shape's pinned semantics — re-pin them under the + establisher variant; the narrow establisher-pass→handler-run window + is the residual `correlation-miss` class). +4. **Scope gate precedes the establisher.** An identity WITHOUT + `tunnel:forwarded` → FORBIDDEN and the gate closure is never + invoked (a witness-style `Arc` or captured flag the + gate sets on entry; assert unmoved) — the registry runs the ACL + before the open op's establishment phase; pin the order. + +If the establisher variant's parse-failure behavior (malformed params +→ typed `channel:open_failed` rather than birth-teardown, the design +decision 1 of the API task) is separately testable through the public +surface, pin it as a fifth test; if the existing malformed-params test +already covers the base shape, note the establisher-shape delta +explicitly (do not silently assume). + +## Acceptance Criteria + +- [ ] Gate-miss test: typed `channel:open_failed` / + `unknown_resource` / no handler invocation / no phantom channel +- [ ] Gate-pass test: the full round-trip through the establisher + variant (handler receives parsed params + stream, bytes + round-trip) +- [ ] Residual-race test: gate passes → handler-time miss → the + channel reaps (teardown-at-birth re-pinned) +- [ ] Ordering test: missing `tunnel:forwarded` scope → FORBIDDEN and + the gate never invoked +- [ ] The establisher-variant malformed-params delta is pinned or + explicitly noted +- [ ] Full verification green: `cargo test`, + `cargo clippy --all-targets -- -D warnings` (native + wasm32), + `cargo fmt --check`, + `cargo check --target wasm32-unknown-unknown`, + `cargo test --all-features` + +## References + +- docs/plans/003-correlation-miss-resolve.md §W1 (the Tests bullet; + plan-level AC "W1 ... tests green") +- tests/producer_forwarded.rs (the shapes to mirror: the serving e2e, + the FORBIDDEN gate, the malformed-params gates, the + correlation-miss teardown) +- tasks/tunnels/corrmiss-forwarded-gate.md (the surface being tested; + design decisions 1 + 3 — the parse-failure and error-mapping pins) +- docs/architecture/wire.md §The Open Ops (the + `details.reason == "unknown_resource"` vocabulary — the assertion + target) +- alkcall 0.10.0 `src/channels/operations.rs:761` (the wrapper's + establisher failure → typed open_failed semantics; ADR-049 §5) + +## Notes + +> To be filled by implementation agent + +## Summary + +> To be filled on completion \ No newline at end of file diff --git a/tasks/tunnels/corrmiss-review.md b/tasks/tunnels/corrmiss-review.md new file mode 100644 index 0000000..7a95db7 --- /dev/null +++ b/tasks/tunnels/corrmiss-review.md @@ -0,0 +1,70 @@ +--- +id: tunnels/corrmiss-review +name: "Review: the W1 gate surface before the consumer waves adopt it (the {W2, W3} fork's critical point)" +status: pending +depends_on: [tunnels/corrmiss-gate-tests] +scope: narrow +risk: low +impact: phase +level: review +tags: [review, checkpoint, establisher, review-003] +--- + +## Description + +Review checkpoint before the parallel consumer waves (W2 — alkssh, +W3 — alksocks) adopt the landed establisher variant: the surface these +sessions build on must be right before two sibling repos burn sessions +on it. Wire-stability context: the REPLY-side semantics (a typed +`channel:open_failed` with the pre-pinned `unknown_resource` reason) +are what the consumers ride — once alkssh ships the gate shape, the +API surface is de-facto wire-stable for them. + +Check: + +- [ ] The API matches the ADR ink (the gate type, the registration + signature, the error-mapping pin, the timeout, the no-scoped + change) +- [ ] The doc comments' two-shape posture (establisher = recommended; + base = compatibility + residual-race fallback) is consistent + across `make_forwarded_op_handler`, the base/variant + registrations, and lib.rs's re-export surface +- [ ] The tests actually pin the wire-observable contract + (`channel:open_failed` / `unknown_resource`, gate ordering, + residual-race reaping) — not just internal shapes +- [ ] Patterns are consistent with the existing establisher shapes + (the `bindfirst_establisher` mirror; the + `From` table reuse; no new error axes) +- [ ] `cargo test`, clippy native + wasm32 `-D warnings`, fmt — green + (re-confirm, they gate the review) +- [ ] CHANGELOG updated (Added: the establisher variant) if the + implementation tasks did not already + +Filing guidance: if the surface needs a shape change (naming, gate +arity, plan payload), fix it in this checkpoint — it is the last cheap +moment before the consumers fork. + +## Acceptance Criteria + +- [ ] All checks above pass; any found shape drift fixed and + re-verified before the consumer-wave tasks leave `pending` +- [ ] The review outcome recorded in this task's Notes (what was + checked, what moved if anything) + +## References + +- docs/plans/003-correlation-miss-resolve.md §Ordering (the W1 → + {W2, W3} fork this review gates) +- docs/architecture/decisions/008-listen-metadata-forwarded-op.md + (the amended ADR — the shape source) +- tasks/tunnels/corrmiss-adr.md, corrmiss-forwarded-gate.md, + corrmiss-gate-tests.md (the W1 trio being reviewed) +- src/producer.rs (the landed surface) + +## Notes + +> To be filled by implementation agent + +## Summary + +> To be filled on completion \ No newline at end of file