docs(arch): ADR-066 — move from_jsonschema to alknet-http as HTTP-backed single-endpoint adapter

from_jsonschema was in alknet-call as a schema-only placeholder with a
NOT_FOUND handler — broken (an op in the registry needs a real handler)
and in the wrong crate (alknet-call has no HTTP client; a useful
from_jsonschema needs reqwest like from_openapi). ADR-066 moves it to
alknet-http as a real reqwest-backed single-endpoint adapter for
non-standard/non-OpenAPI REST endpoints, functionally similar to
from_openapi but one endpoint at a time. FromJsonSchema provenance
stays in alknet-call (now a handler-bearing leaf).

- New ADR-066 (supersedes ADR-017 §5 from_jsonschema clause + ADR-022
  FromJsonSchema row; both amended with strikethrough + pointer)
- Updated specs: call/client-and-adapters, call/README,
  call/operation-registry, http/http-adapters (new from_jsonschema
  section), http/overview, http/README, arch README + overview
- New task: tasks/http/adapters/from-jsonschema.md (depends on
  from-openapi; includes alknet-call cleanup of the broken placeholder)
- Old task tasks/call/client/from-jsonschema.md marked superseded

taskgraph validate: 116 tasks valid
This commit is contained in:
glm-5.2 committed 2026-07-09 11:42:56 +00:00
1 parent 06ab5db459
commit 97456bc608
13 files changed
+739 -95

No files matched your search

