Surfaces¶
Surfaces, handlers, cross-cutting concerns.
Every command and query has one handler and as many surface adapters as needed. A new surface is a new adapter; the core does not move. For the adapters in service today, see Stack/Backend.
Surface aggregate¶
The Trust BC carries a Surface aggregate (Phase B, shipped 2026-05-19) that names the ingress shape each call arrives through. Three seeded values today, modeled as a closed SurfaceKind enum:
| Surface | Kind | Default policy binding |
|---|---|---|
| HTTP | HTTP |
V2 bootstrap policy |
| MCP stdio | MCP_STDIO |
โ |
| MCP streamable HTTP | MCP_STREAMABLE_HTTP |
โ |
surface_id threads through every command + query handler, the Authorize port, Policy evaluation, and the idempotency-cache key namespace (so the same Idempotency-Key on different surfaces does not collide). The composition root injects the resolved surface_id per-request; tests use a canonical NIL_SENTINEL_ID from cora.infrastructure.routing.
Cross-cutting¶
- Idempotency. Create-style commands accept an
Idempotency-Keyheader (IETF draft-07). The store remembers(surface_id, key, command_name, body_hash) โ resultand replays on retry. The composite key per draft-07 ยง5 keeps cross-surface keys isolated. - Authentication. Bearer-token at the HTTP edge (
BearerAuthMiddleware+TokenVerifierper IdP); legacyX-Principal-Idfrom a verifying proxy when no IdPs are configured. See Stack/Auth. - Authorization. Every command and query calls an
Authorizeport (authorize(subject, command_name, conduit_id, surface_id)). Policy model is ReBAC; cross-principal contract tests (BOLA) cover read endpoints across 12 aggregates. - Observability. Structured logs, distributed tracing, and metrics on every handler. Trace context is the source of truth for correlation id.
- Migrations. Forward-only. A rollback is a new compensating migration. CI verifies hash-sum integrity and runs a safety scan on net-new migrations.