/** * Capability Broker contract (P9) — the single governed egress boundary. * * IIOS prepares idempotent outbound commands; the broker gates them through * policy, enforces the returned obligations, and routes to a provider. In dev the * provider is a sandbox (no network); a real provider is a binding/config swap. * This is the concrete realization of the `capability` platform port. */ import type { DataClass } from './events'; import type { PolicyDecision } from './ports'; /** One obligation the broker must enforce before/at egress. */ export type PolicyObligation = PolicyDecision['obligations'][number]; export type CapabilityOutcome = 'SENT' | 'BLOCKED' | 'FAILED' | 'RATE_LIMITED'; export interface CapabilityRequest { /** Dotted capability name, e.g. "channel.send". */ capability: string; scopeId?: string; channelType: string; target: string; payload: Record; idempotencyKey: string; /** CMP purpose code for the consent check (e.g. 'outbound_message', 'marketing'). */ purpose?: string; dataClass?: DataClass; } export interface CapabilityResult { providerRef: string; outcome: CapabilityOutcome; errorCode?: string; latencyMs?: number; /** The CMP consent receipt this egress went out under (provenance). */ consentReceiptRef?: string; } /** What a provider reports; the broker normalizes `outcome` into CapabilityResult. */ export interface ProviderResult { providerRef: string; outcome: string; errorCode?: string; latencyMs?: number; } /** * A pluggable egress provider. Sandbox (no network) by default; real providers * (WhatsApp/SMTP/HTTP webhook) implement the same shape. Must be idempotent and * must surface transport errors as FAILED rather than throwing. */ export interface CapabilityProvider { readonly name: string; readonly channelTypes: string[]; readonly capabilities: { canSend: boolean; maxPayloadBytes?: number }; send(req: CapabilityRequest): Promise; }