- Rewrote the remaining em dashes outside docs/reviews/ (preserved as historical record, matching the alktty precedent): tests/ (313), fuzz/ (34 plus one shell comment), tasks/ (671 plus 12 kept in fences), docs/research + sdd_process + plans (525 plus 25 in fences), docs/architecture/overview.md fence labels (13), README, CHANGELOG, AGENTS.md, fuzz/README.md (176), and the .opencode/agents prompts (110) - Rewrote fenced content too: ASCII tree and module-map label separators, Rust snippet comments, and template placeholders; wire data, JSON/BAST examples, and transcripts survive verbatim - Rewrote 6 assert/expect message literals in tests/ and 2 format strings in fuzz/shared/src; no test data changed - Added Project Convention 18: no em dashes in prose (doc comments, markdown including docs/ and tasks/, agent prompts, commit messages); fence content rule, en-dash clause rule, and the no-spaced-hyphen prohibition follow alktty's convention 15 Follows6b20924(src doc comments) andcd0afe0(docs/architecture). Verification: cargo test (141 pass); cargo clippy --all-targets -D warnings; cargo fmt --check; cargo doc --no-deps; wasm check and clippy for wasm32-unknown-unknown with -D warnings; em dash grep over the repo returns matches only in docs/reviews/
7.2 KiB
7.2 KiB
Plan: resolve review 003 (the correlation-miss arrival class)
Status: W1 landed (2026-11-03), covering ADR-008 Amendment 2, the
…_with_establisher surface, the gate tests, and the review/checkpoint
- doc sync done. W2 (alkssh) / W3 (alksocks) are open: sibling-repo
sessions, unticked until those repos land. Resolution of
docs/reviews/003-correlation-miss-arrival-class-alkssh-input.md(also kept: it records the tri-vocabulary decision's ground), including the verification caveats found in this session (see §Verified findings, which extend the review and do not contradict it).
Verified findings (the ground the plan stands on)
The review's claims held under code verification. Two additions sharpen the resolution scope:
- A third vocabulary variant. alksocks (
src/composed/mod.rs:497) logs the same miss class as prose atwarn("forwarded open with no waiting session"). So the family names the stale-token miss three ways: alksshcorrelation-miss(debug), alksocks prose (warn), alktunnelshandler_error-class generic arm (warn, call-plane failures only). - The in-session miss is fully silent on the fabric side. The
forwarded op is served establisher-less everywhere (alkssh,
alksocks, and this crate's own built-in shape), so an in-session
correlation miss (route removed while the fabric connection lives)
succeeds at the call plane, declines post-open in the assembly, and
the producer-side pump EOFs with no log at all. The generic arm
(
src/producer.rs:838-854) only fires for the connection-gone/NOT_FOUND/ACL-refused subclass. - All three are the phantom-channel shape, i.e. the ADR-049 posture exception ("a refused open is a typed call error, never a phantom channel") that the forwarded op's serving side currently rides.
Decisions (settled this session, pending ADR ink)
- Route the miss through an establisher: the serving side gains
an establisher variant so a no-route token returns a typed
channel:open_failedbefore the channel is born. The residual post-open decline (a token missing between establisher pass and handler run, a narrow race) keeps teardown-at-birth as the fallback shape. - Reuse
unknown_resourceas the typed reason for a stale/missing token. The waiting session is a resource that is gone; the wire vocabulary (wire.md§The Open Ops,details.reason ∈) already pins it. No wire-vocabulary extension, no reason-class ADR (framing option 2's "new class" question is moot). - Adopt
correlation-missas the canonical event name for the residual post-open decline class (alkssh's shipped vocabulary wins, as it is published); alksocks' prose variant retires. Level posture: assembly-side declines atdebug; the producer-side generic arm stayswarn(it now carries a typed reason instead of a prose one). - Scope of the change is additive-only in this crate: a new
registration surface for the forwarded op. The base
register_tunnel_forwarded_openableshape stays (compatibility + assemblies that prefer the post-open shape); the establisher variant is the recommended shape and new assemblies take it by default posture.
Work items
W1 (alktunnels): ADR + additive API (this repo; ~1 session)
- ADR-008 amendment (or a small successor ADR): the forwarded op's
serving side gains an establishment phase; misses are typed failures
(decision 1-4 above), the residual post-open decline keeps the
correlation-missname. Also record the tri-vocabulary history the decision retires (review 003 + this plan). - API: an establisher variant for the forwarded-op serving half. The
protocol cannot hold the assembly's correlation map, so the
establisher's check is injected. Candidate shape (a W1 design
decision to finalize): a small assembly gate closure
(
(TunnelForwardedParams) -> Result<(), TunnelEstablishError>) that the crate wraps into the alkcallOpenEstablisherdance, plusregister_tunnel_forwarded_openable_with_establisher(core, on_registry, auth, gate, handler). Assemblies must not hand-roll the alkcall establisher plumbing. - Tests: miss at the gate →
channel:open_failedwith reasonunknown_resource, no channel allocated; gate-pass → existing serving flow unchanged; the residual race shape (gate passes, route gone at handler time) still reaps cleanly; scope gate unchanged (tunnel:forwarded, runs before the establisher; pin the order). - Update the in-code docs that describe the miss as assembly-side-only
(
make_forwarded_op_handlerdoc,Register…forwardeddoc).
W2 (alkssh): adopt the establisher (dedicated session; alkssh repo)
- Move
pump_forwarded_arrival's route lookup into the new gate (theListenRouterlookup becomes the establisher's check); the residual handler keepsdecline_arrival("correlation-miss", …)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; producer-side generic arm fires with a parseable reason), so the race window no longer produces a zero-signal pump.
- Fold alkssh's em-dash doc cleanup into its release for this change ("cleanup rides the code-update release"; the user-owned task, out of this plan).
W3 (alksocks): adopt the establisher (dedicated session; alksocks repo)
- Move
CorrelationRegistrylookup into the new gate; retire the prose warn (the miss becomes a typed failure at the open; residual logging aligns tocorrelation-missatdebug). - Fold alksocks' em-dash doc cleanup into its release for this change (user-owned, out of this plan).
Ordering
W1 → {W2, W3} (the dependent waves can run in parallel; each is its own session). Em-dash cleanup rides each repo's release for its wave and is otherwise out of scope here.
Acceptance criteria (plan level)
- W1: ADR landed;
…_with_establishersurface landed; tests green (cargo test, clippy--all-targets -D warnings, fmt, wasm check;--all-featuresas far as features exist today); review 003 status updated to resolved (W1 absorbed; W2/W3 pointed). - W2: alkssh serves the gate shape; stale-token arrival produces a
typed call-plane failure; residual class named
correlation-missatdebug; alkssh release includes its doc cleanup. - W3: alksocks serves the gate shape; prose variant retired; residual logging aligned; release includes its doc cleanup.
- The family names the class one way in its event surface;
composed
-Rtraces read coherently end to end.
References
docs/reviews/003-correlation-miss-arrival-class-alkssh-input.md(the ask; this plan resolves it)docs/architecture/decisions/008-listen-metadata-forwarded-op.md§3 (the serving shape this amends); alkcall ADR-049 (the establisher posture being extended);docs/architecture/wire.md§The Open Ops (the pinneddetails.reasonvocabulary, unextended by this plan)src/producer.rs(the generic arm; the forwarded-op serving half); alksshsrc/tunnel_map.rs(pump_forwarded_arrival,ListenRouter); alksockssrc/composed/mod.rs(make_forwarded_handler,CorrelationRegistry)- alkssh
docs/plans/implementation.md("Still booked with their owners" (the booking this filing unblocks)