+5 -4
View File
@@ -14,7 +14,7 @@ Structured RPC: operations, request/response, streaming subscriptions, and servi
|----------|--------|-------------|
| [call-protocol.md](call-protocol.md) | draft | CallAdapter, hand-rolled EventEnvelope framing (no irpc — ADR-064), stream model, PendingRequestMap, bidirectional calls |
| [operation-registry.md](operation-registry.md) | draft | OperationSpec, Handler, OperationRegistry, AccessControl, service discovery, hand-rolled framing (no irpc — ADR-064) |
| [client-and-adapters.md](client-and-adapters.md) | draft | CallClient (outbound connection opener), from_call / from_jsonschema, OperationAdapter trait, adapter location map, no-env-vars invariant, exchange-of-operations pattern |
| [client-and-adapters.md](client-and-adapters.md) | draft | CallClient (outbound connection opener), from_call, OperationAdapter trait, adapter location map, no-env-vars invariant, exchange-of-operations pattern (from_jsonschema moved to alknet-http per ADR-066) |
## Applicable ADRs
@@ -36,7 +36,8 @@ Structured RPC: operations, request/response, streaming subscriptions, and servi
| [014](../../decisions/014-secret-material-flow-and-capability-injection.md) | Secret Material Flow and Capability Injection | Call protocol carries no secret material; capabilities injected at assembly layer |
| [015](../../decisions/015-privilege-model-and-authority-context.md) | Privilege Model and Authority Context | `internal` = authority switch not ACL skip; External/Internal visibility; handler identity + scoped env |
| [016](../../decisions/016-abort-cascade-for-nested-calls.md) | Abort Cascade for Nested Calls | `call.aborted` cascades to descendants; default `abort-dependents`, `continue-running` opt-in |
| [017](../../decisions/017-call-protocol-client-and-adapter-contract.md) | Call Protocol Client and Adapter Contract | `CallClient` opens connections; `from_call` imports remote ops; connection direction independent of call direction |
| [017](../../decisions/017-call-protocol-client-and-adapter-contract.md) | Call Protocol Client and Adapter Contract | `CallClient` opens connections; `from_call` imports remote ops; connection direction independent of call direction. ~~`from_jsonschema` clause superseded by ADR-066~~ |
| [066](../../decisions/066-from-jsonschema-as-http-adapter.md) | `from_jsonschema` as HTTP-Backed Single-Endpoint Adapter in alknet-http | Moved `from_jsonschema` from `alknet-call` (broken schema-only placeholder) to `alknet-http` as a real reqwest-backed single-endpoint adapter; `FromJsonSchema` provenance stays in `alknet-call` as a leaf |
| [022](../../decisions/022-handler-registration-provenance-and-composition-authority.md) | Handler Registration, Provenance, and Composition Authority | Registration bundle carries provenance, composition authority, scoped env, capabilities |
| [023](../../decisions/023-operation-error-schemas.md) | Operation Error Schemas | Operations declare domain errors; `call.error` carries typed `details`; adapter fidelity |
| [024](../../decisions/024-operation-registry-layering.md) | Operation Registry Layering | Curated (static) + session/connection overlays (dynamic); `OperationEnv` as trait-object integration point; `OperationContext.env` split into `scoped_env` (data) and `env` (dispatch trait) |
@@ -79,8 +80,8 @@ Structured RPC: operations, request/response, streaming subscriptions, and servi
7. **No secret material on the wire**: The call protocol carries no private keys, API keys, mnemonics, or decrypted credentials. Handlers receive outbound credentials through `OperationContext.capabilities`, injected at the assembly layer. See ADR-014.
8. **Abort cascades to descendants**: `call.aborted` for a parent request cascades to all non-terminal descendants. Default `abort-dependents`; `continue-running` opt-in. See ADR-016.
9. **Internal calls switch authority context, not skip ACL**: The `internal` flag marks composition-originated calls. ACL runs against the handler's composition authority, not the caller's and not as a blanket skip. Operations have External/Internal visibility. Scoped composition env bounds reachability. See ADR-015, ADR-022.
10. **Provenance determines composition capability**: Only `Local` and `Session` ops can compose. Leaves (`FromOpenAPI`, `FromMCP`, `FromCall`) are forwarding stubs — they don't get composition authority or a scoped env. The assembly layer is the sole grantor of composition authority. See ADR-022.
10. **Provenance determines composition capability**: Only `Local` and `Session` ops can compose. Leaves (`FromOpenAPI`, `FromMCP`, `FromCall`, `FromJsonSchema`) are forwarding stubs — they don't get composition authority or a scoped env. The assembly layer is the sole grantor of composition authority. See ADR-022. (`FromJsonSchema` is now a real HTTP-forwarding leaf per ADR-066, not a schema-only placeholder.)
11. **Connection direction is independent of call direction**: Who opens the QUIC connection is a connection-layer concern, not a protocol-layer concern. Both sides can call each other once connected. The `CallAdapter` accepts connections; the `CallClient` opens them; both produce the same `CallConnection` and dispatch through the same loop. See ADR-017, [client-and-adapters.md](client-and-adapters.md).
12. **Peer authorization via `AccessControl`**: A remote peer's call is authorized by `AccessControl::check(peer_identity)` against the op's `AccessControl` — the same mechanism that gates every other call. No `remote_safe` flag, no `trusted_peer` bypass. An op with `AccessControl::default()` is callable by any peer; an op with `required_scopes` is callable only by peers whose `Identity.scopes` satisfy them; an op with `Visibility::Internal` is never callable from the wire. See ADR-029.
13. **Adapter trait lives with the types; implementations live with their transport**: `OperationAdapter` is in `alknet-call`; `from_call`/`from_jsonschema` are in `alknet-call` (QUIC / pure parse); `from_openapi`/`from_mcp`/`to_openapi`/`to_mcp` are in `alknet-http` (reqwest / axum). `alknet-call` stays lean — no HTTP client, no HTTP server. See [client-and-adapters.md](client-and-adapters.md).
13. **Adapter trait lives with the types; implementations live with their transport**: `OperationAdapter` is in `alknet-call`; `from_call` is in `alknet-call` (QUIC); `from_jsonschema`/`from_openapi`/`from_mcp`/`to_openapi`/`to_mcp` are in `alknet-http` (reqwest / axum). `alknet-call` stays lean — no HTTP client, no HTTP server. (`from_jsonschema` was originally in `alknet-call` as a schema-only placeholder; ADR-066 moved it to `alknet-http` as a real HTTP-backed adapter.) See [client-and-adapters.md](client-and-adapters.md).
14. **No handler reads outbound credentials from any source other than `OperationContext.capabilities`** (no-env-vars invariant): the credential injection path is vault → assembly layer → `Capabilities` → `HandlerRegistration.capabilities` → `OperationContext.capabilities` → handler. Downstream consumers' `std::env::var` reads are unreachable because the assembly layer never calls `Default::default()`. See ADR-014, [client-and-adapters.md](client-and-adapters.md).
@@ -1,6 +1,6 @@
---
status: draft
last_updated: 2026-07-02
last_updated: 2026-07-09
---
# alknet-call — Client and Adapters
@@ -9,14 +9,16 @@ The outbound half of the call protocol: opening connections, importing remote
operations, and the adapter contract that ties import-style adapters together.
This document covers what ADR-017 specced but the server-side implementation
(`call-protocol.md`, `operation-registry.md`) did not include — the `CallClient`
that *opens* a connection, the `from_call`/`from_jsonschema` adapters, and the
`OperationAdapter` trait. The server-side `CallAdapter` and `CallConnection`
that *opens* a connection, the `from_call` adapter, and the
`OperationAdapter` trait. (`from_jsonschema` was originally specced here
too, but ADR-066 moved it to `alknet-http` — see §"from_jsonschema" below.)
The server-side `CallAdapter` and `CallConnection`
dispatch loop are covered in `call-protocol.md`; this document covers the
client-side connection-establishment half and the adapter surface.
## What
This document specifies four components, all in `alknet-call`:
This document specifies three components, all in `alknet-call`:
1. **`CallClient`** — opens an outbound `alknet/call` QUIC connection and
produces a `CallConnection`. The dispatch loop is shared with the
@@ -27,12 +29,19 @@ This document specifies four components, all in `alknet-call`:
via `services/list` + `services/schema` (already implemented in
`registry/discovery.rs`) and registers them in the connection's Layer 2
overlay as `FromCall`-provenance leaves with forwarding handlers.
3. **`from_jsonschema`** — schema-only registration: produces
`HandlerRegistration` bundles with no handler, for validation, discovery,
and composition-graph construction without a runtime.
4. **`OperationAdapter` trait** — the async trait that `from_call`,
3. **`OperationAdapter` trait** — the async trait that `from_call`,
`from_openapi`, `from_mcp`, and `from_jsonschema` all implement.
> **`from_jsonschema` moved.** ADR-066 moved `from_jsonschema` from
> `alknet-call` to `alknet-http` and gave it a real reqwest-backed
> forwarding handler (it was a broken schema-only placeholder before).
> It is now an HTTP-backed single-endpoint adapter for non-standard /
> non-OpenAPI / basic REST endpoints, functionally similar to
> `from_openapi` but one endpoint at a time. See
> [`crates/http/http-adapters.md`](../http/http-adapters.md) §"from_jsonschema".
> The `FromJsonSchema` provenance variant stays in `alknet-call`
> (`OperationProvenance`); only the adapter implementation moved.
It also records two cross-cutting architectural mechanisms that the adapter
surface rests on:
@@ -58,8 +67,8 @@ trait is the enabling gap for `alknet-http`'s `from_openapi`/`from_mcp`.
ADR-017 specced this surface. This document is the spec that operationally
fills the gap ADR-017 left to implementation: the `CallClient` API, the
`from_call`/`from_jsonschema` flows, the trait signature, the adapter
location, the credential invariant, and the bilateral pattern. The gap
`from_call` flow, the trait signature, the adapter location, the credential
invariant, and the bilateral pattern. The gap
analysis (`docs/research/alknet-call-completion/gap-analysis.md`) identified
four decisions (DC-1..4) needed before implementation. DC-1 was initially
resolved by ADR-028 (`remote_safe`/`trusted_peer`), but a subsequent research
@@ -377,29 +386,31 @@ want to disclose the originator. See [ADR-032](../../decisions/032-forwarded-for
### from_jsonschema
Schema-only registration: produces `HandlerRegistration` bundles with no
handler (`FromJsonSchema` provenance). Used for validation, discovery, and
composition-graph construction without a runtime — type-checking a composition
plan without executing it, building a UI of available operations without
standing up the transports, etc.
`from_jsonschema` was originally specified here (ADR-017 §5) as a
schema-only adapter in `alknet-call` — a placeholder handler returning
`NOT_FOUND`. That was broken: an op in the registry needs a real handler,
and the "schema-only, no handler" concept conflated schema validation
(a planning activity that doesn't need a registry entry) with operation
registration (which always needs a handler).
```rust
pub fn from_jsonschema(
spec: OperationSpec,
schema: serde_json::Value,
) -> HandlerRegistration;
```
[ADR-066](../../decisions/066-from-jsonschema-as-http-adapter.md) moved
`from_jsonschema` to `alknet-http` as an HTTP-backed single-endpoint
adapter: the caller supplies an `OperationSpec` + `HttpServiceConfig` +
path template + method, and the adapter builds one
`HandlerRegistration` with a real reqwest forwarding handler and
`FromJsonSchema` provenance. It is functionally similar to `from_openapi`
but one endpoint at a time, for non-standard / non-OpenAPI / basic REST
endpoints that don't have a full OpenAPI document. See
[`crates/http/http-adapters.md`](../http/http-adapters.md) §"from_jsonschema".
Distinct from `from_call` (gap analysis DC-5, confirmed not a decision):
The schema-validation-without-a-handler use case (the original stated
purpose) is served by consuming `OperationSpec` directly — the spec
already carries the input/output JSON Schemas. No adapter, no registry
entry, no handler is needed for that.
| | `from_jsonschema` | `from_call` |
|---|---|---|
| Schema source | Provided directly (caller fetches, passes in) | Discovered over wire (`services/list` + `services/schema`) |
| Handler at call time | None (schema-only, `FromJsonSchema` provenance) | Forwards over QUIC (`FromCall` provenance, leaf) |
| Use case | Type validation, discovery, composition graph construction | Actually invoking remote operations |
Keeping them separate preserves the "schema-only, no execution" use case
(type checking, safe composition planning without runtime).
The `FromJsonSchema` provenance variant stays in `alknet-call`
(`OperationProvenance` in `registry/registration.rs`); only the adapter
implementation moved.
### OperationAdapter trait
@@ -433,8 +444,9 @@ door, recorded here.
Implementations:
- `FromCall` — QUIC-backed (in `alknet-call`).
- `FromJsonSchema` — pure parse, no transport (in `alknet-call`).
- `FromOpenAPI` — HTTP-backed (in `alknet-http`).
- `FromJsonSchema` — HTTP-backed, single-endpoint (in `alknet-http` per
ADR-066; was a broken schema-only placeholder in `alknet-call`).
- `FromMCP` — MCP streamable-HTTP-backed (in `alknet-http`, feature-gated).
The `to_*` adapters (`to_openapi`, `to_mcp`) are outbound projections, not
@@ -451,12 +463,12 @@ dependencies live.**
alknet-call (lean — no HTTP client, no HTTP server)
├── OperationAdapter trait (the contract — async, per ADR-017 §5)
├── from_call (QUIC — discovers remote ops via call protocol)
├── from_jsonschema (pure parse — caller fetches the doc, passes it in)
└── CallClient (outbound connection opener — the #1 gap)
alknet-http (owns HTTP server + HTTP client — separate crate, separate Phase 0)
├── ProtocolHandler for h2/http1.1/h3 (axum server — inbound HTTP)
├── from_openapi (parse OpenAPI doc + reqwest forwarding handler)
├── from_jsonschema (single-endpoint reqwest forwarding handler — ADR-066)
├── to_openapi (generate OpenAPI doc from local registry)
├── from_mcp (feature-gated) (import remote MCP tools over streamable HTTP — reqwest)
└── to_mcp (feature-gated) (expose local ops as MCP tools over streamable HTTP — axum)
@@ -591,12 +603,10 @@ Based on the gap analysis and the downstream unblock chain:
already-implemented `services/list` + `services/schema` discovery API.
3. **`OperationAdapter` trait** (enabling) — the async trait. Small,
standalone, unblocks `alknet-http` Phase 1.
standalone, unblocks `alknet-http` Phase 1 (including `from_jsonschema`
per ADR-066).
4. **`from_jsonschema`** (medium, standalone) — schema-only registration, no
handler. Small.
5. **DC-1 resolution** (peer-graph routing model, ADR-029) — the
4. **DC-1 resolution** (peer-graph routing model, ADR-029) — the
peer-keyed overlay + `AccessControl`-based peer authorization model that
replaces ADR-028's `remote_safe`/`trusted_peer`. This is a structural
change to `CompositeOperationEnv` (→ `PeerCompositeEnv`), the dispatch
@@ -617,10 +627,12 @@ Based on the gap analysis and the downstream unblock chain:
## Constraints
- **No HTTP in alknet-call.** `from_openapi`/`from_mcp`/`to_openapi`/`to_mcp`
live in `alknet-http`. The `OperationAdapter` trait and the QUIC-backed
adapters (`from_call`, `from_jsonschema`) live in `alknet-call`. See
Adapter Location Map.
- **No HTTP in alknet-call.** `from_openapi`/`from_mcp`/`from_jsonschema`/
`to_openapi`/`to_mcp` live in `alknet-http`. The `OperationAdapter`
trait and the QUIC-backed adapter (`from_call`) live in `alknet-call`.
`from_jsonschema` was originally (mis)placed in `alknet-call` as a
schema-only placeholder; ADR-066 moved it to `alknet-http` as a real
HTTP-backed adapter. See Adapter Location Map.
- **No secret material on the wire.** `CallCredentials` carries vault-derived
material for the *outbound* connection (TLS identity, auth token); the
call protocol's wire format carries no private keys, API keys, or decrypted
@@ -669,7 +681,8 @@ Based on the gap analysis and the downstream unblock chain:
| Decision | ADR | Summary |
|----------|-----|---------|
| Call protocol client and adapter contract | [ADR-017](../../decisions/017-call-protocol-client-and-adapter-contract.md) | `CallClient` opens connections; `from_call` imports remote ops; connection direction independent of call direction; trait is async; adapters produce `HandlerRegistration` bundles |
| Call protocol client and adapter contract | [ADR-017](../../decisions/017-call-protocol-client-and-adapter-contract.md) | `CallClient` opens connections; `from_call` imports remote ops; connection direction independent of call direction; trait is async; adapters produce `HandlerRegistration` bundles. ~~`from_jsonschema` clause superseded by ADR-066~~ |
| `from_jsonschema` as HTTP-backed single-endpoint adapter in alknet-http | [ADR-066](../../decisions/066-from-jsonschema-as-http-adapter.md) | Moved `from_jsonschema` from `alknet-call` (broken schema-only placeholder) to `alknet-http` as a real reqwest-backed single-endpoint adapter; `FromJsonSchema` provenance stays in `alknet-call` as a leaf |
| Peer-graph routing model (DC-1, supersedes ADR-028) | [ADR-029](../../decisions/029-peer-graph-routing-model.md) | Peer-keyed overlays + `PeerRef` routing; peer authorization via existing `AccessControl::check(peer_identity)`; retires `remote_safe`/`trusted_peer` |
| PeerEntry and Identity.id decoupling | [ADR-030](../../decisions/030-peerentry-and-identity-id-decoupling.md) | `PeerId` source changes from UUID to `Identity.id` (= `PeerEntry.peer_id`, stable across key rotation); `Identity.id` decoupled from crypto material on the fingerprint path |
| Forwarded-for identity | [ADR-032](../../decisions/032-forwarded-for-identity.md) | `forwarded_for` field on `call.requested` and `OperationContext`; the `from_call` handler populates it; metadata only, never used by `AccessControl::check` |
@@ -1,6 +1,6 @@
---
status: draft
last_updated: 2026-07-05
last_updated: 2026-07-09
---
# Operation Registry
@@ -74,7 +74,7 @@ Operation names use slash-based paths without a leading slash, aligned with URL
The `namespace` field is derived from the name: for `fs/readFile` it's `fs`, for `agent/chat` it's `agent`. It's a convenience accessor for ACL matching and service grouping.
Visibility (ADR-015) controls whether an operation is callable from the wire. `External` operations are wire-facing — they appear in `services/list` and accept `call.requested` from clients. `Internal` operations are composition-only — they return `NOT_FOUND` (not `FORBIDDEN`) when called from the wire, and do not appear in `services/list`. The assembly layer declares visibility at registration. All import adapters (`from_openapi`, `from_mcp`, `from_jsonschema`, `from_call`) register operations as `Internal` by default (they're composition material, not directly callable); the handler that composes them is `External`.
Visibility (ADR-015) controls whether an operation is callable from the wire. `External` operations are wire-facing — they appear in `services/list` and accept `call.requested` from clients. `Internal` operations are composition-only — they return `NOT_FOUND` (not `FORBIDDEN`) when called from the wire, and do not appear in `services/list`. The assembly layer declares visibility at registration. All import adapters (`from_openapi`, `from_mcp`, `from_jsonschema`, `from_call`) register operations as `Internal` by default (they're composition material, not directly callable); the handler that composes them is `External`. (`from_jsonschema` is now a real HTTP-backed adapter in `alknet-http` per ADR-066, not the schema-only placeholder it was.)
### AccessControl
@@ -383,7 +383,7 @@ pub enum OperationProvenance {
FromOpenAPI, // HTTP forwarding stub (from_openapi), leaf
FromMCP, // MCP forwarding stub (from_mcp), leaf
FromCall, // QUIC forwarding stub (from_call), leaf locally
FromJsonSchema, // JSON Schema definition, no handler — schema only
FromJsonSchema, // HTTP forwarding stub (from_jsonschema, single endpoint), leaf
Session, // Agent-written, sandboxed, can compose within sandbox
}
```
@@ -394,9 +394,19 @@ pub enum OperationProvenance {
| `FromOpenAPI` | No (leaf) | No | Internal |
| `FromMCP` | No (leaf) | No | Internal |
| `FromCall` | No (leaf in local registry) | No | Internal |
| `FromJsonSchema` | N/A (no handler) | No | N/A |
| `FromJsonSchema` | No (leaf) | No | Internal |
| `Session` | Yes (within sandbox) | Yes — scopes set at sandbox creation | Internal always |
> **ADR-066 update.** `FromJsonSchema` was originally a schema-only
> provenance with no handler (the old row read "N/A (no handler) /
> N/A"). ADR-066 moved `from_jsonschema` to `alknet-http` as a real
> HTTP-backed single-endpoint adapter with a reqwest forwarding
> handler. `FromJsonSchema` is now a leaf, same trust model as
> `FromOpenAPI` (HTTP endpoint trusted; handler is a forwarding stub).
> The "schema-only, no handler" concept is removed — schema validation
> without a handler is served by consuming `OperationSpec` directly,
> not by registering a placeholder op.
#### CompositionAuthority
The declared authority (label + scopes + resources) the handler operates
@@ -906,7 +916,8 @@ The `Capabilities` type holds non-serializable, zeroized secret material. It doe
| Handler registration, provenance, and composition authority | [ADR-022](../../decisions/022-handler-registration-provenance-and-composition-authority.md) | Registration bundle carries provenance, composition authority, scoped env, capabilities; dispatch path reads from bundle |
| Operation registry layering | [ADR-024](../../decisions/024-operation-registry-layering.md) | Curated (static, immutable) + session and connection overlays (dynamic); `OperationEnv` as trait-object integration point; `OperationContext.env` split into `scoped_env` (data) and `env` (dispatch trait) |
| Operation error schemas | [ADR-023](../../decisions/023-operation-error-schemas.md) | Operations declare domain errors; `call.error` carries typed `details`; adapter fidelity for `from_openapi`/`to_openapi` |
| Call protocol client and adapter contract | [ADR-017](../../decisions/017-call-protocol-client-and-adapter-contract.md) | `from_call`/`from_jsonschema`/`OperationAdapter` produce `HandlerRegistration` bundles; adapter-registered ops are `Internal` leaves. Surface specced in [client-and-adapters.md](client-and-adapters.md) |
| Call protocol client and adapter contract | [ADR-017](../../decisions/017-call-protocol-client-and-adapter-contract.md) | `from_call`/`OperationAdapter` produce `HandlerRegistration` bundles; adapter-registered ops are `Internal` leaves. Surface specced in [client-and-adapters.md](client-and-adapters.md). ~~`from_jsonschema` clause superseded by ADR-066~~ |
| `from_jsonschema` as HTTP-backed single-endpoint adapter | [ADR-066](../../decisions/066-from-jsonschema-as-http-adapter.md) | Moved `from_jsonschema` from `alknet-call` (broken schema-only placeholder) to `alknet-http` as a real reqwest-backed single-endpoint adapter; `FromJsonSchema` provenance stays in `alknet-call` as a leaf (now handler-bearing, not "no handler") |
| Peer-graph routing model (supersedes ADR-028) | [ADR-029](../../decisions/029-peer-graph-routing-model.md) | Peer-keyed overlays + `PeerRef` routing; peer authorization via `AccessControl::check(peer_identity)`; retires `remote_safe`/`trusted_peer` (the field this doc's `HandlerRegistration` previously gained) |
| Forwarded-for identity | [ADR-032](../../decisions/032-forwarded-for-identity.md) | `forwarded_for` field on `OperationContext` and `call.requested`; metadata only — `AccessControl::check` never reads it; the `from_call` handler populates it |
| ~~Peer-scoped registry filtering~~ (superseded) | ~~[ADR-028](../../decisions/028-callclient-peer-scoped-registry-filtering.md)~~ | ~~`remote_safe` marking on `HandlerRegistration`~~ — superseded by ADR-029 |