Ride the alkcall 0.10 gateway ownership seam (review 012, ADR-048 amendment) into the door layer: - HttpAdapter::with_ownership_provider / HttpAdapter::with_static_ownership_fallback mirror alkcall's builder shape; OwnershipProvider re-exported next to GatewayDispatch - RouterState carries the wiring; GatewayState::dispatch is the single spine builder for both the gateway routes and the MCP nest - loud default passes through: a resource_type-gated op on an unwired spine is refused (FORBIDDEN envelope -> 403/401) on HTTP exactly as on the native wire - WS native-session path untouched (consults ownership natively) fix: with_ws_max_sessions never stored the fresh session-slot semaphore; later builder calls silently reverted the cap. Builder state now assembled through one router_state() helper. infra: fuzz/shared follows to alkcall 0.10 (two alkcall copies in one build would type-clash); alkhttp 0.8.0 per the dep-wave convention. Verification: cargo test (444 pass, incl. 3 new call_resource_gated_* HTTP-surface pins), clippy --all-targets -D warnings, fmt --check, test --all-features (520), fuzz corpus replay (21/21), doc.
3.8 KiB
ADR-072: HTTP-Surface Ownership Wiring (Gateway + MCP)
Status
Accepted
Context
alkcall 0.10.0 landed the gateway ownership seam (alkcall review 012,
downstream evidence from alkgit's LFS POC): the dispatch spine's
previously-silent static Identity.resources fallback becomes loud — a
resource_type-gated op served through an unwired spine is refused
with a FORBIDDEN error envelope unless the deployment wires a
runtime ownership provider
(GatewayDispatch::with_ownership_provider) or declares the static
fallback explicitly
(GatewayDispatch::with_static_ownership_fallback). The change closes
the two-authorization-paths drift: a namespace-ACL-gated op served
through an HTTP door previously ran against the token-carried static
claim, while the same op on the native wire consulted the revocable
grant table.
alkhttp is the only live spine consumer. It constructs the spine
internally in two places — the gateway endpoints' per-request spine
(gateway::routes::GatewayState) and the MCP nest's spine
(server::build_router) — so an assembly layer wiring a provider for
the native wire cannot reach those spines through alkcall's API. Once
alkhttp rode 0.10, any resource_type-gated op in the registry would
break on the HTTP surface even for deployments that wired providers
correctly.
Decision
alkhttp mirrors alkcall's builder shape on HttpAdapter and threads
the wiring into every spine it constructs.
HttpAdapter::with_ownership_provider(Arc<dyn OwnershipProvider>)andHttpAdapter::with_static_ownership_fallback()— the two alkcall-named opt-ins, one method each, no alkcall-specific vocabulary changed.OwnershipProvideris re-exported fromalkhttp::gatewaynext toGatewayDispatch.- The wiring lives on
RouterStateand is threaded byGatewayState::dispatch()(routes) andRouterState::dispatch()(the MCP nest — the gateway routes extractGatewayStateviaFromRef, soGatewayStateis the single wiring point). - Both spines share one wiring: the gateway endpoints and the MCP surface are the same door contract; no separate MCP wiring exists.
The door contract (alkcall review 012, unchanged here): any
deployment serving resource_type-gated ops through the HTTP surface
must wire the same provider the native wire consults —
visible-surface = authorized-surface. The loud default passes through
from alkcall unchanged: an unwired, undeclared spine refuses a
resource_type-gated op with the spine's FORBIDDEN envelope, which
the gateway error mapping serves as 403 (with identity) / 401
(without).
The WS native-session path needs no wiring — it speaks the native call protocol, which consults ownership natively in alkcall's serving layer (alkcall ADR-048).
Consequences
Positive:
- The HTTP surface cannot silently diverge from the native wire's
ownership truth — alkcall's loud default is inheritable at the door
layer, and
with_static_ownership_fallbackkeeps the static-claims posture a code-review-visible declaration here too. - alkcall's builder shape is mirrored on alkhttp's builder, so an assembly layer configures both spines the same way.
Negative:
- Deployments upgrading alkhttp to the 0.10-riding release must wire
the provider (or declare the fallback) before serving
resource_type-gated ops over HTTP — the 403 refusal is the reminder, not a compile error.
References
- alkcall review 012
(
/workspace/@alkdev/alkcall/docs/reviews/012-gateway-ownership-seam-consumer-input.md) — the consumer evidence and the two recorded decisions - alkcall 0.10.0 CHANGELOG (the loud-default behavior break)
- ADR-048 — the WS path this does not touch
- Review 008 — the same consumption round's alkhttp-filed findings (AH-1, AH-2)