docs(adr): amendments pinning the single-publish fix — marked-pub contract (047 am.4), control surface (052), resource enumerators (053), op/register forward-through + marked refusal (022 am.)

Per review 011 §6 sequencing: the four amendment documents drafted
before code. All pins, no options — the hedged alternatives are stated
as rejected with rationale:
- ADR-047 amendment 4: the marked-pub open contract (review 011 §1/§2's
  seven pins — marker semantics, publish_schema refusal, reserved input
  key + dispatch strip, wrapper-as-responder-of-record, ack-timing
  sentence, relay translation, client put-open capability) plus the
  registration invariants that make stubs unregistrable (§4.8).
- ADR-052 (new): channel/control control-handle surface — establisher-
  contributed ChannelControl, wrapper-owned registry, channel:no_control_handle.
- ADR-053 (new): channel/resources/subscribe live resource enumerators —
  snapshot-then-changes, scan-once aggregation, empty seed.
- ADR-022 amendment: announced unmarked Sub/Pub forward through the real
  forwarding shapes; marked announcements refused (MARKED_SPEC_UNSUPPORTED).
This commit is contained in:
glm-5.3-flash committed 2026-10-13 08:27:50 +00:00
1 parent 4eae18f539
commit df4d4d3a9e
4 files changed
+618 -3

No files matched your search

@@ -2,7 +2,7 @@
## Status
Accepted (amended 2026-06-26, 2026-07-13, and 2026-07-16 — see "Amendments" below; the 2026-07-16 amendment per ADR-045 §5 removes `CallClient::connect`; amendment 2026-09-03 — the bootstrap-op set and the connect-side serving loop, see "Amendment (2026-09-03)" below; amendment 2026-09-04 — the `op/register` collision policy, in that amendment's "Collision policy" paragraph)
Accepted (amended 2026-06-26, 2026-07-13, and 2026-07-16 — see "Amendments" below; the 2026-07-16 amendment per ADR-045 §5 removes `CallClient::connect`; amendment 2026-09-03 — the bootstrap-op set and the connect-side serving loop, see "Amendment (2026-09-03)" below; amendment 2026-09-04 — the `op/register` collision policy, in that amendment's "Collision policy" paragraph; amendment 2026-10-13 — announced Sub/Pub forward-through and marked-spec refusal (review 010 S-04), see "Amendment (2026-10-13)" below)
## Context
@@ -622,4 +622,59 @@ shared dial seam is `alknet-client`; `spawn_dispatch` is the
protocol-crate take-over that consumes the dial's `Connection`.
See [client-and-adapters.md](../crates/call/client-and-adapters.md)
§"CallClient" for the reframed operational spec.
§"CallClient" for the reframed operational spec.
## Amendment (2026-10-13 — review 010 S-04: announced Sub/Pub forward-through, marked-spec refusal)
`op/register`'s announced Sub/Pub handling shipped as invocation-failing
stubs (`INVALID_OPERATION_TYPE` on every invocation of an advertised,
discoverable op — review 010 S-04, nine published versions). The
amendment replaces the stubs with the real forwarding machinery and
closes the marked-spec hole the stubs sat in:
1. **Unmarked `Sub` announcements** register as real
`HandlerKind::Stream` handlers
(`make_streaming_forwarding_handler`) — a nested composition that
cannot invoke them anyway (`env.invoke` is request/response-only,
ADR-046 §6), but the overlay now carries a genuine working forward
of the remote stream, not an advertised-always-failing body.
2. **Unmarked `Pub` announcements** register as real
`HandlerKind::Sink` handlers (`make_sink_forwarding_handler`) —
same posture; the shapes already exist in-tree (`from_call`'s own
import path).
3. **Marked (`channel_open`) announcements — any type — are refused at
`op/register`** with a typed error (`MARKED_SPEC_UNSUPPORTED`):
marked ops are channel-machinery ops by their own marker contract
(ADR-047 §2 — the data plane is the allocated channel's
`BiStream`). Forwarding a marked op is incoherent by the marker's
own semantics — a `Sub`-side forward would deliver the
`{channel_id}` ack of a channel that exists only on the remote
side; a `Pub`-side forward would stream call-plane chunks into a
surface alkcall's amendment 4 rejects. The announcing peer's
sanctioned compositions are the relay
(`ChannelRelay::register_relay_openable`) for a hub, and direct
consumption (`ChannelClient`) otherwise. The same refusal applies
to overlay imports generally: `CallConnection::register_imported`
and the generic registration path refuse marked specs that did not
come through the channel-machinery seam (ADR-047 amendment 4
§4.8), so a marked spec can no longer land anywhere as an
advertised-always-failing or advertised-but-unusable body.
The stub-era rationale ("nested composition is request/response-only;
the streaming/sink forwarding shapes ride on the `from_call` import
path") explained why the *stub body* existed, not why the *announcement
was accepted*; it was reviewed and rejected in review 010 (S-04) — the
rationale may justify not implementing nested streaming composition,
but not accepting and advertising an announcement that cannot serve it.
Door type: one-way. The refusal code and the marked-spec overlay
invariant are wire-visible (announcing peers observe the rejection) and
join the stable error set per ADR-016. The handler-kind mapping for
unmarked announcements reuses the existing forwarding shapes — no new
surface.
References: review 010 S-04 (the stub),
`src/registry/op_register.rs` (the handler), ADR-047 amendment 4 §4.8
(the marked-spec registration invariant this enforces on the wire
side), ADR-046 §6 (the composition boundary), ADR-051 (the relay
composition marked announcements are refused in favor of).