docs(adr): ADR-008 Amendment 2 — the forwarded op's serving-side establishment phase + the correlation-miss vocabulary
- 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
This commit is contained in:
1 parent
aa3db39e3e
commit
7d2b6d11f0
2 files changed
+168
-13
No files matched your search
@@ -3,7 +3,9 @@
|
||||
## Status
|
||||
|
||||
Accepted (2026-09-16); amended 2026-09-18 (the correlation token —
|
||||
`listen` reply field + forwarded-params key, see Amendment 1)
|
||||
`listen` reply field + forwarded-params key, see Amendment 1); amended
|
||||
2026-11-03 (the forwarded op's serving-side establishment phase + the
|
||||
correlation-miss vocabulary, see Amendment 2)
|
||||
|
||||
## Context
|
||||
|
||||
@@ -185,9 +187,12 @@ the listen-opener** — accept-as-open, the `forwarded-tcpip` shape:
|
||||
exposing a listener and dialing egress are different capabilities.
|
||||
- The opener-side serving shape: `register_openable_with_establisher`
|
||||
as-is (no establisher — the forwarded channel needs no
|
||||
establishment; its data plane starts immediately), ACL-gated by the
|
||||
scope, handler = correlate the open (via `listen`, the correlation
|
||||
token) to the waiting
|
||||
establishment; its data plane starts immediately — **amended by
|
||||
Amendment 2**: the served shape gains an establisher variant, the
|
||||
injected correlation gate; this sentence records the pre-amendment
|
||||
posture, which stays a valid shape — see Amendment 2), ACL-gated by
|
||||
the scope, handler = correlate the open (via `listen`, the
|
||||
correlation token) to the waiting
|
||||
session, accept the `BiStream`, pump against the local BIND client's
|
||||
halves. The correlation registry is assembly-side bookkeeping —
|
||||
the protocol provides the op and the params, not the
|
||||
@@ -338,4 +343,114 @@ establisher's reply surface (§2 gains `listen`).
|
||||
delta vs the pre-amendment ADR is exactly: the reply gains the
|
||||
optional `listen` field, the forwarded params rename `channel` →
|
||||
`listen` with token semantics. Nothing else shipped against either
|
||||
(no consumer exists), so the change is pre-consumer and legal.
|
||||
(no consumer exists), so the change is pre-consumer and legal.
|
||||
|
||||
## Amendment 2 (the serving-side establishment phase + the correlation-miss vocabulary, 2026-11-03)
|
||||
|
||||
Resolves review 003 (`docs/reviews/003-correlation-miss-arrival-class-alkssh-input.md`)
|
||||
via `docs/plans/003-correlation-miss-resolve.md` §Decisions 1–4. The
|
||||
decision stands — bind-first establisher, accept-as-open, the
|
||||
`bound`/`listen` reply fields, the forwarded op, `tunnel:forwarded`.
|
||||
What changes: **the serving side of the forwarded op (§3) gains an
|
||||
establishment phase** — §3's sentence "no establisher — the forwarded
|
||||
channel needs no establishment; its data plane starts immediately"
|
||||
(marked inline above) is the text this amendment amends.
|
||||
|
||||
### The miss class this closes (the tri-vocabulary history)
|
||||
|
||||
A forwarded open whose `listen` token no longer routes — the
|
||||
stale/missing-token arrival class — is currently served
|
||||
establisher-less everywhere (alkssh's door, alksocks' composed BIND,
|
||||
and this crate's built-in shape). That is the one posture exception
|
||||
to ADR-049's "a refused open is a typed call error, never a phantom
|
||||
channel": the open succeeds at the call plane, declines post-open in
|
||||
the assembly, and the producer-side pump EOFs with no signal. The
|
||||
family has named the class three ways:
|
||||
|
||||
- **alkssh** — `correlation-miss` at `debug`:
|
||||
`observe::decline_arrival(row, "correlation-miss", listen)` +
|
||||
teardown-at-birth (`src/tunnel_map.rs`; tokens removed at session
|
||||
teardown by the shared per-fabric-leg `ListenRouter`).
|
||||
- **alksocks** — prose at `warn`: "forwarded open with no waiting
|
||||
session" (`src/composed/mod.rs:497`).
|
||||
- **alktunnels** — the `handler_error`-class generic arm at `warn`
|
||||
(the bind-first accept loop's failed-open branch,
|
||||
`src/producer.rs:838-854`), which fires only for the
|
||||
connection-gone/`NOT_FOUND`/ACL-refused subclass — an in-session
|
||||
miss (route removed while the fabric connection lives) succeeds at
|
||||
the call plane and logs nothing at all.
|
||||
|
||||
Amendment 2 retires the prose variant and the fabric-side silence.
|
||||
|
||||
### The decisions
|
||||
|
||||
1. **The serving side gains an establisher variant — the gate is
|
||||
injected.** The protocol crate cannot hold the assembly's
|
||||
correlation map, so the establisher's check is an
|
||||
assembly-provided gate closure over the forwarded params
|
||||
(`TunnelForwardedParams`); the crate wraps that closure into the
|
||||
alkcall `OpenEstablisher` dance and registers via
|
||||
`register_openable_with_establisher` (alkcall 0.10.x, verified
|
||||
present). Assemblies must NOT hand-roll the alkcall establisher
|
||||
plumbing — the crate-owned registration surface is the only
|
||||
supported path. The gate is a lookup, not a dial: establishment
|
||||
stays fast, bounded by the usual establisher rules only.
|
||||
2. **A stale/missing token fails the open as a typed
|
||||
`channel:open_failed`.** The crate maps the gate's failure to
|
||||
alkcall's `EstablishmentError::UnknownResource`, so the reply is
|
||||
`channel:open_failed` with `details.reason = "unknown_resource"` —
|
||||
no phantom channel is ever born (ADR-049's posture, extended here
|
||||
to the forwarded op's serving side). The waiting session IS a
|
||||
resource that is gone; **`unknown_resource` is reused as-is and
|
||||
the wire vocabulary is NOT extended**: `wire.md`'s open-op sections
|
||||
(the pinned `details.reason ∈ dial_failed / unknown_resource /
|
||||
resource_shortage / handler_error / timeout` list and its
|
||||
§The Forwarded Op) are untouched by this amendment — there is no
|
||||
reason-class ADR, no new wire value. (The one serving-shape prose
|
||||
line in `wire.md` — "no establisher" under §The Forwarded Op —
|
||||
syncs with the API task's in-code doc updates, plan 003 W1; this
|
||||
ADR does not touch `wire.md`.)
|
||||
3. **Gate order is pinned: the scope gate precedes the establisher.**
|
||||
The registry runs `tunnel:forwarded` ACL before the open op's
|
||||
establishment phase (alkcall's open-op wrapper order: registry
|
||||
gates — schema, then ACL — then the wrapper's allocate →
|
||||
establisher → handler). A scope-less producer is `FORBIDDEN`
|
||||
before any gate lookup; the gate never sees an unauthorized open.
|
||||
4. **The residual post-open race keeps teardown-at-birth, named
|
||||
`correlation-miss` at `debug`.** A token that vanishes between
|
||||
establisher pass and handler run — the narrow race the gate cannot
|
||||
close — keeps §3's opener-half posture, unchanged: the assembly
|
||||
handler declines, its early return reaps the channel
|
||||
teardown-at-birth (R-02). Its event name is **`correlation-miss`**
|
||||
(alkssh's shipped vocabulary wins — it is published; alksocks'
|
||||
prose variant retires), at `debug` **assembly-side** — the
|
||||
protocol crate's built-in handler holds no map, so this is the
|
||||
assemblies' convention this ADR records, not code this crate runs.
|
||||
The producer-side generic arm (the accept loop's failed-open
|
||||
branch) stays at `warn`, now carrying the typed reason from the
|
||||
open failure instead of the prose one.
|
||||
|
||||
### Additive-only surface
|
||||
|
||||
The base `register_tunnel_forwarded_openable` (establisher-less, the
|
||||
post-open shape) stays for compatibility; the establisher variant
|
||||
(`register_tunnel_forwarded_openable_with_establisher`) is the
|
||||
recommended posture, and new assemblies take it by default. Both ride
|
||||
the same op id, params, scope, and reply surface — the wire delta of
|
||||
this amendment is empty.
|
||||
|
||||
### References
|
||||
|
||||
- `docs/reviews/003-correlation-miss-arrival-class-alkssh-input.md`
|
||||
(the ask; situation + framing this amendment resolves)
|
||||
- `docs/plans/003-correlation-miss-resolve.md` §Decisions, §Verified
|
||||
findings (the tri-vocabulary survey; W1 is this amendment + the API
|
||||
task), §Ordering (W2 alkssh / W3 alksocks adoption waves)
|
||||
- alkcall ADR-049 (the establishment phase and typed-error posture
|
||||
extended here); alkcall 0.10.x
|
||||
`register_openable_with_establisher` and
|
||||
`EstablishmentError::UnknownResource → unknown_resource` (verified)
|
||||
- alkssh `src/tunnel_map.rs` (`ListenRouter`, `decline_arrival`);
|
||||
alksocks `src/composed/mod.rs:497`; alktunnels
|
||||
`src/producer.rs:838-854` — the three miss sites this amendment
|
||||
converges (source for §The miss class above)
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: tunnels/corrmiss-adr
|
||||
name: "ADR: the forwarded op's establishment phase + the correlation-miss vocabulary (resolves review 003 — decisions)"
|
||||
status: pending
|
||||
status: completed
|
||||
depends_on: []
|
||||
scope: narrow
|
||||
risk: medium
|
||||
@@ -77,18 +77,18 @@ format precedent).
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Amendment 2 to ADR-008 (or the successor ADR) lands under
|
||||
- [x] 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
|
||||
- [x] The amended/superseded §3 sentence is marked, not silently
|
||||
replaced
|
||||
- [ ] Wire-vocabulary non-extension is explicit (`unknown_resource`
|
||||
- [x] Wire-vocabulary non-extension is explicit (`unknown_resource`
|
||||
reused; `wire.md` §The Open Ops untouched — state that)
|
||||
- [ ] Status block of
|
||||
- [x] 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
|
||||
- [x] No code changes; doc build clean (`cargo doc --no-deps` clean is
|
||||
NOT required for pure docs/ edits — verify md renders coherently
|
||||
instead)
|
||||
|
||||
@@ -108,8 +108,48 @@ format precedent).
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
- Shape chosen: **Amendment 2 to ADR-008** (the recommendation held —
|
||||
it did not balloon; §4/§5 needed no restating).
|
||||
- Before writing, verified the ground against the shipped sources:
|
||||
alkcall 0.10.1 `EstablishmentError` (variants
|
||||
`DialFailed`/`UnknownResource`/`ResourceShortage`/`HandlerError`;
|
||||
`.reason()` maps `UnknownResource → "unknown_resource"`,
|
||||
operations.rs:592-596) and `register_openable_with_establisher`
|
||||
(operations.rs:761); the open-op wrapper order
|
||||
(`policy.check_open` — the ACL — then allocate → establisher →
|
||||
handler, operations.rs:1085-1103) pins the "scope gate precedes the
|
||||
establisher" invariant. Cargo.toml pins `alkcall = "0.10.1"`, so
|
||||
the ADR says "0.10.x, verified present".
|
||||
- The amended §3 sentence (lines 187-196, the serving-shape bullet)
|
||||
is marked inline with "**amended by Amendment 2**" — the
|
||||
pre-amendment posture is recorded, not replaced (the Amendment 1
|
||||
style).
|
||||
- Deliberately NOT touched: `wire.md` (the amendment states its
|
||||
`details.reason` vocabulary is unextended; the one serving-shape
|
||||
prose line — "no establisher" under §The Forwarded Op — syncs with
|
||||
the API task per the amendment's note) and review 003's status
|
||||
block (doc-sync task owns it).
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
Amendment 2 landed at
|
||||
`docs/architecture/decisions/008-listen-metadata-forwarded-op.md`
|
||||
(2026-11-03): the forwarded op's serving side gains an establishment
|
||||
phase — an assembly-provided gate closure (over
|
||||
`TunnelForwardedParams`) the crate wraps into the alkcall
|
||||
`OpenEstablisher` dance via `register_openable_with_establisher`,
|
||||
with failures mapped to `EstablishmentError::UnknownResource` so a
|
||||
stale/missing `listen` token is a typed
|
||||
`channel:open_failed`/`unknown_resource` before any channel is born.
|
||||
`unknown_resource` is reused as-is; the wire vocabulary is unextended
|
||||
and `wire.md` is untouched. Gate order pinned (`tunnel:forwarded` ACL
|
||||
precedes the establisher); the residual post-open race keeps
|
||||
teardown-at-birth with the canonical assembly-side name
|
||||
`correlation-miss` at `debug` (producer-side generic arm stays `warn`
|
||||
with the typed reason); the base
|
||||
`register_tunnel_forwarded_openable` stays, the establisher variant
|
||||
is the recommended default posture; the wire delta of the amendment
|
||||
is empty. The tri-vocabulary history (alkssh `correlation-miss`
|
||||
debug, alksocks prose warn, alktunnels `handler_error`-class generic
|
||||
warn + the fabric-side silence) is recorded with sources. Doc-only;
|
||||
no code changes.
|
||||
Reference in new issue
Block a user