{"openapi":"3.1.0","info":{"title":"Mnemom API","description":"Trust infrastructure for AI agents. Transparent alignment verification, behavioral drift detection, and accountability primitives.","version":"1.0.0","contact":{"name":"Mnemom","url":"https://mnemom.ai","email":"support@mnemom.ai"},"license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0"}},"servers":[{"url":"https://api.mnemom.ai/v1","description":"Production"}],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"tags":[{"name":"A2A","description":"Public A2A AgentCard projection of the canonical alignment card, with embedded AAP attestation extension (cards-as-primitive Phase 5)."},{"name":"Agents","description":"Agent registration, lifecycle, and metadata."},{"name":"Agent Containment","description":"Containment policies and quarantine controls."},{"name":"Agent Groups","description":"Lightweight logical tags for bucketing an org's agents — the unscored counterpart to the scored Teams primitive. No cards, coherence, reputation, or feature gate."},{"name":"Alignment","description":"Alignment manifest CRUD — canonical `/v1/alignment/<scope>/<scope_id>` surface across platform / org / team / agent (cards-as-primitive Phase 4)."},{"name":"Analyze","description":"Behavioral analysis endpoints."},{"name":"Aletheia Support","description":"In-product Aletheia assistant MVP (issue #2195) — chat + voice adapters over one shared answer core. Gated behind ALETHEIA_SUPPORT_MVP_ENABLED + the ALETHEIA_SUPPORT_ALLOWLIST identity allowlist (whose default is the whole @mnemom.ai domain, and which may be set to \"*\" to admit every authenticated identity), fail-closed 404 for every non-allowed caller. Dark by default; whether it is customer-facing depends on that env var per deployment."},{"name":"Attestation","description":"AAP attestation token JWKS surface and platform-admin signing-key rotation (cards-as-primitive Phase 5)."},{"name":"Auth","description":"Authentication, sessions, and access management."},{"name":"Billing","description":"Subscription, usage, and invoicing."},{"name":"Blog","description":"Public blog content."},{"name":"Card Templates","description":"Org-level alignment and protection card templates."},{"name":"Catalog","description":"Discovery surface for the 25-entry Mnemom value catalog v1 (cards-as-primitive Phase 4)."},{"name":"Checkpoints","description":"Integrity checkpoints and proof artifacts."},{"name":"Conscience Values","description":"Org-level conscience-value configuration."},{"name":"Consent","description":"GDPR Art. 7(1) append-only consent audit log (MNE-477). Public write (banner POSTs each decision); admin-only read/export. Stores a pseudonymous subject id + truncated IP only — in addition to client-side enforcement."},{"name":"Domains","description":"Domain ownership claims (DNS-TXT verified) + the public no-PII claim-status projection."},{"name":"MCP Servers","description":"MCP-server ownership claims (DNS-TXT verified on the origin domain) + the public no-PII claim-status projection for the IITR MCP-readiness rubric."},{"name":"Dojo","description":"Dojo demo shared contracts (MNE-517): SimEvent SSE narrative feed + ephemeral compute-key issuance. Internal/demo surface, not customer-facing."},{"name":"Coherence","description":"Coherence report-claim round-trip (MNE-1379): single-use claim-intent tickets that carry a report claim across the sign-up/email-confirm/return round-trip so no session token rides the URL — only the opaque `mci_…` ticket."},{"name":"Drift","description":"Drift detection and resolution."},{"name":"Enforcement","description":"Enforcement-mode configuration and queries."},{"name":"Governance","description":"Operator-actionable governance signals (ADR-048)."},{"name":"Integrity","description":"AIP integrity checkpoints and verdicts."},{"name":"Intelligence","description":"Intelligence reports and queries."},{"name":"Licensing","description":"License management."},{"name":"Network","description":"Protection Network L4 thermometer read surface. Public-aggregate disclosure: any authenticated principal may read; rows carry no per-tenant identifiers."},{"name":"OAuth","description":"OAuth 2.1 authorization-code + PKCE flow for MCP clients (MNE-328). Identity delegated to Supabase GoTrue; mnemom-api mints its own short-lived MCP-scoped tokens. Includes RFC 7591 dynamic client registration and RFC 7009 revocation."},{"name":"On-Chain","description":"On-chain verification and proofs."},{"name":"Organizations","description":"Org-level resources and management."},{"name":"Policy","description":"Policy evaluation and configuration."},{"name":"Postures","description":"Trust posture management (ADR-045)."},{"name":"Protection","description":"Protection manifest CRUD — canonical `/v1/protection/<scope>/<scope_id>` surface across platform / org / team / agent (cards-as-primitive Phase 4)."},{"name":"Recipes","description":"Customer-facing detection-recipe surface — FN/FP reports. Distinct from the Admin recipe-promotion surface and the Internal seeding surface."},{"name":"Reclassification","description":"Reclassification workflows."},{"name":"Reputation","description":"Per-agent reputation scores."},{"name":"Risk","description":"Risk assessment endpoints."},{"name":"Safe House","description":"Safe House threat detection and quarantine."},{"name":"Sideband","description":"Sideband detection queries (legacy; sunsetting)."},{"name":"Team Reputation","description":"Team-level reputation aggregates."},{"name":"Teams","description":"Team-scope resources."},{"name":"Tools","description":"Mnemom-side tools registry — per-tool class+domain+schema metadata (cards-as-primitive Phase 4)."},{"name":"Telemetry","description":"Public browser-RUM ingest (Core Web Vitals). Anon-eligible by design, rate-limited, closed-enum dimensions only — emits spans, persists nothing."},{"name":"Traces","description":"AP-Trace artifacts and queries."},{"name":"Transparency","description":"Append-only public log of every canonical card identity ever composed. Signed Merkle root + per-row inclusion proofs (cards-as-primitive Phase 5)."},{"name":"Trust","description":"Protection Network L5 public-trust surface — security advisories, IoC feed (STIX 2.1), and platform-admin CMS for both."},{"name":"Mu","description":"mu-engine ledger proxy — thin pass-through to the mnemom-mu Worker (balances, budgets, staff reads). api owns auth/RBAC/org-context; the ledger lives in mnemom-mu (issue #2357)."},{"name":"Verification","description":"Trace verification endpoints."},{"name":"Webhook Notifications","description":"Webhook event subscription management."},{"name":"Webhooks","description":"Webhook delivery and lifecycle."},{"name":"Misc","description":"Miscellaneous operator-facing endpoints (contact, enterprise inquiries, compliance)."},{"name":"Feedback","description":"Authenticated in-product feedback ingest (Aletheia Customer Voice). Redacted + consent-gated + idempotent."},{"name":"Notifications","description":"Reactive notification channels — SSE stream + signed-webhook subscriptions for canonical card changes (cards-as-primitive Phase 5)."},{"name":"Presentations","description":"Investor/data-room presentations + per-viewer grants (MNE-1428, \"Inside Mnemom\"). Admin create/invite/revoke; authed-user read scoped to active grants. Internal/demo surface, not customer-facing."},{"name":"Aletheia","description":"Aletheia grounded Q&A answer core (MNE-1937). Internal/preview surface, not customer-facing."},{"name":"AletheiaVoice","description":"In-product Aletheia voice register (MNE-1944), the customer/anon sibling of the Presentations deck voice register. DARK: feature-flag + allowlist gated, zero customer exposure until promoted; cookie/bearer-authed like any other customer route."}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Supabase JWT token in Authorization: Bearer header"},"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-Mnemom-Api-Key","description":"Mnemom API key (mnm_... format)"},"ServiceRole":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Supabase service role bearer JWT. Used by /blog admin operations that talk directly to Supabase. NOT used by /internal/* or /v1/arena/internal/* — those use the custom-header schemes below."},"InternalKeyAuth":{"type":"apiKey","in":"header","name":"X-Internal-Key","description":"Internal service-to-service shared secret, timing-safe compared against INTERNAL_API_KEY. Used by /internal/* gateway routes (compose, agents, webhooks emit)."},"ServiceKeyAuth":{"type":"apiKey","in":"header","name":"X-Service-Key","description":"Service-to-service shared secret, timing-safe compared against MNEMOM_SERVICE_KEY. Used by /v1/arena/internal/*, /v1/on-chain/*, and the /v1/internal/* readers consumed by the reputation cron."},"CoherenceTokenAuth":{"type":"http","scheme":"bearer","description":"Per-cell coherence bearer token. Provisioned in 1Password vault `mnemom-coherence` (one item per receiver). Value compared against COHERENCE_<NAME>_SERVICE_TOKEN_EXPECTED. Used by /v1/internal/coherence/* and /v1/internal/governance/dispatch."},"ArenaCandidateTokenAuth":{"type":"http","scheme":"bearer","description":"Dedicated arena writer token (ADR-004 §\"Arena dedicated writer token\"). Compared against ARENA_RECIPE_CANDIDATE_TOKEN. The token's only capability is writing recipe candidates with writer_identity='arena-bypass' (stamped server-side). Used by POST /v1/internal/recipe-candidates."},"CustomerVoiceTokenAuth":{"type":"http","scheme":"bearer","description":"Customer Voice API bearer token. Timing-safe compared against CUSTOMER_VOICE_API_TOKEN. Grants access to all /v1/internal/feedback/* endpoints (MNE-1876). No customer-facing or reporter-read capability."},"CookieAuth":{"type":"apiKey","in":"cookie","name":"mnemom_session","description":"HttpOnly, Secure, SameSite=Lax cookie issued by /v1/auth/sign-in (or the SSO / email-callback flows). The value is an AES-256-GCM-encrypted blob of {access_token, refresh_token, issued_at, auth_method}. Browser clients include this automatically with `credentials: \"include\"`."},"LicenseJwtAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"License JWT (HS256, HMAC-signed with LICENSE_SIGNING_SECRET). Used by self-hosted deployment instances to authenticate `/v1/deployments/heartbeat`. Not interchangeable with the Supabase user JWT."},"AgentAuth":{"type":"apiKey","in":"header","name":"X-Mnemom-Agent-Proof","description":"Agent possession proof: the full SHA-256 hex digest of `${apiKey}|${agentName}` (or `${apiKey}` for an unnamed singleton agent) — the same `hash_proof` primitive used by POST /v1/agents claim, link-agent, and verify-binding. The server resolves the agent by `agent_hash = proof[:16]`. The agent's *own* identity (ADR-API-001 third auth class) — distinct from ApiKeyAuth (`X-Mnemom-Api-Key`, which resolves a user/account, not an agent)."}},"parameters":{"AgentId":{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"},"description":"Agent identifier (e.g. smolt-abc123)"},"OrgId":{"name":"org_id","in":"path","required":true,"schema":{"type":"string"},"description":"Organization identifier (e.g. org-abc12345)"},"EndpointId":{"name":"endpoint_id","in":"path","required":true,"schema":{"type":"string"},"description":"Webhook endpoint identifier (e.g. whe-abc12345)"},"TeamId":{"name":"team_id","in":"path","required":true,"schema":{"type":"string"},"description":"Team identifier (UUID)"},"SubmissionId":{"name":"submission_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Aletheia Customer Voice feedback submission identifier (UUID)."}},"responses":{"BadRequest":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"PaymentRequired":{"description":"Paid feature gate — the caller's plan doesn't include this operation's feature flag. Emitted by `requireFeature` / `requireEntitlement` in `src/org/rbac.ts`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InternalServerError":{"description":"Server error — request was well-formed but the server failed to fulfill it. Typically a downstream dependency (DB / RPC / external API) returned an unexpected error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Conflict":{"description":"Resource conflict — the request cannot proceed because of a current state conflict (e.g., resource already exists, version mismatch, in-flight idempotency key with a different body).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"UnprocessableEntity":{"description":"Request was well-formed but semantically invalid (e.g., business-rule validation failure, malformed YAML inside a JSON payload).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Gone":{"description":"The target is no longer available — a single-use, time-boxed resource (e.g. a claim-intent ticket) that has been consumed or has expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"TooManyRequests":{"description":"Rate-limit exceeded. The global per-IP limiter (100 requests/minute, applied to every `/v1/*` route) rejected this request. Back off until the window resets — `Retry-After` carries the cooldown in seconds and `X-RateLimit-Reset` the absolute reset time.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":1}},"X-RateLimit-Limit":{"description":"Requests permitted per window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window (0 on a 429).","schema":{"type":"integer","minimum":0}},"X-RateLimit-Reset":{"description":"Unix epoch seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"BadGateway":{"description":"An upstream dependency returned an invalid response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"PermanentRedirect":{"description":"Permanent Redirect (RFC 7538). This URL is deprecated; follow `Location` to the canonical `/v1/<resource>/<scope>/<scope_id>` shape. Method and body are preserved across the redirect — modern clients re-issue the same `PUT` / `POST` / `DELETE` against the target unchanged.","headers":{"Location":{"description":"Canonical URL to follow. Preserves the original query string.","schema":{"type":"string","format":"uri-reference"}},"Deprecation":{"description":"RFC 8594 — `true` for every legacy alignment / protection URL.","schema":{"type":"string","enum":["true"]}},"Sunset":{"description":"RFC 8594 — HTTP-date after which the legacy URL stops redirecting and returns 410 Gone. Currently `Fri, 15 Jan 2027 00:00:00 GMT`, aligned with the cards-as-primitive Phase 5 GA window.","schema":{"type":"string","format":"http-date"}},"Link":{"description":"RFC 8288 — points to the deprecation guide (`rel=\"deprecation\"`). Currently `<https://docs.mnemom.ai/concepts/cards-as-resources>; rel=\"deprecation\"; type=\"text/html\"`.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Always `cards/url-canonicalization/v1` on this response.","schema":{"type":"string","enum":["cards/url-canonicalization/v1"]}}}},"ServiceUnavailable":{"description":"An upstream dependency is currently unavailable. The request was not processed; retry after the cooldown window.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"PreconditionFailed":{"description":"The `If-Match` header carried a stale ETag (the spec was updated since the caller read it). Run `GET` to fetch the current ETag, splice your changes onto the latest state, and retry the write. Cards-as-primitive Phase 4 W3.1.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"PreconditionRequired":{"description":"The `If-Match` header is missing on a sub-resource write. Sub-resource verbs use optimistic concurrency — read the current ETag via `GET`, then retry with `If-Match: \"sha256:...\"`. Cards-as-primitive Phase 4 W3.1.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RequestEntityTooLarge":{"description":"Request body exceeded the per-endpoint size cap. Cards-as-primitive sub-resource verbs cap each primitive body at 64 KiB; full-card PUTs cap at 128 KiB (alignment) / 64 KiB (protection).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","description":"Canonical error envelope (ADR-API-001 conv 1). `error` is always an object — never a bare string. Every 4xx/5xx response across the API conforms to this shape; the runtime helper is `src/http-errors.ts::buildErrorBody`.","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","pattern":"^[a-z][a-z0-9_]*$","description":"Stable, machine-matchable failure identifier (lowercase snake_case). Clients may branch on this; the string is part of the contract.\n\n**Status-class defaults** — emitted when no caller code is supplied (`errorCodeForStatus(status)`): `bad_request` (400), `unauthorized` (401), `forbidden` (403), `not_found` (404), `method_not_allowed` (405), `conflict` (409), `gone` (410), `precondition_failed` (412), `payload_too_large` (413), `unsupported_media_type` (415), `unprocessable_entity` (422), `precondition_required` (428), `rate_limited` (429), `internal_error` (500), `not_implemented` (501), `bad_gateway` (502), `service_unavailable` (503), `gateway_timeout` (504). Fallback `error` for unmapped statuses.\n\n**Caller-supplied codes** — handlers may pass an explicit `code` for a specific failure class. Examples: `agent_not_found`, `invalid_hash_proof`, `already_linked`, `idempotency_conflict`, `feature_gated`, `schema_validation_failed`, `no_token`, `bad_canonical_payload`.\n\n**Care-framed sub-resource codes** — the cards-as-primitive surface passes its stable care code-string straight through as `error.code`. Examples: `if_match_absent`, `if_match_stale`, `if_match_malformed`, `primitive_validation_failed`."},"message":{"type":"string","description":"Human-readable, care-framed explanation of the failure."},"details":{"description":"Optional structured context for the failure (any JSON value: object, array, or primitive). Common shapes: validation findings list, idempotency-conflict diff, `{presented_etag, current_etag}` on a stale `If-Match`, etc. Mirrors the helper's `details?: unknown`."}}}}},"Agent":{"type":"object","description":"An agent. GET /v1/agents/{id} returns one of TWO projections by authorization: an ORGANIZATION-MEMBER (owner) caller receives the full agent row (all fields below); a NON-OWNER receives a reduced public projection (id, name, claimed, created_at, last_seen, status, avatar_url). additionalProperties is left open because the owner row is the full DB row and grows as agent-settings columns are added (ADR-053 / proof / DDR); over-constraining it would 500 the endpoint on the next migration under /v1 response enforcement.","additionalProperties":true,"properties":{"id":{"type":"string"},"claimed":{"type":"boolean","description":"Public projection only: whether the agent has been claimed by a user."},"avatar_url":{"type":["string","null"]},"claimed_by":{"type":["string","null"],"description":"Owner projection: user id that claimed the agent."},"created_by":{"type":["string","null"],"description":"Owner projection: user id that created the agent (provenance)."},"org_id":{"type":["string","null"],"description":"Owner projection: the agent's org binding (ADR-062 authz boundary)."},"agent_proof_hash":{"type":["string","null"],"description":"Owner projection: captured hash_proof of the bound key (mig 263)."},"agent_proof_captured_at":{"type":["string","null"],"format":"date-time"},"deleted_at":{"type":["string","null"],"format":"date-time","description":"Owner projection: soft-delete timestamp (null when live)."},"agent_hash":{"type":"string","description":"First 16 hex chars of `SHA256(apiKey + '|' + agentName)` for named agents, or `SHA256(apiKey)` for unnamed singleton agents. The gateway computes the same value on each request and uses it as the lookup key. See [Agent Identity](https://docs.mnemom.ai/concepts/agent-identity#agent_hash--the-canonical-identity-hash).","example":"a1b2c3d4e5f6a7b8"},"user_id":{"type":["string","null"]},"email":{"type":["string","null"]},"claimed_at":{"type":["string","null"],"format":"date-time"},"last_seen":{"type":["string","null"],"format":"date-time"},"name":{"type":["string","null"],"description":"Agent name (2-32 chars, alphanumeric + hyphens). Present on all list and get responses."},"containment_status":{"type":["string","null"],"enum":["active","paused","killed"],"description":"Containment state of the agent (ADR-053)."},"key_prefix":{"type":["string","null"],"description":"First 8 chars of the bound API key hash — useful for key-rotation debugging."},"status":{"type":"string","enum":["active","offline"]},"caller":{"type":"string","enum":["anonymous","authenticated","org_member"],"description":"Self-describing caller context for THIS response. `org_member` callers receive the full owner record (all fields here); `anonymous`/`authenticated` (non-member) callers receive the reduced public projection (id, name, claimed, created_at, last_seen, status, avatar_url, caller). The differing field set is GOVERNED by this value — read it instead of inferring why a field is absent."},"public":{"type":"boolean","description":"Identity-record visibility axis — whether the agent's IDENTITY RECORD is publicly discoverable. This is DISTINCT from reputation visibility: every registered agent's reputation is public by accountability standard (see `ReputationScore.visibility`). `public` here governs only the identity record, never the Trust Rating."},"aip_enforcement_mode":{"type":["string","null"],"enum":["observe","enforce","nudge"]},"billing_account_id":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"groups":{"type":"array","description":"Active groups this agent belongs to, name-ordered; `[]` when none. Present on org-fleet rows (GET /v1/orgs/{org_id}/agents). Archived groups are excluded.","items":{"type":"object","required":["id","name","color"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"color":{"type":["string","null"],"description":"Group color (hex, e.g. `#0d9488`); `null` when unset."}}}}}},"AlignmentCard":{"type":"object","properties":{"card_id":{"type":"string"},"agent_id":{"type":"string"},"is_active":{"type":"boolean"},"card_json":{"type":"object","description":"Full alignment card JSON per AAP spec"},"conscience_values":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ConscienceValue"}},"issued_at":{"type":"string","format":"date-time"}}},"APTrace":{"type":"object","properties":{"trace_id":{"type":"string"},"agent_id":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"action":{"type":"object","properties":{"type":{"type":"string"},"name":{"type":"string"},"category":{"type":"string"}}},"decision":{"type":"object","properties":{"selected":{"type":"string"},"selection_reasoning":{"type":"string"},"values_applied":{"type":"array","items":{"type":"string"}},"confidence":{"type":["number","null"]}}},"verification":{"type":["object","null"],"properties":{"verified":{"type":"boolean"},"violations":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"severity":{"type":"string"},"description":{"type":"string"}},"additionalProperties":true}}}},"created_at":{"type":"string","format":"date-time"}}},"IntegrityScore":{"type":"object","properties":{"agent_id":{"type":"string"},"total_traces":{"type":"integer"},"verified_traces":{"type":"integer"},"violation_count":{"type":"integer"},"integrity_score":{"type":"number","description":"Value between 0 and 1"},"bounded_refusal_count":{"type":"integer","description":"MNE-596: count of traces AAP structurally flagged but reclassified as a correctly policy-refused attack (AIP independently confirmed clear; no bounded action was ever executed). Logged for transparency — already counted toward verified_traces and excluded from violation_count, so it does not reduce integrity_score."}}},"Checkpoint":{"type":"object","properties":{"checkpoint_id":{"type":"string"},"agent_id":{"type":"string"},"card_id":{"type":"string"},"session_id":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"thinking_block_hash":{"type":"string"},"provider":{"type":"string"},"model":{"type":"string"},"verdict":{"type":"string","enum":["clear","review_needed","boundary_violation","unverified"]},"concerns":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string"},"severity":{"type":"string"},"description":{"type":"string"},"evidence":{"type":"string"}}}},"reasoning_summary":{"type":"string"},"conscience_context":{"type":"object"},"window_position":{"type":"object","properties":{"index":{"type":"integer"},"window_size":{"type":"integer"}}},"analysis_metadata":{"type":"object"},"linked_trace_id":{"type":["string","null"]},"re_evaluated_at":{"type":["string","null"],"format":"date-time"},"original_verdict":{"type":["string","null"]}}},"DriftAlert":{"type":"object","properties":{"alert_id":{"type":"string"},"agent_id":{"type":"string"},"session_id":{"type":"string"},"checkpoint_ids":{"type":"array","items":{"type":"string"}},"sustained_checks":{"type":"integer"},"severity":{"type":"string","enum":["low","medium","high"]},"drift_direction":{"type":"string"},"message":{"type":"string"},"detection_timestamp":{"type":"string","format":"date-time"}}},"ConscienceValue":{"type":"object","required":["type","name","content"],"properties":{"type":{"type":"string","enum":["BOUNDARY","FEAR","COMMITMENT","BELIEF","HOPE"]},"name":{"type":"string"},"content":{"type":"string"}}},"Subscription":{"type":"object","properties":{"subscription":{"type":["object","null"]},"plan_id":{"type":"string"},"status":{"type":"string"},"check_count_this_period":{"type":"integer"}}},"Invoice":{"type":"object","properties":{"id":{"type":"string"},"amount_due":{"type":"integer"},"amount_paid":{"type":"integer"},"currency":{"type":"string"},"status":{"type":"string"},"created":{"type":"integer"},"hosted_invoice_url":{"type":["string","null"]},"invoice_pdf":{"type":["string","null"]}}},"UsageMetrics":{"type":"object","properties":{"daily":{"type":"array","items":{"type":"object","properties":{"rollup_date":{"type":"string","format":"date"},"check_count":{"type":"integer"},"tokens_in":{"type":"integer"},"tokens_out":{"type":"integer"}}}},"summary":{"type":"object","properties":{"checks_used":{"type":"integer"},"checks_included":{"type":"integer"},"overage":{"type":"integer"},"estimated_overage_cost":{"type":"number"},"period_start":{"type":"string","format":"date-time"},"period_end":{"type":"string","format":"date-time"}}}}},"Plan":{"type":"object","properties":{"plan_id":{"type":"string"},"display_name":{"type":"string"},"description":{"type":"string"},"billing_model":{"type":"string","enum":["none","metered","subscription","subscription_plus_metered"]},"base_price_cents":{"type":"integer"},"annual_price_cents":{"type":"integer"},"per_check_price":{"type":"number"},"included_checks":{"type":"integer"},"trace_retention_days":{"type":"integer"},"feature_flags":{"type":"object","properties":{"release_ring":{"type":"string","enum":["internal","early_adopter","ga"],"description":"Release ring controlling feature exposure (MNE-889). Carried in feature_flags alongside the boolean gates; defaults to `ga`."}},"additionalProperties":{"type":"boolean"}},"limits":{"type":"object"},"sort_order":{"type":"integer"}}},"Organization":{"type":"object","properties":{"org_id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"billing_account_id":{"type":["string","null"],"description":"Stripe billing account. NULL for personal orgs (no billing account provisioned)."},"owner_user_id":{"type":["string","null"]},"billing_email":{"type":["string","null"]},"company_name":{"type":["string","null"]},"member_count":{"type":"integer"},"role":{"type":"string","description":"The caller's role in this org (membership-scoped listings only)."},"is_owner":{"type":"boolean","description":"Whether the caller owns this org (membership-scoped listings only)."},"is_personal":{"type":"boolean","description":"Whether this is the caller's auto-provisioned personal org."},"avatar_url":{"type":["string","null"]},"accepted_at":{"type":["string","null"],"format":"date-time","description":"When the caller accepted membership (membership-scoped listings only)."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"OrgMember":{"type":"object","properties":{"user_id":{"type":"string"},"email":{"type":"string"},"role":{"type":"string","enum":["owner","admin","member","viewer","auditor"]},"accepted_at":{"type":"string","format":"date-time"}}},"OrgInvitation":{"type":"object","properties":{"invitation_id":{"type":"string"},"org_id":{"type":"string"},"email":{"type":"string"},"role":{"type":"string"},"token":{"type":"string","description":"Only returned on creation"},"status":{"type":"string","enum":["pending","accepted","revoked","expired"]},"invited_by":{"type":"string"},"expires_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"}}},"License":{"type":"object","properties":{"license_id":{"type":"string"},"account_id":{"type":"string"},"plan_id":{"type":"string"},"feature_flags":{"type":"object","additionalProperties":{"type":"boolean"}},"limits":{"type":"object"},"max_activations":{"type":"integer"},"is_offline":{"type":"boolean"},"issued_at":{"type":"string","format":"date-time"},"expires_at":{"type":"string","format":"date-time"},"revoked_at":{"type":["string","null"],"format":"date-time"},"revoked_reason":{"type":["string","null"]},"notes":{"type":["string","null"]}}},"ApiKeyScope":{"type":"string","enum":["gateway","api:read","api:write","admin:org","admin:platform","api"],"description":"Capability-based scope (ADR-049). `gateway` permits gateway-worker traffic; `api:read` and `api:write` permit identity-scoped GET and write endpoints respectively; `admin:org` permits org-admin operations on orgs the bearer owns/admins (per-request membership re-check); `admin:platform` permits `/v1/admin/*` Mnemom-staff operations (per-request staff-role re-check). The legacy `api` scope is accepted for backward compatibility and aliased to `api:read` + `api:write` at the auth gate; new keys should use the canonical vocabulary."},"ApiKey":{"type":"object","properties":{"key_id":{"type":"string"},"key":{"type":"string","description":"Full secret key, only returned on creation"},"key_prefix":{"type":"string"},"name":{"type":"string"},"org_id":{"type":["string","null"]},"scopes":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyScope"},"description":"Capabilities granted to this key. Default for new keys is `[\"gateway\", \"api:read\", \"api:write\"]`. Admin scopes (`admin:org`, `admin:platform`) are opt-in and gated by the requester's role at mint time. See [API Keys → Scope vocabulary](https://docs.mnemom.ai/guides/api-keys#scope-vocabulary)."},"created_at":{"type":"string","format":"date-time"},"last_used_at":{"type":["string","null"],"format":"date-time"}}},"WebhookEndpoint":{"type":"object","description":"Webhook endpoint with signing secret (only returned on creation and secret rotation)","properties":{"endpoint_id":{"type":"string","description":"Unique identifier (whe-xxxxxxxx)"},"billing_account_id":{"type":"string"},"url":{"type":"string","format":"uri"},"description":{"type":"string"},"signing_secret":{"type":"string","description":"32-byte hex-encoded HMAC signing secret. Only returned on creation and rotation."},"event_types":{"type":"array","items":{"type":"string"},"description":"Subscribed event types. Empty array means all events."},"is_active":{"type":"boolean"},"consecutive_failures":{"type":"integer"},"disabled_at":{"type":["string","null"],"format":"date-time"},"disabled_reason":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"WebhookEndpointPublic":{"type":"object","description":"Webhook endpoint without signing secret (used in list and get responses)","properties":{"endpoint_id":{"type":"string"},"billing_account_id":{"type":"string"},"url":{"type":"string","format":"uri"},"description":{"type":"string"},"event_types":{"type":"array","items":{"type":"string"}},"is_active":{"type":"boolean"},"consecutive_failures":{"type":"integer"},"disabled_at":{"type":["string","null"],"format":"date-time"},"disabled_reason":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"WebhookDelivery":{"type":"object","description":"Webhook delivery log entry","properties":{"delivery_id":{"type":"string","description":"Unique identifier (whd-xxxxxxxx)"},"event_id":{"type":"string"},"endpoint_id":{"type":"string"},"event_type":{"type":"string"},"status":{"type":"string","enum":["pending","delivering","delivered","failed","retrying"]},"attempt_count":{"type":"integer"},"max_attempts":{"type":"integer"},"last_response_status":{"type":["integer","null"],"description":"HTTP status code from last delivery attempt"},"last_error":{"type":["string","null"]},"latency_ms":{"type":["integer","null"],"description":"Round-trip latency in milliseconds"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"SigningKeyInfo":{"type":"object","description":"Ed25519 signing key metadata. Public keys are used to verify IntegrityCertificate signatures.","properties":{"key_id":{"type":"string","description":"Unique key identifier"},"public_key":{"type":"string","description":"Hex-encoded Ed25519 public key"},"algorithm":{"type":"string","description":"Signing algorithm (always Ed25519)"},"created_at":{"type":"string","format":"date-time","description":"When the key was created"},"is_active":{"type":"boolean","description":"Whether the key is currently in use for new signatures"}},"required":["key_id","public_key","algorithm","created_at","is_active"]},"IntegrityCertificate":{"type":"object","description":"Machine-readable cryptographic certificate for an integrity checkpoint. Modeled on C2PA content credentials and W3C Verifiable Credentials.","properties":{"@context":{"type":"string","description":"Namespace identifier","enum":["https://mnemom.ai/aip/v1"]},"type":{"type":"string","enum":["IntegrityCertificate"]},"version":{"type":"string","description":"Certificate format version"},"certificate_id":{"type":"string","description":"Unique certificate identifier (cert-{8 random chars})"},"issued_at":{"type":"string","format":"date-time","description":"ISO 8601 timestamp of certificate issuance"},"subject":{"type":"object","description":"Identifies the checkpoint this certificate attests to","properties":{"checkpoint_id":{"type":"string","description":"Integrity checkpoint ID (ic-{uuid})"},"agent_id":{"type":"string"},"session_id":{"type":"string"},"card_id":{"type":"string"}},"required":["checkpoint_id","agent_id","session_id","card_id"]},"claims":{"type":"object","description":"Analysis verdict and supporting evidence","properties":{"verdict":{"type":"string","enum":["clear","review_needed","boundary_violation","unverified"]},"concerns":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string"},"severity":{"type":"string"},"description":{"type":"string"}}}},"confidence":{"type":"number","description":"Extraction confidence (0.0-1.0)"},"reasoning_summary":{"type":"string"},"analysis_model":{"type":"string"},"analysis_duration_ms":{"type":"number"}}},"input_commitments":{"type":"object","description":"Cryptographic commitments to analysis inputs","properties":{"thinking_block_hash":{"type":"string","description":"SHA-256 hash of the thinking block"},"card_hash":{"type":"string","description":"SHA-256 hash of the Alignment Card"},"values_hash":{"type":"string","description":"SHA-256 hash of conscience values"},"context_hash":{"type":"string","description":"SHA-256 hash of window context"},"model_version":{"type":"string"},"combined_commitment":{"type":"string","description":"SHA-256 of all input fields concatenated"}}},"proofs":{"type":"object","description":"Cryptographic evidence supporting the claims","properties":{"signature":{"type":"object","properties":{"algorithm":{"type":"string","enum":["Ed25519"]},"key_id":{"type":"string"},"value":{"type":"string","description":"Base64-encoded Ed25519 signature"},"signed_payload":{"type":"string","description":"Deterministic JSON string that was signed"}}},"chain":{"type":"object","properties":{"chain_hash":{"type":"string"},"prev_chain_hash":{"type":["string","null"]},"position":{"type":"integer"}}},"merkle":{"type":["object","null"],"description":"Merkle inclusion proof. Null if not yet added to tree.","properties":{"leaf_hash":{"type":"string"},"leaf_index":{"type":"integer"},"root":{"type":"string"},"tree_size":{"type":"integer"},"inclusion_proof":{"type":"array","items":{"type":"object","properties":{"hash":{"type":"string"},"position":{"type":"string","enum":["left","right"]}}}}}},"verdict_derivation":{"type":["object","null"],"description":"SP1 STARK proof. Null if not yet proven.","properties":{"method":{"type":"string","enum":["SP1-STARK"]},"image_id":{"type":"string"},"receipt":{"type":"string","description":"Base64-encoded STARK proof receipt"},"journal":{"type":"string","description":"Base64-encoded public journal"},"verified_at":{"type":"string","format":"date-time"}}}}},"verification":{"type":"object","description":"URLs for independent verification","properties":{"keys_url":{"type":"string","format":"uri"},"certificate_url":{"type":"string","format":"uri"},"verify_url":{"type":"string","format":"uri"}}}},"required":["@context","type","version","certificate_id","issued_at","subject","claims","input_commitments","proofs","verification"]},"MerkleRootResponse":{"type":"object","description":"Current Merkle tree root and metadata for an agent","properties":{"agent_id":{"type":"string","description":"The agent ID"},"merkle_root":{"type":"string","description":"SHA-256 Merkle root hash (hex-encoded)"},"tree_depth":{"type":"integer","description":"Depth of the Merkle tree (ceil(log2(leaf_count)))"},"leaf_count":{"type":"integer","description":"Total number of checkpoint leaves in the tree"},"last_updated":{"type":"string","format":"date-time","description":"When the tree was last updated"}},"required":["agent_id","merkle_root","tree_depth","leaf_count","last_updated"]},"InclusionProofResponse":{"type":"object","description":"Merkle inclusion proof for a checkpoint","properties":{"checkpoint_id":{"type":"string","description":"The checkpoint ID"},"leaf_hash":{"type":"string","description":"SHA-256 leaf hash of this checkpoint"},"leaf_index":{"type":"integer","description":"Index of this leaf in the tree"},"siblings":{"type":"array","description":"O(log N) sibling hashes for proof verification","items":{"type":"object","properties":{"hash":{"type":"string","description":"Hex-encoded sibling hash"},"position":{"type":"string","enum":["left","right"],"description":"Position of sibling relative to the path node"}},"required":["hash","position"]}},"root":{"type":"string","description":"Current Merkle root (hex-encoded)"},"tree_size":{"type":"integer","description":"Total number of leaves in the tree"},"verified":{"type":"boolean","description":"Whether the proof was verified against the stored root"}},"required":["checkpoint_id","leaf_hash","leaf_index","siblings","root","tree_size","verified"]},"ProofStatusResponse":{"type":"object","description":"ZK proof status and metadata for a checkpoint","properties":{"proof_id":{"type":"string","description":"Proof identifier (prf-{8 random chars})"},"checkpoint_id":{"type":"string","description":"The checkpoint this proof is for"},"status":{"type":"string","enum":["pending","proving","completed","failed"],"description":"Current proof status"},"proof_type":{"type":"string","description":"Proof system (e.g., sp1-stark)"},"image_id":{"type":["string","null"],"description":"Guest program image ID (set when proving begins)"},"proving_duration_ms":{"type":["integer","null"],"description":"Wall-clock proving time in milliseconds (set when completed)"},"verified":{"type":"boolean","description":"Whether the proof has been verified"},"verified_at":{"type":["string","null"],"format":"date-time","description":"When the proof was verified (null if not yet verified)"},"created_at":{"type":"string","format":"date-time","description":"When the proof request was created"},"updated_at":{"type":"string","format":"date-time","description":"When the proof record was last updated"}},"required":["proof_id","checkpoint_id","status","proof_type","verified","created_at","updated_at"]},"VerifyCertificateResponse":{"type":"object","description":"Result of certificate verification","properties":{"valid":{"type":"boolean","description":"Whether all verification checks passed"},"checks":{"type":"object","description":"Individual verification check results","properties":{"signature":{"type":"object","properties":{"valid":{"type":"boolean"},"key_id":{"type":"string","description":"The signing key the certificate was verified against. Present when the certificate carries a key id; omitted otherwise (data-dependent)."}},"required":["valid"]},"chain":{"type":"object","properties":{"valid":{"type":"boolean"},"chain_hash":{"type":"string"}},"required":["valid","chain_hash"]},"merkle":{"type":["object","null"],"description":"Null if Merkle proof was not present in the certificate","properties":{"valid":{"type":"boolean"},"root":{"type":"string"}}},"input_commitment":{"type":"object","properties":{"valid":{"type":"boolean"},"commitment":{"type":"string"}},"required":["valid","commitment"]},"verdict_derivation":{"type":["object","null"],"description":"Null if verdict derivation proof was not present","properties":{"valid":{"type":"boolean"},"method":{"type":"string"}}}},"required":["signature","chain","input_commitment"]},"details":{"type":"string","description":"Semicolon-separated human-readable verification details"}},"required":["valid","checks","details"]},"OrgConscienceValue":{"type":"object","description":"A custom conscience value for an organization","properties":{"id":{"type":"string","description":"Value ID (cv-xxx)"},"org_id":{"type":"string"},"name":{"type":"string","maxLength":50},"description":{"type":"string","maxLength":500},"type":{"type":"string","enum":["BOUNDARY","FEAR","COMMITMENT","BELIEF","HOPE"]},"severity":{"type":"string","enum":["advisory","mandatory"]},"scope":{"type":"string"},"is_active":{"type":"boolean"},"sort_order":{"type":"integer"},"created_by":{"type":"string"},"updated_by":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","org_id","name","description","type","severity"]},"OrgConscienceAuditEntry":{"type":"object","description":"Audit log entry for conscience value changes","properties":{"id":{"type":"string"},"org_id":{"type":"string"},"value_id":{"type":["string","null"]},"action":{"type":"string","enum":["create","update","delete","activate","deactivate","reorder","mode_change"]},"actor":{"type":"string"},"changes":{"type":"object"},"metadata":{"type":"object"},"created_at":{"type":"string","format":"date-time"}},"required":["id","org_id","action","actor","created_at"]},"OrgCardTemplate":{"type":"object","description":"Organization alignment card template that all agents inherit","properties":{"org_id":{"type":"string","description":"Organization ID"},"enabled":{"type":"boolean","description":"Whether the template is active"},"template":{"$ref":"#/components/schemas/AlignmentCard","description":"The alignment card template JSON"},"created_by":{"type":"string","description":"User ID who created the template"},"updated_by":{"type":"string","description":"User ID who last updated the template"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["org_id","enabled","template"]},"Team":{"type":"object","properties":{"id":{"type":"string","description":"Team identifier (UUID)"},"org_id":{"type":"string","description":"Organization that owns this team"},"name":{"type":"string","description":"Display name"},"description":{"type":["string","null"],"description":"Optional description"},"status":{"type":"string","enum":["active","archived"],"description":"Team status"},"metadata":{"type":"object","additionalProperties":true,"description":"Freeform metadata"},"member_count":{"type":"integer","description":"Number of active members"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"TeamMember":{"type":"object","properties":{"team_id":{"type":"string"},"agent_id":{"type":"string"},"agent_name":{"type":["string","null"]},"avatar_url":{"type":["string","null"]},"role":{"type":"string","description":"team_members.role — the agent's role inside the team (e.g. 'member', 'lead')."},"joined_at":{"type":"string","format":"date-time","description":"Alias for added_at, returned by the list endpoint for UI convenience."},"added_at":{"type":"string","format":"date-time"},"removed_at":{"type":["string","null"],"format":"date-time"},"reputation_score":{"type":["number","null"],"description":"Agent's reputation score, joined from reputation_scores at list time. `null` when no row exists OR the agent's visibility is private."},"reputation_grade":{"type":["string","null"],"description":"Agent's reputation grade (A+, A, B+, ..., NR). `null` under the same conditions as reputation_score."},"is_eligible":{"type":["boolean","null"],"description":"Whether the agent has crossed the eligibility threshold. The UI honors this to avoid rendering a misleading grade circle for agents that haven't accumulated enough checkpoints."}}},"TeamRosterChange":{"type":"object","properties":{"id":{"type":"string"},"team_id":{"type":"string"},"change_type":{"type":"string","enum":["agent_added","agent_removed"]},"agent_id":{"type":"string"},"actor_id":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"}}},"TeamReputationScore":{"type":"object","properties":{"team_id":{"type":"string"},"team_name":{"type":"string"},"score":{"type":"number","description":"0-1000"},"grade":{"type":"string","enum":["AAA","AA","A","BBB","BB","B","CCC","NR"]},"confidence":{"type":"string","enum":["insufficient","low","medium","high"]},"is_eligible":{"type":"boolean","description":"true when total_assessments >= 10"},"components":{"type":"array","items":{"$ref":"#/components/schemas/TeamReputationComponent"}},"total_assessments":{"type":"integer"},"last_assessed":{"type":["string","null"],"format":"date-time"},"trend_30d":{"type":"number"},"visibility":{"type":"string","enum":["public","unlisted","private"],"description":"Reputation-publication axis for the team's Trust Rating: `public` (published by standard), `unlisted` (readable by id but hidden from the directory), or `private` (owner opt-out). Distinct from any identity-record visibility — shares the word \"public\" but governs only whether the rating is published."},"computed_at":{"type":["string","null"],"format":"date-time"},"member_count":{"type":"integer"},"a2a_trust_extension":{"$ref":"#/components/schemas/A2ATeamTrustExtension"}}},"TeamReputationComponent":{"type":"object","properties":{"key":{"type":"string","enum":["coherence_history","member_quality","operational_record","structural_stability","assessment_density"]},"label":{"type":"string"},"score":{"type":"number","description":"Raw score 0-1000"},"weight":{"type":"number","description":"Weight 0-1"},"weighted_score":{"type":"number","description":"score * weight"},"factors":{"type":"array","items":{"type":"string"}}}},"A2ATeamTrustExtension":{"type":"object","properties":{"extension_uri":{"type":"string"},"provider":{"type":"string"},"score":{"type":"number"},"grade":{"type":"string"},"confidence":{"type":"string"},"member_count":{"type":"integer"},"verified_url":{"type":"string","format":"uri"},"badge_url":{"type":"string","format":"uri"},"methodology_url":{"type":"string","format":"uri"},"last_updated":{"type":"string","format":"date-time"}}},"TeamReputationSnapshot":{"type":"object","properties":{"team_id":{"type":"string"},"week_start":{"type":"string","format":"date"},"score":{"type":"number"},"grade":{"type":"string"},"components":{"type":"object","additionalProperties":{"type":"number"}},"created_at":{"type":"string","format":"date-time"}}},"PolicyMeta":{"type":"object","description":"Metadata for a CLPI policy including schema version, name, description, and scope.","properties":{"schema_version":{"type":"string","description":"Semantic version of the policy schema (e.g. '1.0.0')"},"name":{"type":"string","description":"Human-readable name of the policy"},"description":{"type":"string","description":"Detailed description of the policy's purpose"},"scope":{"type":"string","enum":["agent","org","global"],"description":"Scope at which the policy applies"}}},"CapabilityMapping":{"type":"object","description":"Maps a named capability to specific tools and alignment card actions.","properties":{"description":{"type":"string","description":"Human-readable description of what this capability represents"},"tools":{"type":"array","items":{"type":"string"},"description":"List of tool identifiers that belong to this capability"},"card_actions":{"type":"array","items":{"type":"string"},"description":"Alignment card action types associated with this capability"}}},"ForbiddenRule":{"type":"object","description":"A rule that forbids tools matching a specific pattern.","required":["pattern","reason"],"properties":{"pattern":{"type":"string","description":"Glob or regex pattern matching tool identifiers to forbid"},"reason":{"type":"string","description":"Human-readable reason why these tools are forbidden"},"severity":{"type":"string","enum":["low","medium","high","critical"],"default":"high","description":"Severity level when a forbidden tool is invoked"}}},"EscalationTrigger":{"type":"object","description":"Defines a condition that triggers an escalation action.","required":["condition","action"],"properties":{"condition":{"type":"string","description":"Expression or rule describing when this trigger fires (e.g. 'violation_count > 3')"},"action":{"type":"string","enum":["notify","pause","block","require_approval"],"description":"Action to take when the condition is met"},"reason":{"type":"string","description":"Human-readable explanation of why this escalation exists"}}},"PolicyDefaults":{"type":"object","description":"Default enforcement behavior for tools and situations not explicitly covered by the policy.","properties":{"unmapped_tool_action":{"type":"string","enum":["allow","warn","block","escalate"],"default":"warn","description":"Action to take when a tool is not mapped to any capability"},"unmapped_severity":{"type":"string","enum":["low","medium","high","critical"],"default":"medium","description":"Severity level assigned to unmapped tool invocations"},"fail_open":{"type":"boolean","default":false,"description":"If true, allow actions when the policy engine is unavailable. If false, block by default."},"enforcement_mode":{"type":"string","enum":["observe","enforce","nudge"],"default":"observe","description":"Default enforcement mode for the policy"},"grace_period_hours":{"type":"integer","default":0,"description":"Number of hours to allow violations before enforcement kicks in (for new policy rollouts)"}}},"Policy":{"type":"object","description":"A complete CLPI policy document defining capability mappings, forbidden tools, escalation triggers, and enforcement defaults.","properties":{"meta":{"$ref":"#/components/schemas/PolicyMeta"},"capability_mappings":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/CapabilityMapping"},"description":"Map of capability names to their definitions"},"forbidden":{"type":"array","items":{"$ref":"#/components/schemas/ForbiddenRule"},"description":"List of forbidden tool rules"},"escalation_triggers":{"type":"array","items":{"$ref":"#/components/schemas/EscalationTrigger"},"description":"List of escalation trigger definitions"},"defaults":{"$ref":"#/components/schemas/PolicyDefaults"}}},"PolicyViolation":{"type":"object","description":"A single policy violation detected during evaluation.","properties":{"type":{"type":"string","enum":["forbidden","unmapped","escalation","capability_mismatch"],"description":"Type of policy violation"},"tool":{"type":"string","description":"Tool identifier that triggered the violation"},"capability":{"type":["string","null"],"description":"Capability the tool was mapped to, if any"},"rule":{"type":["string","null"],"description":"The specific rule or pattern that was matched"},"reason":{"type":"string","description":"Human-readable explanation of the violation"},"severity":{"type":"string","enum":["low","medium","high","critical"],"description":"Severity level of the violation"}}},"PolicyEvaluationResult":{"type":"object","description":"Result of evaluating a CLPI policy against a set of tools or traces.","properties":{"verdict":{"type":"string","enum":["pass","warn","fail"],"description":"Overall evaluation verdict"},"violations":{"type":"array","items":{"$ref":"#/components/schemas/PolicyViolation"},"description":"List of policy violations detected"},"warnings":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"message":{"type":"string"}}},"description":"Non-blocking warnings about potential issues"},"card_gaps":{"type":"array","items":{"type":"object","properties":{"capability":{"type":"string"},"missing_card_field":{"type":"string"},"suggestion":{"type":"string"}}},"description":"Gaps between the policy and the alignment card"},"coverage":{"type":"number","minimum":0,"maximum":1,"description":"Fraction of tools covered by the policy (0.0 to 1.0)"}}},"ReclassificationRequest":{"type":"object","description":"Request to reclassify a checkpoint violation.","required":["checkpoint_id","reason"],"properties":{"checkpoint_id":{"type":"string","description":"Identifier of the checkpoint to reclassify"},"reason":{"type":"string","description":"Human-readable justification for the reclassification"},"card_amendment_id":{"type":["string","null"],"description":"Optional ID of an alignment card amendment that triggered this reclassification"},"after_classification":{"type":"string","enum":["clear","review_needed","boundary_violation"],"default":"clear","description":"Verdict the checkpoint is reclassified TO (MNE-2156). Omit for a full exoneration ('clear', the historical behavior); send 'review_needed' or 'boundary_violation' when the review lowers the severity without clearing the agent. An unrecognized value is rejected with 400 — it is never coerced to 'clear'. This is deliberately a SUBSET of the checkpoint verdict enum: 'unverified' means the integrity control did not run, which the system assigns and a reviewer cannot choose."}}},"ReclassificationResult":{"type":"object","description":"Result of a checkpoint violation reclassification.","properties":{"reclassification_id":{"type":"string","description":"Unique identifier for this reclassification"},"checkpoint_id":{"type":"string","description":"Identifier of the reclassified checkpoint"},"agent_id":{"type":"string","description":"Agent whose checkpoint was reclassified"},"original_type":{"type":"string","description":"Original violation type before reclassification"},"new_type":{"type":"string","description":"New violation type after reclassification"},"reason":{"type":"string","description":"Justification provided for the reclassification"},"score_impact":{"type":"object","properties":{"previous_score":{"type":"number"},"new_score":{"type":"number"},"delta":{"type":"number"}},"description":"Impact of the reclassification on the agent's score"}}},"FaultLine":{"type":"object","description":"A single fault line identified in team alignment analysis.","properties":{"id":{"type":"string","description":"Unique identifier for this fault line"},"value":{"type":"string","description":"The specific value, capability, or constraint that constitutes the fault line"},"classification":{"type":"string","enum":["resolvable","priority_mismatch","incompatible","complementary"],"description":"Classification of the fault line's nature"},"severity":{"type":"string","enum":["low","medium","high","critical"],"description":"Severity of the fault line"},"agents_declaring":{"type":"array","items":{"type":"string"},"description":"Agent IDs that declare or satisfy this requirement"},"agents_missing":{"type":"array","items":{"type":"string"},"description":"Agent IDs that are missing this requirement"},"agents_conflicting":{"type":"array","items":{"type":"string"},"description":"Agent IDs whose declared conflicts_with includes this value"},"impact_score":{"type":"number","minimum":0,"maximum":1,"description":"Estimated impact of this fault line on team alignment (0.0 to 1.0)"},"resolution_hint":{"type":"string","description":"Suggested action to resolve this fault line"},"affects_capabilities":{"type":"array","items":{"type":"string"},"description":"Bounded actions/capabilities shared by all involved agents"}}},"FaultLineAnalysis":{"type":"object","description":"Complete fault line analysis result for a team.","properties":{"team_id":{"type":"string","description":"Team that was analyzed"},"analysis_id":{"type":"string","description":"Unique identifier for this analysis run"},"fault_lines":{"type":"array","items":{"$ref":"#/components/schemas/FaultLine"},"description":"Identified fault lines sorted by severity then impact_score desc"},"alignments":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Detected alignment patterns — sets of agents consistently isolated across multiple fault lines."},"summary":{"$ref":"#/components/schemas/FaultLineSummary"},"coherence":{"type":"object","additionalProperties":true,"description":"@mnemom/team-coherence v2 dimensional coherence vector (governance median, conflict edges, conscience/integrity invariants + narrative helpers). Replaces the deprecated scalar fleet_score."}}},"FaultLineSummary":{"type":"object","description":"Aggregated fault-line counts by classification (AAP `FaultLineSummary`). All counts are non-negative integers; every field is present even when no fault lines were detected (all zero).","properties":{"total":{"type":"integer","minimum":0,"description":"Total number of fault lines"},"resolvable":{"type":"integer","minimum":0,"description":"Count of resolvable fault lines"},"priority_mismatch":{"type":"integer","minimum":0,"description":"Count of priority_mismatch fault lines"},"incompatible":{"type":"integer","minimum":0,"description":"Count of incompatible fault lines"},"complementary":{"type":"integer","minimum":0,"description":"Count of complementary fault lines"},"critical_count":{"type":"integer","minimum":0,"description":"Count of critical-severity fault lines"}}},"RiskForecast":{"type":"object","description":"Risk forecast for a team based on alignment trends and fault lines.","properties":{"forecast_id":{"type":"string","description":"Unique identifier for this forecast"},"failure_modes":{"type":"array","items":{"type":"object","properties":{"mode":{"type":"string","description":"Description of the potential failure mode"},"probability":{"type":"number","minimum":0,"maximum":1,"description":"Estimated probability of occurrence"},"impact":{"type":"string","enum":["low","medium","high","critical"],"description":"Estimated impact if the failure occurs"},"contributing_factors":{"type":"array","items":{"type":"string"},"description":"Factors contributing to this risk"},"mitigation":{"type":"string","description":"Suggested mitigation action"}}},"description":"Ranked list of potential failure modes"},"overall_risk_level":{"type":"string","enum":["low","medium","high","critical"],"description":"Overall risk level for the team"},"confidence":{"type":"number","minimum":0,"maximum":1,"description":"Confidence level of the forecast (0.0 to 1.0)"}}},"OnChainAnchorResult":{"type":"object","description":"An on-chain Merkle-root anchoring record — a row from the `on_chain_anchors` table (migration 057). Returned by GET /on-chain/history (raw row, all columns) and embedded as `latest_anchor` in GET /on-chain/status (subset via the get_on_chain_status RPC, which omits gas_used/created_at).","properties":{"id":{"type":"string","description":"Anchor record identifier (`oca-<uuid>`)."},"merkle_root":{"type":"string","description":"Hex-encoded Merkle root hash that was anchored"},"tx_hash":{"type":["string","null"],"description":"Blockchain transaction hash. Null while the anchor is pending (recorded before the transaction is broadcast)."},"block_number":{"type":["integer","null"],"description":"Block number in which the transaction was included. Null until the anchor is confirmed on-chain."},"leaf_count":{"type":"integer","description":"Number of leaves covered by this anchor."},"tree_depth":{"type":"integer","description":"Depth of the Merkle tree."},"gas_used":{"type":["integer","null"],"description":"Gas consumed by the anchoring transaction. Null until the transaction is broadcast/confirmed."},"chain":{"type":"string","enum":["base-sepolia","base"],"description":"Blockchain network where the anchor was created. Matches the on_chain_anchors.chain CHECK constraint; defaults to `base-sepolia`."},"status":{"type":"string","enum":["pending","confirmed","failed"],"description":"Lifecycle status of the anchor record."},"anchored_at":{"type":"string","format":"date-time","description":"Timestamp when the anchor was created"},"created_at":{"type":"string","format":"date-time","description":"Row creation timestamp (present on raw history rows)."}}},"User":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"app_metadata":{"type":"object","additionalProperties":true},"user_metadata":{"type":"object","additionalProperties":true}},"description":"Supabase user shape. Fields beyond `id` and `email` are passthrough."},"PublicKeyCredentialCreationOptionsJSON":{"type":"object","description":"WebAuthn registration options (base64url-encoded per the WebAuthn Level 3 JSON serialization).","properties":{"rp":{"type":"object","required":["id","name"]},"user":{"type":"object","required":["id","name","displayName"]},"challenge":{"type":"string"},"pubKeyCredParams":{"type":"array"},"authenticatorSelection":{"type":"object"},"attestation":{"type":"string"},"excludeCredentials":{"type":"array"},"timeout":{"type":"integer"}},"additionalProperties":true},"PublicKeyCredentialRequestOptionsJSON":{"type":"object","description":"WebAuthn authentication options.","properties":{"rpId":{"type":"string"},"challenge":{"type":"string"},"userVerification":{"type":"string"},"allowCredentials":{"type":"array"},"timeout":{"type":"integer"}},"additionalProperties":true},"RegistrationResponseJSON":{"type":"object","description":"Browser's `navigator.credentials.create()` response, JSON-serialized per the WebAuthn Level 3 JSON form.","properties":{"id":{"type":"string"},"rawId":{"type":"string"},"type":{"type":"string","enum":["public-key"]},"response":{"type":"object"},"clientExtensionResults":{"type":"object"},"authenticatorAttachment":{"type":"string"}},"required":["id","rawId","type","response"],"additionalProperties":true},"AuthenticationResponseJSON":{"type":"object","description":"Browser's `navigator.credentials.get()` response, JSON-serialized.","properties":{"id":{"type":"string"},"rawId":{"type":"string"},"type":{"type":"string","enum":["public-key"]},"response":{"type":"object"},"clientExtensionResults":{"type":"object"},"authenticatorAttachment":{"type":"string"}},"required":["id","rawId","type","response"],"additionalProperties":true},"UnifiedAlignmentCard":{"type":"object","description":"Unified alignment card (ADR-008/ADR-039). Authored in YAML or JSON; composed server-side with platform defaults, org template, and active exemptions before storage. This schema matches the runtime validator at src/composition/validate.ts EXACTLY — a card authored strictly to it passes `PUT /v1/agents/{id}/alignment-card` and the preview-compose endpoint. Output-only fields (card_id, issued_at, expires_at, _composition, content_hash, version) are server-assigned and must NOT be sent on a PUT.","required":["card_version","agent_id","autonomy_mode","integrity_mode","principal","values","autonomy","audit"],"properties":{"card_version":{"type":"string","minLength":1,"description":"Card schema version (required, non-empty). Current canonical value: `unified/2026-04-26`."},"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"],"description":"ADR-039 master switch for the action-policing pipeline (autonomy constraints). Required at the top level post-cutover; the legacy `enforcement.mode` location is rejected."},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"],"description":"ADR-039 master switch for the values/conscience pipeline (integrity constraints). Required at the top level post-cutover; the legacy `integrity.enforcement_mode` location is rejected."},"card_id":{"type":"string","description":"Card row id. Server-assigned on PUT (`ac-{uuid}`)."},"agent_id":{"type":"string","description":"Target agent id. On PUT, server overwrites to match the URL path."},"issued_at":{"type":"string","format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time"},"principal":{"type":"object","description":"Required object describing whose authority the agent acts under (ADR-039 Decision 10).","properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string","minLength":1,"description":"Required (non-empty) when principal.type is not `unspecified`; identifies the human / organization / agent."},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}},"required":["type","relationship"],"allOf":[{"if":{"properties":{"type":{"not":{"const":"unspecified"}}}},"then":{"required":["identifier"]}}]},"values":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","minItems":1,"items":{"oneOf":[{"type":"string","minLength":1},{"type":"object","required":["id"],"properties":{"id":{"type":"string","minLength":1}},"additionalProperties":{"type":"string"}}]},"description":"Ordered list of declared values. Phase 1 cards-as-primitive: each entry is either a catalog-v1 ID string (e.g. `'accuracy'`) or a parameterized map carrying optional `intensity` / `domain` / `severity_on_violation` / `scope` (e.g. `{id: 'accuracy', domain: 'financial', severity_on_violation: 'critical'}`)."},"definitions":{"type":"object","additionalProperties":{"type":"object","properties":{"description":{"type":"string"},"priority":{"type":"integer"}}}},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}},"conscience":{"type":"object","properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object","required":["type","content"],"properties":{"type":{"type":"string","enum":["BOUNDARY","FEAR","COMMITMENT","BELIEF","HOPE"]},"content":{"type":"string"},"id":{"type":"string"},"severity":{"type":"string","enum":["advisory","mandatory"]}}}}},"required":["mode","values"]},"autonomy":{"type":"object","required":["bounded_actions"],"properties":{"bounded_actions":{"type":"array","minItems":1,"items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object","required":["condition","action","reason"],"properties":{"condition":{"type":"string"},"action":{"type":"string","enum":["escalate","deny","log"]},"reason":{"type":"string"}}}},"max_autonomous_value":{"type":"object","properties":{"amount":{"type":"number"},"currency":{"type":"string"}}}}},"capabilities":{"type":"object","additionalProperties":{"type":"object","properties":{"description":{"type":"string"},"tools":{"type":"array","items":{"type":"string"}},"required_actions":{"type":"array","items":{"type":"string"}}}}},"enforcement":{"type":"object","description":"Optional ADR-039 Decision-3 user-facing knobs for unmapped-tool handling. The legacy `mode`, `unmapped_tool_action` and `fail_open` keys are REJECTED by the validator (mode → top-level autonomy_mode; fail_open → gateway env config).","properties":{"allow_unmapped_tools":{"type":"boolean","description":"When true, tools not mapped to a capability are allowed by default."},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"],"description":"Severity assigned to an unmapped tool when allow_unmapped_tools is false."},"forbidden_tools":{"type":"array","items":{"type":"object","required":["pattern","reason","severity"],"properties":{"pattern":{"type":"string"},"reason":{"type":"string"},"severity":{"type":"string","enum":["critical","high","medium","low"]}}}},"grace_period_hours":{"type":"integer"}}},"audit":{"type":"object","required":["retention_days","queryable"],"allOf":[{"if":{"properties":{"queryable":{"const":true}},"required":["queryable"]},"then":{"required":["query_endpoint"]}}],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer","minimum":0},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string","description":"Required when audit.queryable is true."},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object","properties":{"type":{"type":"string","enum":["local","remote","distributed"]},"location":{"type":"string"}}}}},"extensions":{"type":"object","additionalProperties":true},"_composition":{"$ref":"#/components/schemas/CompositionMetadata"},"content_hash":{"type":"string","description":"Response-only: content hash of the composed card (`sha256:<hex>`), injected by the GET/PUT response. Server-assigned — do not send on a PUT."},"version":{"type":"integer","description":"Response-only: monotonic card version, injected by the GET/PUT response. Server-assigned — do not send on a PUT."}}},"UnifiedProtectionCard":{"type":"object","description":"Unified protection card (ADR-037). Safe House thresholds + trusted-source policy for a single agent. Shape matches src/composition/types.ts::UnifiedProtectionCard (canonical) and what the runtime validator at src/composition/validate.ts accepts. The customer-facing docs at /concepts/protection-card and /specifications/protection-card-schema document this same shape.","required":["card_version","agent_id","mode","thresholds","screen_surfaces","trusted_sources"],"properties":{"card_version":{"type":"string"},"card_id":{"type":"string"},"agent_id":{"type":"string"},"issued_at":{"type":"string","format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time"},"mode":{"type":"string","enum":["off","observe","nudge","enforce"],"description":"Strictest-wins composition: enforce > nudge > observe > off."},"thresholds":{"type":"object","description":"Score bands. Must satisfy warn <= quarantine <= block; each value in [0, 1].","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}},"screen_surfaces":{"type":"object","description":"Which request surfaces Safe House inspects. Composed across scopes by OR-per-field (any scope requiring inspection wins).","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean","description":"The user/principal prompt entering the agent."},"outgoing":{"type":"boolean","description":"The agent's response leaving the agent."},"tool_calls":{"type":"boolean","description":"Tool-use invocations the agent makes."},"tool_responses":{"type":"boolean","description":"Responses to tool calls returning to the agent."}}},"trusted_sources":{"type":"object","description":"Sources for which detectors short-circuit (each match logged in the trace). Composed as platform->agent intersection (compliance ceiling) with org+agent union inside that ceiling — an agent cannot widen trust beyond what the platform allows.","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"},"description":"DNS names or host:port entries."},"agent_ids":{"type":"array","items":{"type":"string"},"description":"Mnemom agent IDs (mnm-* / smolt-* prefixed)."},"ip_ranges":{"type":"array","items":{"type":"string"},"description":"IPv4 or IPv6 CIDR ranges."}}},"protected_surface":{"type":"object","description":"Org-declared protected surface policy (MNE-830). Strengthen-only UNION across platform → org → team → agent: each scope may add entries; none may remove. The composer always emits this block; callers omit it to inherit the composed floor. See ADR-037 §protected_surface.","properties":{"assets":{"type":"array","description":"Protected assets. Intrinsic identity = `${kind}:${selector}` (normalized). Composer merges by identity, keeping the strictest entry per scope.","items":{"type":"object","required":["kind","selector"],"properties":{"kind":{"type":"string","description":"Asset kind (e.g. `row`, `field`, `resource`, `table`)."},"selector":{"type":"string","description":"Asset selector (e.g. `customer:critical-0000`, `replica_dsn`)."},"label":{"type":"string","description":"Human-facing display label (optional)."},"reason":{"type":"string","description":"Why this asset is protected (optional)."},"source_scope":{"type":"string","description":"Composer-assigned provenance (`platform`, `org:<id>`, `team:<id>`, `agent:<id>`). Server-assigned — do not send on a PUT."}}}},"forbidden_operations":{"type":"array","description":"Operations that are unconditionally forbidden. Intrinsic identity = normalized `pattern`. Composer unions across scopes; on identity collision, severity → max.","items":{"type":"object","required":["pattern"],"properties":{"pattern":{"type":"string","description":"Operation pattern (e.g. `TRUNCATE`, `unscoped UPDATE/DELETE`, `exfiltrate:pii`)."},"applies_to":{"type":"array","items":{"type":"string"},"description":"Asset identities (`${kind}:${selector}`) this operation applies to. Empty/absent means GLOBAL."},"severity":{"type":"string","enum":["low","medium","high","critical"],"description":"Severity level. Composer merges to strictest across scopes."},"reason":{"type":"string","description":"Why this operation is forbidden (optional)."},"source_scope":{"type":"string","description":"Composer-assigned provenance. Server-assigned — do not send on a PUT."}}}},"escalation_required":{"type":"array","description":"Operations that require escalation before proceeding. Same intrinsic-identity + union rules as forbidden_operations (minus severity).","items":{"type":"object","required":["pattern"],"properties":{"pattern":{"type":"string","description":"Operation pattern requiring escalation."},"applies_to":{"type":"array","items":{"type":"string"},"description":"Asset identities this escalation applies to. Empty/absent = GLOBAL."},"reason":{"type":"string","description":"Why escalation is required (optional)."},"source_scope":{"type":"string","description":"Composer-assigned provenance. Server-assigned — do not send on a PUT."}}}}}},"review":{"type":"object","description":"Review-hold policy (Safe House Review, Slice 2a — MNE-920 design). gate_on is the minimum verdict band per surface that escalates to a review-hold. Composition is strictest-wins; on_timeout defaults to 'reject' (fail-closed). reviewer.kind 'endpoint' is designed for MNE-1650 and not consumed yet.","required":["enabled"],"properties":{"enabled":{"type":"boolean"},"gate_on":{"type":"object","properties":{"incoming":{"type":"string","enum":["off","warn","quarantine","block"]},"outgoing":{"type":"string","enum":["off","warn","quarantine","block"]},"tool_calls":{"type":"string","enum":["off","warn","quarantine","block"]},"tool_responses":{"type":"string","enum":["off","warn","quarantine","block"]},"integrity":{"type":"string","enum":["off","review_needed","boundary_violation"]}}},"sla_seconds":{"type":"number","minimum":1},"on_timeout":{"type":"string","enum":["reject","release"]},"notify":{"type":"object","properties":{"sse":{"type":"boolean"},"webhooks":{"type":"boolean"}}},"reviewer":{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["builtin_opus","endpoint"]},"endpoint_url":{"type":"string","format":"uri"}}},"quarantine_notice":{"type":"string","maxLength":2000}}},"extensions":{"type":"object","additionalProperties":true,"description":"Free-form extension slot for non-canonical fields. Ignored by the composer; preserved on read for tooling that needs an audit-tail metadata bag."},"_composition":{"$ref":"#/components/schemas/CompositionMetadata"},"content_hash":{"type":"string","description":"Response-only: content hash of the composed card (`sha256:<hex>`), injected by the GET/PUT response. Server-assigned — do not send on a PUT."},"version":{"type":"integer","description":"Response-only: monotonic card version, injected by the GET/PUT response. Server-assigned — do not send on a PUT."}}},"CompositionMetadata":{"type":"object","description":"System-managed block describing which scope sources merged into the canonical card. Only returned when `?include_composition=true`.","properties":{"canonical_id":{"type":"string"},"composed_at":{"type":"string","format":"date-time"},"scopes_applied":{"type":"array","items":{"type":"object","properties":{"scope":{"type":"string","description":"`platform`, `org:<id>`, or `agent:<id>`."},"version":{"type":"integer"},"template_version":{"type":"integer"},"card_id":{"type":"string"}}}},"exemptions_applied":{"type":"array","items":{"type":"string"}},"source_card_id":{"type":"string"},"source_policy_id":{"type":"string"}}},"AgentExemption":{"type":"object","description":"A single exemption row relaxing an org-template floor for one agent (ADR-008).","required":["id","agent_id","exempt_section","reason","granted_by","granted_at","status"],"properties":{"id":{"type":"string"},"agent_id":{"type":"string"},"exempt_section":{"type":"string","enum":["autonomy.forbidden_actions","enforcement.forbidden_tools","autonomy.max_autonomous_value"]},"exempt_patterns":{"type":["array","null"],"items":{"type":"string"}},"reason":{"type":"string"},"granted_by":{"type":"string"},"granted_at":{"type":"string","format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time"},"status":{"type":"string","enum":["active"],"description":"Always `active` today (forward-compat stub for future dual-control approval workflow)."}}},"OrgCardTemplateResponse":{"type":"object","required":["org_id","template","enabled"],"properties":{"org_id":{"type":"string"},"template":{"oneOf":[{"$ref":"#/components/schemas/UnifiedAlignmentCard"},{"$ref":"#/components/schemas/UnifiedProtectionCard"},{"type":"null"}]},"enabled":{"type":"boolean"}}},"AgentSettings":{"type":"object","description":"Per-agent operational observer-rollout flags. MNE-556 P4: the former behavioral toggles (aap_enabled, aip_enabled, proof_enabled, proof_rate, nudge_strategy, ddr_mode, analyze_output) were removed — that config now lives on the composed alignment card (PUT /agents/{id}/alignment-card). Only the observer V2/V1 rollout flags remain here.","required":["agent_id","observer_v2_primary_enabled","observer_v1_shadow_enabled"],"properties":{"agent_id":{"type":"string"},"observer_v2_primary_enabled":{"type":"boolean","description":"Whether the V2 observer retune is authoritative for this agent (default true)."},"observer_v1_shadow_enabled":{"type":"boolean","description":"Whether the V1 observer runs in parallel shadow for this agent (default false)."}}},"DeletionRequestStatus":{"type":"object","description":"Tracks progress of the async GDPR Art. 17 deletion cascade (ADR-021).","required":["deletion_request_id","status","requested_at","retry_count"],"properties":{"deletion_request_id":{"type":"string"},"status":{"type":"string","enum":["received","tombstoned","phase_1_complete","phase_2_complete","phase_3_complete","phase_4_complete","phase_5_complete","phase_6_complete","phase_7_complete","kv_cleared","pseudonymized","complete","failed"]},"requested_at":{"type":"string","format":"date-time"},"completed_at":{"type":["string","null"],"format":"date-time"},"failed_phase":{"type":["string","null"]},"failed_reason":{"type":["string","null"]},"retry_count":{"type":"integer","minimum":0}}},"DisagreementReview":{"type":"object","description":"Row from `disagreement_reviews` — a human-adjudicable action that failed to find consensus during enforcement.","properties":{"id":{"type":"string"},"agent_id":{"type":"string"},"status":{"type":"string","enum":["pending","review","applied","dismissed"]},"proposed_amendment":{"type":["object","null"],"properties":{"type":{"type":"string"},"action":{"type":"string","description":"Action the reviewer proposes to add to `autonomy_envelope.bounded_actions`."},"description":{"type":"string"}}},"created_at":{"type":"string","format":"date-time"},"resolved_at":{"type":["string","null"],"format":"date-time"},"resolved_by":{"type":["string","null"]}},"additionalProperties":true},"ReputationScore":{"type":"object","description":"Agent reputation row computed by the reputation worker's 6-hour cron. Grade alphabet: `AAA AA+ AA A+ A B+ B C+ C D NR` (NR = not-rated, insufficient data). Score is an integer 0–1000.","required":["agent_id","score","grade","is_eligible","checkpoint_count","confidence","components","visibility"],"properties":{"agent_id":{"type":"string"},"score":{"type":["integer","null"],"minimum":0,"maximum":1000},"grade":{"type":["string","null"],"description":"AAA–D or NR."},"tier":{"type":["string","null"]},"is_eligible":{"type":"boolean"},"checkpoint_count":{"type":"integer"},"checkpoint_accounting":{"type":["object","null"],"description":"Structured breakdown of how checkpoints were counted toward the score. `analyzed` is the scoring population; `excluded` buckets are mutually exclusive and `analyzed + synthetic + insufficient_thinking + quarantined = total`. Null for legacy rows computed before this field existed.","required":["total","analyzed","excluded"],"properties":{"total":{"type":"integer","description":"All checkpoints recorded for the agent."},"analyzed":{"type":"integer","description":"Checkpoints that counted toward the score (drives the X/50 eligibility gauge)."},"excluded":{"type":"object","required":["synthetic","insufficient_thinking","quarantined"],"properties":{"synthetic":{"type":"integer","description":"Synthetic (`ic-synthetic-*`) checkpoints."},"insufficient_thinking":{"type":"integer","description":"Zero-analysis checkpoints (no extraction confidence, thinking tokens, or analysis duration)."},"quarantined":{"type":"integer","description":"Checkpoints referenced by a non-expired enforce advisory; excluded from scoring entirely."}}},"re_evaluated":{"type":"object","description":"How many of the agent's checkpoints carry each kind of re-evaluation annotation (counted over `total`, not the analyzed subset). Observability only — these are not an exclusion bucket and do not enter the score arithmetic. Absent on scores computed before this breakdown existed.","required":["corrected_clear","corrected_non_clear","resolved_no_correction"],"properties":{"corrected_clear":{"type":"integer","description":"Checkpoints explicitly corrected to `clear` (`re_evaluation_metadata.corrected_verdict = 'clear'`)."},"corrected_non_clear":{"type":"integer","description":"Checkpoints corrected to a NON-clear verdict — a cross-turn escalation or a reviewer reclassification to `review_needed`/`boundary_violation`. These count against the score per the correction, not as exonerations; a non-zero value is why this agent's score differs from the pre-MNE-2156 calculation."},"resolved_no_correction":{"type":"integer","description":"Checkpoints re-evaluated with NO recorded correction — the trust-recovery convention, scored as `clear`."}}}}},"confidence":{"type":"string","enum":["insufficient","low","medium","high"]},"components":{"type":"array","items":{"type":"object","required":["key","score","weight","weighted_score"],"properties":{"key":{"type":"string","enum":["integrity_ratio","compliance","drift_stability","trace_completeness","coherence_compatibility"]},"label":{"type":"string"},"score":{"type":"number"},"weight":{"type":"number"},"weighted_score":{"type":"number"},"factors":{"type":"array"}}}},"computed_at":{"type":["string","null"],"format":"date-time"},"next_compute_at":{"type":["string","null"],"format":"date-time","description":"Next scheduled recompute — the 00/06/12/18 UTC cron slot strictly after `computed_at` (`floor(computed_at/6h)*6h + 6h`). Null when `computed_at` is null."},"trend_30d":{"type":["number","null"]},"visibility":{"type":"string","enum":["public","private"],"description":"Reputation-publication axis — whether this agent's Trust Rating is published. Every registered agent's reputation is `public` by accountability standard (the default; that is the whole point of a portable, verifiable rating); `private` is a rare owner opt-out that 403s the read to non-owners. This is DISTINCT from `Agent.public` (the identity-record visibility axis) — they share the word \"public\" but govern different things."},"claimed":{"type":"boolean"},"agent_name":{"type":["string","null"]},"a2a_trust_extension":{"type":"object","description":"A2A trust extension for interop. Only present on `GET /reputation/{agent_id}` (not on batch/compare rows).","properties":{"extension_uri":{"type":"string"},"provider":{"type":"string"},"score":{"type":"number"},"grade":{"type":"string"},"confidence":{"type":"string"},"verified_url":{"type":"string","format":"uri"},"badge_url":{"type":"string","format":"uri"},"methodology_url":{"type":"string","format":"uri"},"last_updated":{"type":"string","format":"date-time"}}}}},"RiskAssessment":{"type":"object","description":"Individual risk assessment row (`ra-…`). Produced by `POST /risk/assess`.","properties":{"assessment_id":{"type":"string"},"agent_id":{"type":"string"},"risk_score":{"type":"number","description":"0–1000 integer (higher = riskier)."},"risk_level":{"type":"string","enum":["low","moderate","high","critical"]},"recommendation":{"type":"string","enum":["proceed","proceed_with_caveats","require_approval","block"]},"confidence":{"type":"string","enum":["insufficient","low","medium","high"]},"contributing_factors":{"type":"array","items":{"type":"object","additionalProperties":true}},"suggested_thresholds":{"type":"object","additionalProperties":true},"explanation":{"type":"string"},"proof_id":{"type":["string","null"]},"proof_status":{"type":"string","enum":["none","pending","completed","failed"]},"created_at":{"type":"string","format":"date-time"}},"additionalProperties":true},"TeamRiskAssessment":{"type":"object","description":"Team risk assessment row (`tra-…`). Produced by `POST /risk/assess/team`. Three-pillar result (portfolio + coherence + concentration) with weakest-link and Shapley attribution per member.","properties":{"assessment_id":{"type":"string"},"team_id":{"type":["string","null"]},"agent_count":{"type":"integer"},"team_risk_score":{"type":"number"},"team_risk_level":{"type":"string"},"team_coherence_score":{"type":"number"},"team_recommendation":{"type":"string"},"portfolio_risk":{"type":"object","additionalProperties":true},"coherence_risk":{"type":"object","additionalProperties":true},"concentration_risk":{"type":"object","additionalProperties":true},"weakest_link_risk":{"type":"object","additionalProperties":true},"individual_assessments":{"type":"array","items":{"$ref":"#/components/schemas/RiskAssessment"}},"outliers":{"type":"array"},"clusters":{"type":"array"},"value_divergences":{"type":"array"},"shapley_values":{"type":"object","additionalProperties":{"type":"number"}},"synergy_type":{"type":"string"},"explanation":{"type":"string"},"proof_id":{"type":["string","null"]},"proof_status":{"type":"string"},"created_at":{"type":"string","format":"date-time"}},"additionalProperties":true},"QuarantineItem":{"type":"object","description":"Quarantined message row. Stores only `content_hash` — the original plaintext is not retained once the message is quarantined.","properties":{"quarantine_id":{"type":"string"},"agent_id":{"type":"string"},"status":{"type":"string","enum":["pending","released","deleted","confirmed_threat"]},"threat_type":{"type":"string"},"content_hash":{"type":"string"},"reviewed_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"}},"additionalProperties":true},"ReviewLifecycle":{"type":"object","description":"A Safe House review-hold lifecycle row, as read by `GET /v1/safe-house/reviews[/{review_id}]` (Task A1/A2, canonical-consumer plan). This is the reconcile/backfill (\"pull, truth\") leg of the review-hold lifecycle — the same shape delivered live via the `sh.review.*` webhook (\"push, latency\"). Reflects the already-attested `screen.review` jsonb off `safe_house_decisions`; this API never writes to that table.","required":["review_id","status","surface","verdict","reason","reviewer_model","triggered_at","resolved_at","turn_index"],"properties":{"review_id":{"type":"string"},"status":{"type":"string","enum":["pending","allowed","denied","expired"]},"surface":{"type":"string","enum":["incoming","tool_call","tool_response"]},"verdict":{"type":"string","description":"The reconciled verdict on the ruling `safe_house_decisions` row."},"reason":{"type":["string","null"]},"reviewer_model":{"type":["string","null"],"description":"Pinned reviewer model, e.g. `claude-opus-4-8`, when the review was adjudicated."},"triggered_at":{"type":["string","null"],"format":"date-time"},"resolved_at":{"type":["string","null"],"format":"date-time"},"turn_index":{"type":["integer","null"]}}},"SafeHousePattern":{"type":"object","description":"Row from `sh_threat_patterns`. `label: \"benign\"` patterns are used to suppress false positives; `label: \"malicious\"` patterns add to L1/L2 detection.","properties":{"id":{"type":"string"},"threat_type":{"type":"string"},"source":{"type":"string"},"label":{"type":"string","enum":["malicious","benign"]},"content":{"type":"string"},"minhash":{"type":["string","null"]},"metadata":{"type":"object","additionalProperties":true},"is_active":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"}}},"SafeHouseCanary":{"type":"object","description":"Canary credential planted in an agent context. `canary_value` is only returned on creation.","properties":{"id":{"type":"string"},"agent_id":{"type":"string"},"canary_type":{"type":"string","enum":["api_key","password","database_url","ssh_key","oauth_token"]},"triggered":{"type":"boolean"},"triggered_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"}}},"SafeHouseEvaluation":{"type":"object","description":"Row from `sh_evaluations` — one screening decision (inbound or outbound). `threats` and `detector_scores` depend on detector config.","properties":{"id":{"type":"string"},"agent_id":{"type":"string"},"session_id":{"type":["string","null"]},"mode":{"type":"string"},"surface":{"type":["string","null"]},"verdict":{"type":"string","enum":["pass","warn","quarantine","block"]},"threats":{"type":["array","null"],"items":{"type":"object","properties":{"type":{"type":"string"},"confidence":{"type":"number"}}}},"overall_risk":{"type":"number"},"detector_scores":{"type":["object","null"],"additionalProperties":true},"detection_sources":{"type":["array","null"]},"session_multiplier":{"type":["number","null"]},"duration_ms":{"type":["integer","null"]},"created_at":{"type":"string","format":"date-time"}},"additionalProperties":true},"SafeHouseEvaluationPage":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SafeHouseEvaluation"}},"pagination":{"type":"object","properties":{"total":{"type":["integer","null"]},"limit":{"type":"integer"},"after":{"type":["string","null"]}}},"meta":{"type":"object","additionalProperties":true}}},"NetworkThreatBucket":{"type":"object","description":"One per-axis bucket in the Protection Network L4 thermometer. The `bucket_value` is the L0 fingerprint slice for the axis (substrate / vertical / pattern / source) and carries no per-tenant identifier — public-aggregate disclosure model per concept.md §\"Cross-tenant disclosure.\"","required":["bucket_value","state","state_changed_at","updated_at"],"properties":{"bucket_value":{"type":"string","description":"L0 fingerprint slice (e.g. substrate / vertical / pattern / source identifier)."},"state":{"type":"string","enum":["calm","elevated","high","under_attack"]},"prior_state":{"type":["string","null"],"enum":["calm","elevated","high","under_attack",null],"description":"Previous state if a transition has been observed; null until the bucket has changed state at least once."},"state_changed_at":{"type":"string","format":"date-time","description":"Wall-clock time of the most recent state transition."},"updated_at":{"type":"string","format":"date-time","description":"Wall-clock time the rolling-stats roll-up last touched this row."}},"additionalProperties":true},"SelfHostedDeployment":{"type":"object","description":"A self-hosted Mnemom deployment registered by an org.","properties":{"deployment_id":{"type":"string","description":"Prefixed `dep-…` identifier assigned on registration."},"org_id":{"type":"string"},"license_id":{"type":"string"},"instance_name":{"type":"string"},"instance_id":{"type":"string"},"region":{"type":["string","null"]},"status":{"type":"string","enum":["active","inactive","degraded"]},"version":{"type":["string","null"]},"heartbeat_data":{"type":"object","additionalProperties":true},"instance_metadata":{"type":"object","additionalProperties":true},"last_heartbeat_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"TrustEdge":{"type":"object","description":"Directed trust-relationship edge between two agents (CLPI Phase 3). Used by the trust-topology RPC and the team reputation scorer.","properties":{"id":{"type":"string","description":"Prefixed `te-…` identifier."},"from_agent":{"type":"string"},"to_agent":{"type":"string"},"weight":{"type":"number","minimum":0,"maximum":1},"reason":{"type":"string","description":"Free-form label (e.g. `manual`, `roster_coherence`, `co_deployment`)."},"created_at":{"type":"string","format":"date-time"}}},"GovernanceSignalScope":{"type":"string","enum":["platform","org","team","agent"],"description":"Scope at which the signal is produced and routed (ADR-048 §1)."},"GovernanceSignalSource":{"type":"string","enum":["sideband.drift","sideband.coherence","sideband.fault_line","sideband.fleet","network.threat_level.changed"],"description":"Source detector for the signal. Closed enum per ADR-048 §1. `network.threat_level.changed` added in migration 234."},"GovernanceSignalSeverity":{"type":"string","enum":["info","warn","high","critical"]},"GovernanceSignalStatus":{"type":"string","enum":["open","acknowledged","resolved","dismissed","expired"]},"GovernanceActorRole":{"type":"string","enum":["platform_admin","org_owner","org_admin","team_admin","member","system"],"description":"Audit-actor role per ADR-046."},"GovernanceResolutionStatus":{"type":"string","enum":["action_taken","wont_fix","duplicate","false_positive","self_resolved"]},"GovernanceNotificationChannel":{"type":"string","enum":["webhook","slack","email","pagerduty"]},"GovernanceNotificationChannelState":{"type":"object","additionalProperties":false,"required":["state","attempts"],"properties":{"state":{"type":"string","enum":["queued","delivered","failed","skipped"]},"attempts":{"type":"integer","minimum":0},"destination_id":{"type":["string","null"],"format":"uuid"},"delivered_at":{"type":["string","null"],"format":"date-time"},"last_error":{"type":["string","null"]}}},"GovernanceNotificationState":{"type":"object","description":"Per-channel dispatch state populated by the notification dispatcher.","additionalProperties":{"$ref":"#/components/schemas/GovernanceNotificationChannelState"},"properties":{"skipped":{"type":"boolean"}}},"GovernanceSignal":{"type":"object","description":"A governance signal row — operator-actionable observation per ADR-048.","required":["id","scope","scope_id","source","pattern_type","severity","detected_at","detected_by","org_id","agent_ids","detail","source_ref","status","notification_state","created_at","updated_at"],"properties":{"id":{"type":"string","pattern":"^gs-[0-9a-f]{12}$"},"scope":{"$ref":"#/components/schemas/GovernanceSignalScope"},"scope_id":{"type":"string"},"source":{"$ref":"#/components/schemas/GovernanceSignalSource"},"pattern_type":{"type":"string","description":"Free-form per source."},"severity":{"$ref":"#/components/schemas/GovernanceSignalSeverity"},"detected_at":{"type":"string","format":"date-time"},"detected_by":{"type":"string"},"org_id":{"type":"string"},"team_id":{"type":["string","null"],"format":"uuid"},"agent_ids":{"type":"array","items":{"type":"string"}},"detail":{"type":"object","additionalProperties":true},"source_ref":{"type":"object","additionalProperties":true},"status":{"$ref":"#/components/schemas/GovernanceSignalStatus"},"acknowledged_by":{"type":["string","null"],"format":"uuid"},"acknowledged_at":{"type":["string","null"],"format":"date-time"},"acknowledged_actor_role":{"oneOf":[{"$ref":"#/components/schemas/GovernanceActorRole"},{"type":"null"}]},"resolution_status":{"oneOf":[{"$ref":"#/components/schemas/GovernanceResolutionStatus"},{"type":"null"}]},"action_taken":{"type":["string","null"]},"resolved_by":{"type":["string","null"],"format":"uuid"},"resolved_at":{"type":["string","null"],"format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time"},"webhook_delivery_id":{"type":["string","null"],"format":"uuid"},"notification_state":{"$ref":"#/components/schemas/GovernanceNotificationState"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"GovernanceSignalsListResponse":{"type":"object","required":["signals"],"properties":{"signals":{"type":"array","items":{"$ref":"#/components/schemas/GovernanceSignal"}},"total":{"type":"integer","minimum":0}}},"GovernanceDestinationFilter":{"type":"object","additionalProperties":false,"properties":{"sources":{"type":"array","items":{"$ref":"#/components/schemas/GovernanceSignalSource"}},"severities":{"type":"array","items":{"$ref":"#/components/schemas/GovernanceSignalSeverity"}},"scopes":{"type":"array","items":{"$ref":"#/components/schemas/GovernanceSignalScope"}},"pattern_types":{"type":"array","items":{"type":"string"}}}},"GovernanceNotificationDestination":{"type":"object","required":["id","org_id","channel","config","filter","enabled","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid"},"org_id":{"type":"string"},"channel":{"$ref":"#/components/schemas/GovernanceNotificationChannel"},"config":{"type":"object","additionalProperties":true},"filter":{"$ref":"#/components/schemas/GovernanceDestinationFilter"},"enabled":{"type":"boolean"},"display_name":{"type":["string","null"]},"created_by":{"type":["string","null"],"format":"uuid"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"last_tested_at":{"type":["string","null"],"format":"date-time"},"last_test_status":{"type":["string","null"],"enum":["ok","failed"]},"last_test_error":{"type":["string","null"]}}},"GovernanceEscalationPredicate":{"type":"object","additionalProperties":true,"properties":{"source":{"$ref":"#/components/schemas/GovernanceSignalSource"},"pattern_type":{"type":"string"},"severity":{"$ref":"#/components/schemas/GovernanceSignalSeverity"},"severity_min":{"$ref":"#/components/schemas/GovernanceSignalSeverity"},"severity_max":{"$ref":"#/components/schemas/GovernanceSignalSeverity"},"scope":{"$ref":"#/components/schemas/GovernanceSignalScope"},"team_id":{"type":"string","format":"uuid"},"threshold_count":{"type":"integer","minimum":1},"window_minutes":{"type":"integer","minimum":1}}},"GovernanceEscalationRule":{"type":"object","required":["id","org_id","name","predicate","destination_ids","enabled","fire_count","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid"},"org_id":{"type":"string"},"name":{"type":"string"},"predicate":{"$ref":"#/components/schemas/GovernanceEscalationPredicate"},"destination_ids":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":0},"enabled":{"type":"boolean"},"last_fired_at":{"type":["string","null"],"format":"date-time"},"fire_count":{"type":"integer","minimum":0},"created_by":{"type":["string","null"],"format":"uuid"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"GovernanceCoverageReport":{"type":"object","description":"Coverage rollup across the org's teams.","required":["org_id","window_days","by_source","by_severity","totals"],"properties":{"org_id":{"type":"string"},"window_days":{"type":"integer","minimum":1},"by_source":{"type":"object","additionalProperties":{"type":"object","properties":{"fired":{"type":"integer","minimum":0},"acknowledged":{"type":"integer","minimum":0},"resolved":{"type":"integer","minimum":0},"dismissed":{"type":"integer","minimum":0},"open":{"type":"integer","minimum":0}}}},"by_severity":{"type":"object","additionalProperties":{"type":"integer","minimum":0}},"totals":{"type":"object","required":["fired","open"],"properties":{"fired":{"type":"integer","minimum":0},"open":{"type":"integer","minimum":0},"median_time_to_ack_seconds":{"type":["number","null"],"minimum":0}}}}},"PostureScope":{"type":"string","enum":["platform","org"]},"PostureBody":{"type":"object","description":"Trust posture body (PostureBody v1.0). Matches the runtime validator at src/composition/posture-validate.ts EXACTLY — strict-unknown-field rejection (additionalProperties:false) at every level, so adding a field requires a posture_schema_version bump (ADR-023/ADR-045). Used as the `body` of POST /v1/postures and PUT /v1/postures/{id}.","required":["posture_schema_version","sideband","fleet_identification","fan_out"],"additionalProperties":false,"properties":{"posture_schema_version":{"type":"string","const":"v1.0","description":"Schema version pin. Must be exactly `v1.0`."},"sideband":{"type":"object","required":["coherence","fault_line","fleet"],"additionalProperties":false,"properties":{"coherence":{"type":"object","required":["enabled","cadence_seconds","fire_on","severity_on_fire"],"additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"cadence_seconds":{"type":"integer","minimum":1},"severity_on_fire":{"type":"string","enum":["low","medium","high","critical"]},"fire_on":{"type":"object","required":["pairwise_governance_floor_below","conflict_edge_count_exceeds","outlier_agents_count_exceeds"],"additionalProperties":false,"properties":{"pairwise_governance_floor_below":{"type":["number","null"],"minimum":0,"maximum":1,"description":"Fire when pairwise governance floor drops below this; null disables."},"conflict_edge_count_exceeds":{"type":["integer","null"],"minimum":0,"description":"Fire when conflict-edge count exceeds this; null disables."},"outlier_agents_count_exceeds":{"type":["integer","null"],"minimum":0,"description":"Fire when outlier-agent count exceeds this; null disables."}}}}},"fault_line":{"type":"object","required":["enabled","cadence_seconds","severity_floor","use_reputation_scores","severity_on_fire"],"additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"cadence_seconds":{"type":"integer","minimum":1},"severity_floor":{"type":"string","enum":["low","medium","high","critical"]},"use_reputation_scores":{"type":"boolean"},"severity_on_fire":{"type":"string","enum":["low","medium","high","critical"]}}},"fleet":{"type":"object","required":["enabled","cadence_seconds","patterns","severity_on_fire"],"additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"cadence_seconds":{"type":"integer","minimum":1},"severity_on_fire":{"type":"string","enum":["low","medium","high","critical"]},"patterns":{"type":"object","required":["outliers","cluster_partition","min_pair_score_below"],"additionalProperties":false,"properties":{"outliers":{"type":"boolean"},"cluster_partition":{"type":"boolean"},"min_pair_score_below":{"type":["number","null"],"minimum":0,"maximum":1,"description":"Flag pairs scoring below this; null disables."}}}}}}},"fleet_identification":{"type":"object","required":["by"],"additionalProperties":false,"properties":{"by":{"type":"string","enum":["team_membership"]}}},"fan_out":{"type":"object","required":["rule"],"additionalProperties":false,"properties":{"rule":{"type":"string","enum":["per_named_affected_agent"]}}}}},"Posture":{"type":"object","description":"Trust posture row (mig 173). Library row; revisions are versioned bodies stored separately.","required":["posture_id","slug","name","scope","current_revision_id","is_default","created_at","updated_at"],"properties":{"posture_id":{"type":"string","pattern":"^tp-[a-z0-9-]{1,64}$"},"slug":{"type":"string","description":"URL-safe identifier (e.g., 'standard', 'banking-core')."},"name":{"type":"string"},"description":{"type":["string","null"]},"scope":{"$ref":"#/components/schemas/PostureScope"},"org_id":{"type":["string","null"],"description":"NULL for platform-scope postures."},"owner_user_id":{"type":["string","null"],"format":"uuid"},"is_default":{"type":"boolean","description":"True for Mnemom-shipped platform defaults."},"current_revision_id":{"type":["string","null"],"description":"FK to trust_posture_revisions; NULL only mid-create."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"deleted_at":{"type":["string","null"],"format":"date-time","description":"Soft-delete timestamp; NULL = live."}}},"PostureRevision":{"type":"object","description":"Versioned posture body. Immutable by handler discipline (forward-only). Matches revisionForResponse() exactly.","required":["revision_id","posture_id","revision_no","body","change_summary","authored_by","authored_at"],"additionalProperties":false,"properties":{"revision_id":{"type":"string"},"posture_id":{"type":"string"},"revision_no":{"type":"integer","minimum":1},"body":{"type":"object","description":"The versioned posture body (PostureBody shape; older revisions may predate the v1.0 schema).","additionalProperties":true},"change_summary":{"type":["string","null"]},"authored_by":{"type":["string","null"]},"authored_at":{"type":["string","null"],"format":"date-time"}}},"PostureAssignment":{"type":"object","description":"Team→posture binding (one active per team).","required":["team_id","posture_id","assigned_at"],"properties":{"team_id":{"type":"string","format":"uuid"},"posture_id":{"type":"string"},"assigned_revision_id":{"type":["string","null"],"description":"Revision pinned at assignment time (null = tracks current_revision_id)."},"revision_id":{"type":"string","description":"Pinned revision (optional; defaults to current)."},"assigned_by":{"type":["string","null"],"format":"uuid"},"assigned_at":{"type":"string","format":"date-time"},"replaced_prior":{"type":"boolean","description":"`true` when this assignment displaced a previously-active assignment on the team."}}},"PostureEffects":{"type":"object","description":"Analytics rollup: cells affected by this posture revision over a window.","required":["posture_id","window_hours","teams_using","agents_affected"],"properties":{"posture_id":{"type":"string"},"window_hours":{"type":"integer","minimum":1},"teams_using":{"type":"integer","minimum":0},"agents_affected":{"type":"integer","minimum":0},"events_emitted":{"type":"object","additionalProperties":{"type":"integer"},"description":"Per-event-type counts."}}},"PostureDiff":{"type":"object","description":"Structural diff between two revisions (GET /v1/postures/{id}/diff). Matches handleDiffPostureRevisions exactly.","required":["posture_id","from","to","changes"],"additionalProperties":false,"properties":{"posture_id":{"type":"string"},"from":{"type":"object","description":"The `from` revision endpoint.","required":["revision_no","revision_id"],"additionalProperties":false,"properties":{"revision_no":{"type":"integer"},"revision_id":{"type":"string"}}},"to":{"type":"object","description":"The `to` revision endpoint.","required":["revision_no","revision_id"],"additionalProperties":false,"properties":{"revision_no":{"type":"integer"},"revision_id":{"type":"string"}}},"changes":{"type":"array","items":{"type":"object","required":["path","op"],"additionalProperties":false,"properties":{"path":{"type":"string","description":"Dot-path to the changed leaf (`$` for a root scalar change)."},"op":{"type":"string","enum":["added","removed","changed"]},"before":{},"after":{}}}}}},"TeamEffectivePosture":{"type":"object","description":"The team's actual posture cascade (GET /v1/teams/{id}/effective-posture). Matches handleGetTeamEffectivePosture exactly: the gathered Platform → Org → Team layers (each null when its cascade source is unset) plus the composed body.","required":["team_id","org_id","gathered","composed"],"properties":{"team_id":{"type":"string","format":"uuid"},"org_id":{"type":["string","null"]},"gathered":{"type":"object","required":["platform_default","org_assigned","team_assigned"],"properties":{"platform_default":{"type":["object","null"],"additionalProperties":true,"description":"Platform-default posture layer, or null when unset."},"org_assigned":{"type":["object","null"],"additionalProperties":true,"description":"Org-assigned posture layer, or null when unset."},"team_assigned":{"type":["object","null"],"additionalProperties":true,"description":"Team-assigned posture layer, or null when unset."}}},"composed":{"type":"object","description":"Composed posture (Platform ⊕ Org ⊕ Team cascade closure).","additionalProperties":true}}},"PostureComposePreview":{"type":"object","description":"Dry-run composition a posture would produce for a team (POST /v1/postures/{id}/preview-compose). Matches handlePreviewComposePosture exactly: the editor-shaped composed view plus the org floor (Platform ⊕ Org, no team layer). team_id/org_id are null for an org-scoped preview with no resolved team.","required":["posture_id","team_id","org_id","composed","floor"],"properties":{"posture_id":{"type":"string"},"team_id":{"type":["string","null"]},"org_id":{"type":["string","null"]},"composed":{"type":"object","description":"Composed posture with the path posture substituted as the team layer.","additionalProperties":true},"floor":{"type":"object","description":"Org floor (Platform ⊕ Org-default, no team layer) for the editor's 3-column view.","additionalProperties":true}}},"SidebandAdvisorySource":{"type":"string","enum":["sideband.coherence","sideband.fault_line","sideband.fleet","sideband.drift"]},"SidebandAdvisoryRow":{"type":"object","description":"Legacy pre-cutover sideband row. Post ADR-048 cutover, sideband.* sources are written to governance_signals; this query endpoint surveys what historical rows remain in pending_advisories. Sunsetting; clients should consume governance_signals directly.","required":["id","agent_id","source","status","created_at"],"properties":{"id":{"type":"string"},"agent_id":{"type":"string"},"team_id":{"type":["string","null"],"format":"uuid"},"source":{"$ref":"#/components/schemas/SidebandAdvisorySource"},"status":{"type":"string","enum":["pending","delivered","consumed","expired"]},"nudge_content":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time"}}},"SidebandAdvisoryListResponse":{"type":"object","required":["advisories"],"properties":{"advisories":{"type":"array","items":{"$ref":"#/components/schemas/SidebandAdvisoryRow"}}}},"SidebandCoverageReport":{"type":"object","description":"Per-team sideband sweep coverage over a 30-day window: per-axis rollup + raw daily rows. Operator dashboard input.","required":["team_id","window_days","summary","rows"],"properties":{"team_id":{"type":"string","description":"Team the coverage was computed for."},"window_days":{"type":"integer","minimum":1,"description":"Lookback window in days over which coverage is aggregated (currently fixed at 30)."},"summary":{"type":"array","description":"Per-axis rollup of sweep counts over the window.","items":{"type":"object","required":["axis","total_swept","total_fired","total_skipped","last_swept_at","last_outcome"],"properties":{"axis":{"type":"string","description":"Sweep axis (e.g. coherence, fault_line, fleet)."},"total_swept":{"type":"integer","minimum":0},"total_fired":{"type":"integer","minimum":0},"total_skipped":{"type":"integer","minimum":0},"last_swept_at":{"type":["string","null"],"description":"Timestamp of the most recent sweep for this axis, or null if never swept in-window."},"last_outcome":{"type":["string","null"],"description":"Outcome recorded on the most recent sweep, or null."}}}},"rows":{"type":"array","description":"Raw per-day, per-axis sweep log rows, ordered day desc then axis asc.","items":{"type":"object","required":["team_id","axis","day","swept_count","fired_count","skipped_count","last_swept_at","last_outcome","last_duration_ms"],"properties":{"team_id":{"type":"string"},"axis":{"type":"string"},"day":{"type":"string","description":"Sweep day (DATE)."},"swept_count":{"type":"integer","minimum":0},"fired_count":{"type":"integer","minimum":0},"skipped_count":{"type":"integer","minimum":0},"last_swept_at":{"type":"string"},"last_outcome":{"type":"string"},"last_duration_ms":{"type":["integer","null"],"minimum":0}}}}}},"TeamAdmin":{"type":"object","description":"Team-admin grant — allows a non-org-admin user to administer one team.","required":["user_id","team_id","granted_at"],"properties":{"user_id":{"type":"string","format":"uuid"},"team_id":{"type":"string","format":"uuid"},"granted_by":{"type":["string","null"],"format":"uuid"},"granted_at":{"type":"string","format":"date-time"},"revoked_at":{"type":["string","null"],"format":"date-time","description":"When the grant was revoked. `null` on active grants."},"idempotent_noop":{"type":"boolean","description":"Present on grant and revoke responses. `true` when the request was a no-op (grant already active / already revoked)."}}},"ApiKeyWhoAmI":{"type":"object","description":"Caller introspection — the principal authenticated for this request. Returned by `GET /v1/api-keys/whoami`. The handler is generalized across `cookie`, `jwt`, and `api_key` auth methods, so the API-key-specific fields (`key_id`, `account_id`, `scopes`) are null on cookie/JWT principals.","required":["user_id","auth_method"],"properties":{"user_id":{"type":"string","description":"Authenticated principal identifier (Supabase user UUID for cookie/JWT auth; api-key-bound user UUID for api_key auth)."},"email":{"type":["string","null"]},"auth_method":{"type":"string","enum":["cookie","jwt","api_key"]},"key_id":{"type":["string","null"],"description":"API key id (e.g. `mnk_...`), or null for cookie/JWT auth."},"account_id":{"type":["string","null"],"description":"Billing account id, or null for cookie/JWT auth."},"org_id":{"type":["string","null"]},"scopes":{"type":["array","null"],"items":{"type":"string"},"description":"Capability scopes (ADR-049) for api-key auth; null for cookie/JWT. e.g., ['gateway.send', 'gateway.observe']."},"is_admin":{"type":["boolean","null"]}}},"OperatorAttestationRequest":{"type":"object","description":"Sign an operator-issued attestation about a checkpoint, signal, or audit-relevant event. Returns an Ed25519-signed envelope binding the operator's identity to the asserted statement at the asserted time.","required":["subject","statement"],"properties":{"subject":{"type":"object","description":"What's being attested about (e.g., {type: 'governance_signal', id: 'gs-...'}).","additionalProperties":true},"statement":{"type":"string","description":"Free-form operator statement."},"actor_role":{"$ref":"#/components/schemas/GovernanceActorRole"}}},"OperatorAttestationResponse":{"type":"object","required":["attestation_id","signed_at","signature"],"properties":{"attestation_id":{"type":"string"},"signed_at":{"type":"string","format":"date-time"},"signed_by":{"type":"string","format":"uuid"},"actor_role":{"$ref":"#/components/schemas/GovernanceActorRole"},"subject":{"type":"object","additionalProperties":true},"statement":{"type":"string"},"signature":{"type":"string","description":"base64url Ed25519 signature."},"public_key":{"type":"string","description":"base64url Ed25519 public key."}}},"MyRole":{"type":["string","null"],"enum":["super_admin","org_owner","org_admin","team_admin","org_member","org_viewer","org_auditor",null],"description":"The caller's effective role on the resource. Computed server-side per ADR-053; frontends derive `canEdit` exclusively from this field. `team_admin` only appears on team-scope responses. `null` means the caller has no role on this resource (the request still authenticated, but no role applies — e.g. an org-scope response read by an unrelated user)."},"CardSourceScope":{"type":"object","required":["card_json","available"],"description":"One slice of a sources envelope. `card_json` carries the raw template at that scope (full UnifiedAlignment/Protection card, the org/team template, or the platform-defaults object). `available: false` means no card is configured at this scope.","properties":{"card_json":{"type":["object","null"],"additionalProperties":true},"available":{"type":"boolean"}}},"OrgCardSourceScope":{"allOf":[{"$ref":"#/components/schemas/CardSourceScope"},{"type":"object","properties":{"org_id":{"type":["string","null"]},"org_name":{"type":["string","null"]}}}]},"TeamCardSourceScope":{"allOf":[{"$ref":"#/components/schemas/CardSourceScope"},{"type":"object","required":["team_id"],"properties":{"team_id":{"type":"string"},"team_name":{"type":["string","null"]}}}]},"AlignmentCardSourcesEnvelope":{"type":"object","required":["platform","org","teams","agent","composed","composed_stale","my_role"],"description":"Four-scope sources envelope returned by `GET /v1/agents/{agent_id}/alignment-card?include=sources`. Per ADR-053 the envelope mirrors the composer cascade Platform → Org → Team(s) → Agent and carries the caller's effective role + a staleness signal.","properties":{"platform":{"$ref":"#/components/schemas/CardSourceScope"},"org":{"$ref":"#/components/schemas/OrgCardSourceScope"},"teams":{"type":"array","items":{"$ref":"#/components/schemas/TeamCardSourceScope"},"description":"Zero-or-more team-scope contributions. Empty when the agent is in no teams (Charter §I11 amended). Ordered by `teams.created_at ASC` to match the composer's stable order."},"agent":{"$ref":"#/components/schemas/CardSourceScope"},"composed":{"$ref":"#/components/schemas/CardSourceScope"},"composed_stale":{"type":"boolean","description":"True when `composed.card_json._composition.scopes_applied` disagrees with the current `team_templates` set in `gather_composition_inputs` (the queue worker will reconverge via the existing `needs_recompose` flag)."},"my_role":{"$ref":"#/components/schemas/MyRole"}}},"ProtectionCardSourcesEnvelope":{"type":"object","required":["platform","org","teams","agent","composed","composed_stale","my_role"],"description":"Four-scope sources envelope returned by `GET /v1/agents/{agent_id}/protection-card?include=sources`. Identical shape to `AlignmentCardSourcesEnvelope`.","properties":{"platform":{"$ref":"#/components/schemas/CardSourceScope"},"org":{"$ref":"#/components/schemas/OrgCardSourceScope"},"teams":{"type":"array","items":{"$ref":"#/components/schemas/TeamCardSourceScope"}},"agent":{"$ref":"#/components/schemas/CardSourceScope"},"composed":{"$ref":"#/components/schemas/CardSourceScope"},"composed_stale":{"type":"boolean"},"my_role":{"$ref":"#/components/schemas/MyRole"}}},"PlatformCardDefaultsResponse":{"type":"object","required":["available"],"additionalProperties":true,"description":"Base (non-`?include=sources`) JSON body of `GET /v1/{alignment,protection}/platform/{scope_id}`. The platform scope is a template/defaults wrapper, not a full composed card: `handleGet` in src/composition/platform-handlers.ts returns `{ defaults, available }` where `defaults` is the authored platform-defaults JSON (a partial card) or `null` when none is set. YAML is the default representation and is not response-validated; this schema governs the JSON variant returned on `Accept: application/json`.","properties":{"defaults":{"type":["object","null"],"additionalProperties":true,"description":"The authored platform-scope defaults JSON (a partial card), or `null` when no platform defaults are set."},"available":{"type":"boolean","description":"True when platform-scope defaults are set (`defaults !== null`)."}}},"PlatformCardSourceScope":{"type":"object","required":["available"],"additionalProperties":true,"description":"One scope leaf in the platform two-scope sources envelope. `card_json` is the platform-defaults JSON (a partial card) or `null`.","properties":{"card_json":{"type":["object","null"],"additionalProperties":true},"available":{"type":"boolean"}}},"PlatformCardSourcesEnvelope":{"type":"object","required":["platform","composed"],"additionalProperties":true,"description":"Two-scope sources envelope returned by `GET /v1/{alignment,protection}/platform/{scope_id}?include=sources` (JSON-only). Composed equals Platform — the platform scope is the top of the cascade, so there is no upstream layer to constrain it. Shape matches the `?include=sources` branch of `handleGet` in src/composition/platform-handlers.ts.","properties":{"platform":{"$ref":"#/components/schemas/PlatformCardSourceScope"},"composed":{"$ref":"#/components/schemas/PlatformCardSourceScope"}}},"TeamTemplateSourcesEnvelope":{"type":"object","required":["platform","org","team","composed","composed_stale","my_role"],"description":"Three-scope sources envelope returned by `GET /v1/teams/{team_id}/{alignment,protection}-template?include=sources`. The team row is the editable scope; agent layer is omitted (team-scope has no specific agent above it).","properties":{"platform":{"$ref":"#/components/schemas/CardSourceScope"},"org":{"$ref":"#/components/schemas/OrgCardSourceScope"},"team":{"$ref":"#/components/schemas/TeamCardSourceScope"},"composed":{"$ref":"#/components/schemas/CardSourceScope"},"composed_stale":{"type":"boolean","description":"Always false at team-template scope today (team-scope composition is in-memory per request). Included for envelope symmetry with the agent-scope envelopes."},"my_role":{"$ref":"#/components/schemas/MyRole"}}},"OrgTemplateSourcesEnvelope":{"type":"object","required":["platform","org","composed","my_role"],"description":"Two-scope sources envelope returned by `GET /v1/orgs/{org_id}/{alignment,protection}-template?include=sources`. No team or agent layer (org templates compose only against the platform floor).","properties":{"platform":{"$ref":"#/components/schemas/CardSourceScope"},"org":{"$ref":"#/components/schemas/OrgCardSourceScope"},"composed":{"$ref":"#/components/schemas/CardSourceScope"},"my_role":{"$ref":"#/components/schemas/MyRole"}}},"TeamMyRoleResponse":{"type":"object","required":["team_id","my_role"],"description":"Response body of `GET /v1/teams/{team_id}/my-role`. Used by surfaces that don't load a template sources envelope (team roster tab, identity card tab, admins tab) to gate edit affordances from the same single source of truth as the editors.","properties":{"team_id":{"type":"string"},"my_role":{"$ref":"#/components/schemas/MyRole"}}},"RetentionSettings":{"type":"object","required":["org_id","retention_days","enforcement_active"],"description":"Aletheia Customer Voice retention configuration for an org (MNE-2407, `feedback_retention_settings`). `retention_days` is a caller-configured retention window (1-3650) or `null` to retain indefinitely (the default for an org with no configured row yet). `enforcement_active` is ALWAYS `false` today — this build ships configuration + storage + audit only; no cron yet reads `retention_days` to auto-erase aged submissions (tracked follow-up, MNE-440/MNE-443). Returned by both `GET` and `PATCH .../customer-voice/settings`.","properties":{"org_id":{"type":"string","description":"Organization identifier (e.g. org-abc12345)."},"retention_days":{"type":["integer","null"],"minimum":1,"maximum":3650,"description":"Retention window in days, or `null` to retain indefinitely."},"updated_by":{"type":["string","null"],"description":"User id that last wrote this setting, or `null` if never set."},"updated_at":{"type":["string","null"],"format":"date-time","description":"When this setting was last written, or `null` if never set."},"enforcement_active":{"type":"boolean","description":"Always `false` today (honest-voice, MNE-440/MNE-443): retention configuration is stored and audited but not yet enforced by any deletion cron."}}},"ComposedAlignmentCard":{"type":"object","description":"OUTPUT-only variant of `UnifiedAlignmentCard` for the COMPOSED card the server emits on GET `/v1/alignment/{scope}/{id}`, `/effective`, and the `composed` field of preview-compose. Identical to `UnifiedAlignmentCard` except `principal` is optional (a default / org-scope composed card has no agent principal) and `values.declared` / `autonomy.bounded_actions` may be empty (a fresh card declares nothing yet). The strict `UnifiedAlignmentCard` remains the authoring/request contract.","required":["card_version","agent_id","autonomy_mode","integrity_mode","values","autonomy","audit"],"properties":{"card_version":{"type":"string","minLength":1,"description":"Card schema version (required, non-empty). Current canonical value: `unified/2026-04-26`."},"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"],"description":"ADR-039 master switch for the action-policing pipeline (autonomy constraints). Required at the top level post-cutover; the legacy `enforcement.mode` location is rejected."},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"],"description":"ADR-039 master switch for the values/conscience pipeline (integrity constraints). Required at the top level post-cutover; the legacy `integrity.enforcement_mode` location is rejected."},"card_id":{"type":"string","description":"Card row id. Server-assigned on PUT (`ac-{uuid}`)."},"agent_id":{"type":"string","description":"Target agent id. On PUT, server overwrites to match the URL path."},"issued_at":{"type":"string","format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time"},"principal":{"type":"object","description":"Required object describing whose authority the agent acts under (ADR-039 Decision 10).","properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string","minLength":1,"description":"Required (non-empty) when principal.type is not `unspecified`; identifies the human / organization / agent."},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}},"required":["type","relationship"],"allOf":[{"if":{"properties":{"type":{"not":{"const":"unspecified"}}}},"then":{"required":["identifier"]}}]},"values":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{"oneOf":[{"type":"string","minLength":1},{"type":"object","required":["id"],"properties":{"id":{"type":"string","minLength":1}},"additionalProperties":{"type":"string"}}]},"description":"Ordered list of declared values. Phase 1 cards-as-primitive: each entry is either a catalog-v1 ID string (e.g. `'accuracy'`) or a parameterized map carrying optional `intensity` / `domain` / `severity_on_violation` / `scope` (e.g. `{id: 'accuracy', domain: 'financial', severity_on_violation: 'critical'}`)."},"definitions":{"type":"object","additionalProperties":{"type":"object","properties":{"description":{"type":"string"},"priority":{"type":"integer"}}}},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}},"conscience":{"type":"object","properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object","required":["type","content"],"properties":{"type":{"type":"string","enum":["BOUNDARY","FEAR","COMMITMENT","BELIEF","HOPE"]},"content":{"type":"string"},"id":{"type":"string"},"severity":{"type":"string","enum":["advisory","mandatory"]}}}}},"required":["mode","values"]},"autonomy":{"type":"object","required":["bounded_actions"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object","required":["condition","action","reason"],"properties":{"condition":{"type":"string"},"action":{"type":"string","enum":["escalate","deny","log"]},"reason":{"type":"string"}}}},"max_autonomous_value":{"type":"object","properties":{"amount":{"type":"number"},"currency":{"type":"string"}}}}},"capabilities":{"type":"object","additionalProperties":{"type":"object","properties":{"description":{"type":"string"},"tools":{"type":"array","items":{"type":"string"}},"required_actions":{"type":"array","items":{"type":"string"}}}}},"enforcement":{"type":"object","description":"Optional ADR-039 Decision-3 user-facing knobs for unmapped-tool handling. The legacy `mode`, `unmapped_tool_action` and `fail_open` keys are REJECTED by the validator (mode → top-level autonomy_mode; fail_open → gateway env config).","properties":{"allow_unmapped_tools":{"type":"boolean","description":"When true, tools not mapped to a capability are allowed by default."},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"],"description":"Severity assigned to an unmapped tool when allow_unmapped_tools is false."},"forbidden_tools":{"type":"array","items":{"type":"object","required":["pattern","reason","severity"],"properties":{"pattern":{"type":"string"},"reason":{"type":"string"},"severity":{"type":"string","enum":["critical","high","medium","low"]}}}},"grace_period_hours":{"type":"integer"}}},"audit":{"type":"object","required":["retention_days","queryable"],"allOf":[{"if":{"properties":{"queryable":{"const":true}},"required":["queryable"]},"then":{"required":["query_endpoint"]}}],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer","minimum":0},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string","description":"Required when audit.queryable is true."},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object","properties":{"type":{"type":"string","enum":["local","remote","distributed"]},"location":{"type":"string"}}}}},"extensions":{"type":"object","additionalProperties":true},"_composition":{"$ref":"#/components/schemas/CompositionMetadata"},"content_hash":{"type":"string","description":"Response-only: content hash of the composed card (`sha256:<hex>`), injected by the GET/PUT response. Server-assigned — do not send on a PUT."},"version":{"type":"integer","description":"Response-only: monotonic card version, injected by the GET/PUT response. Server-assigned — do not send on a PUT."}}},"ConscienceValueOutput":{"type":"object","required":["type","content"],"properties":{"type":{"type":"string","enum":["BOUNDARY","FEAR","COMMITMENT","BELIEF","HOPE"]},"name":{"type":"string"},"content":{"type":"string"},"id":{"type":"string"},"severity":{"type":"string","enum":["advisory","mandatory"]}},"description":"OUTPUT variant of `ConscienceValue`. A conscience value read back from an agent's card (or the built-in DEFAULT_CONSCIENCE_VALUES) is `{type, content}` plus an optional stable `id` / `severity`; it has no `name` (only the `/conscience-values` PUT input attaches a name). `name` is therefore optional on output, and `id` / `severity` are documented."}}},"paths":{"/.well-known/jwks.json":{"get":{"operationId":"getAttestationJwks","security":[],"summary":"Public JWKS for AAP attestation tokens.","description":"Returns the set of public keys verifying Mnemom-signed AAP attestation tokens. The active key signs new attestations; retired keys remain in the set for the token-TTL window plus grace. Unauthenticated; cacheable for 5 minutes. cards-as-primitive Phase 5 A1.","tags":["Attestation"],"responses":{"200":{"description":"Current key set.","content":{"application/json":{"schema":{"type":"object","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"object","required":["kty","crv","x","kid","alg","use"],"properties":{"kty":{"const":"OKP"},"crv":{"const":"Ed25519"},"x":{"type":"string","description":"base64url-encoded 32-byte Ed25519 public point."},"kid":{"type":"string","description":"Key identifier; matches the `kid` claim in tokens this key signs."},"alg":{"const":"EdDSA"},"use":{"const":"sig"},"mnemom_ext":{"type":"object","description":"Mnemom-specific JWK extension carrying rotation state. Standard JOSE verifiers ignore unknown fields; clients that want to surface rotation in the UI read this block.","properties":{"status":{"type":"string","enum":["active","retired"]},"activated_at":{"type":"string","format":"date-time"},"retired_at":{"type":"string","format":"date-time"},"rotation_reason":{"type":"string"}}}}}}}}}},"headers":{"Cache-Control":{"schema":{"type":"string","example":"public, max-age=300, stale-while-revalidate=600"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/agent-groups":{"post":{"operationId":"createAgentGroup","summary":"Create an agent group","description":"Create a new agent group (a logical tag) in an organization. Group names must be unique among active groups within the organization. Optionally seed the group with an initial set of agent members.","tags":["Agent Groups"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["org_id","name"],"properties":{"org_id":{"type":"string","description":"Organization that owns this group"},"name":{"type":"string","maxLength":100,"description":"Display name (unique among active groups in the org)"},"description":{"type":["string","null"],"description":"Optional description"},"color":{"type":["string","null"],"pattern":"^#[0-9A-Fa-f]{6}$","description":"Optional group colour as #rrggbb hex. Omit or null for no colour."},"agent_ids":{"type":"array","items":{"type":"string"},"maxItems":50,"description":"Agent IDs to add as initial members (optional)"},"metadata":{"type":"object","additionalProperties":true,"description":"Freeform metadata"}}}}}},"responses":{"201":{"description":"Group created","content":{"application/json":{"schema":{"type":"object","properties":{"group_id":{"type":"string"},"org_id":{"type":"string"},"name":{"type":"string"},"color":{"type":["string","null"]},"status":{"type":"string","enum":["active"]},"member_count":{"type":"integer"},"members":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Name conflict — a group with this name already exists among the org's active groups (name uniqueness is case-insensitive). The body carries `error.code: \"group_name_taken\"` and, when the existing group is resolvable, a safe `existing_group` summary a client can steer the user onto. Both the pre-check path and the concurrent-create race path return an identical body.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["group_name_taken"]},"message":{"type":"string"},"details":{"type":"object","description":"Present when the existing group is resolvable; omitted on a rare race where the winning row cannot be re-read.","properties":{"existing_group":{"type":"object","description":"Safe summary of the existing group — only these four fields, never org_id/created_by/metadata.","properties":{"id":{"type":"string"},"name":{"type":"string"},"color":{"type":["string","null"]},"member_count":{"type":"integer"}}}}}}}}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"get":{"operationId":"listAgentGroups","summary":"List agent groups in an organization","description":"List the active agent groups for an organization. With no `q`, groups are returned ordered by creation time (newest first). With `q`, groups are filtered by a case-insensitive name search and ranked most-relevant-first (exact → prefix → fuzzy, then recency, then member count) so a suggestion UI can offer existing groups. Each item carries a `match_type` discriminator (`none` when no `q` was supplied). Optional `limit`/`offset` bound the response; when neither is supplied the legacy `{ groups }` envelope is returned unchanged. Returns an empty array when nothing matches.","tags":["Agent Groups"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"org_id","in":"query","required":true,"schema":{"type":"string"},"description":"Organization whose groups to list"},{"name":"q","in":"query","required":false,"schema":{"type":"string"},"description":"Optional case-insensitive name search. When present, non-matching groups are dropped and the rest are ranked exact → prefix → fuzzy."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"description":"Optional page size, clamped to [1, 200] (defaults to 50 when only `offset` is supplied). Bounds the response after ranking so the highest-ranked suggestions survive truncation."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0},"description":"Optional row offset (≥ 0) into the ranked result."}],"responses":{"200":{"description":"List of active groups (filtered + ranked when `q` is supplied)","content":{"application/json":{"schema":{"type":"object","required":["groups"],"properties":{"groups":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"color":{"type":["string","null"],"description":"Group colour as #rrggbb, or null when no colour is set."},"match_type":{"type":"string","enum":["exact","prefix","fuzzy","none"],"description":"How this group matched `q` (`none` when no `q` was supplied)."}}}},"total":{"type":"integer","description":"Total matched groups before paging (present only when paginated)."},"limit":{"type":"integer","description":"Applied page size (present only when paginated)."},"offset":{"type":"integer","description":"Applied row offset (present only when paginated)."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/agent-groups/{group_id}":{"get":{"operationId":"getAgentGroup","summary":"Get an agent group by ID","description":"Retrieve a group and its current members.","tags":["Agent Groups"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent-group identifier (UUID)."}],"responses":{"200":{"description":"Group details with members","content":{"application/json":{"schema":{"type":"object","properties":{"group_id":{"type":"string"},"org_id":{"type":"string"},"name":{"type":"string"},"color":{"type":["string","null"],"description":"Group colour as #rrggbb, or null when no colour is set."},"status":{"type":"string","enum":["active","archived"]},"member_count":{"type":"integer"},"members":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"patch":{"operationId":"updateAgentGroup","summary":"Update an agent group","description":"Update a group's name, description, or metadata.","tags":["Agent Groups"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent-group identifier (UUID)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"description":"Display name"},"description":{"type":["string","null"],"description":"Optional description"},"color":{"type":["string","null"],"pattern":"^#[0-9A-Fa-f]{6}$","description":"Optional group colour as #rrggbb. Send null to clear."},"metadata":{"type":"object","additionalProperties":true,"description":"Freeform metadata"}}}}}},"responses":{"200":{"description":"Group updated","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"boolean"},"group_id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"delete":{"operationId":"archiveAgentGroup","summary":"Archive an agent group","description":"Archive a group (soft-delete via status='archived'). An archived group's name is freed for reuse; membership rows are retained.","tags":["Agent Groups"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent-group identifier (UUID)."}],"responses":{"200":{"description":"Group archived","content":{"application/json":{"schema":{"type":"object","properties":{"archived":{"type":"boolean"},"group_id":{"type":"string"},"affected_member_count":{"type":"integer","description":"Number of memberships attached to the group at archive time (retained; agents are not modified)."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/agent-groups/{group_id}/members":{"post":{"operationId":"addAgentGroupMembers","summary":"Add members to an agent group","description":"Add one or more agents to a group. Membership is a set — re-adding an existing member is idempotent (reported under already_present, not an error). At most 50 agent IDs per request.","tags":["Agent Groups"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent-group identifier (UUID)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["agent_ids"],"properties":{"agent_ids":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":50,"description":"Agent IDs to add"}}}}}},"responses":{"200":{"description":"Members added","content":{"application/json":{"schema":{"type":"object","properties":{"group_id":{"type":"string"},"added":{"type":"array","items":{"type":"string"}},"already_present":{"type":"array","items":{"type":"string"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"get":{"operationId":"getAgentGroupMembers","summary":"List an agent group's members","description":"Returns the current set of agent memberships for a group.","tags":["Agent Groups"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent-group identifier (UUID)."}],"responses":{"200":{"description":"Group member list","content":{"application/json":{"schema":{"type":"object","properties":{"group_id":{"type":"string"},"members":{"type":"array","items":{"type":"object","additionalProperties":true}},"member_count":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/agent-groups/{group_id}/members/{agent_id}":{"delete":{"operationId":"removeAgentGroupMember","summary":"Remove a member from an agent group","description":"Remove an agent from a group. This hard-deletes the membership row — the agent leaves the set immediately (groups keep no roster history).","tags":["Agent Groups"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent-group identifier (UUID)."},{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"Member removed","content":{"application/json":{"schema":{"type":"object","properties":{"removed":{"type":"boolean"},"group_id":{"type":"string"},"agent_id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/agents":{"post":{"operationId":"registerAgent","summary":"Register a new agent","description":"Register a new agent with a name and hash proof. Optionally attach an alignment card and policy.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","hash_proof"],"properties":{"name":{"type":"string","description":"Agent name. 2-32 characters, alphanumeric and hyphens only, must start and end with alphanumeric.","pattern":"^[a-zA-Z0-9][a-zA-Z0-9-]{0,30}[a-zA-Z0-9]$","minLength":2,"maxLength":32,"example":"my-agent"},"hash_proof":{"type":"string","description":"SHA256 hex string used to derive the agent ID and hash.","minLength":16,"example":"a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"},"card_json":{"type":"object","description":"Optional alignment card JSON to attach on creation.","additionalProperties":true},"policy_yaml":{"type":"string","description":"Optional YAML policy string to create alongside the agent."}}}}}},"responses":{"201":{"description":"Agent registered successfully","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Agent ID (e.g. smolt-abc12345)","example":"smolt-a1b2c3d4"},"agent_hash":{"type":"string","description":"First 16 characters of the hash_proof"},"name":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"card_id":{"type":"string","description":"ID of the created alignment card"},"policy_created":{"type":"boolean","description":"Whether a policy was created from the provided policy_yaml"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"get":{"operationId":"listAgents","summary":"List your agents","description":"List all agents owned by the authenticated user. Supports pagination.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":100},"description":"Maximum number of agents to return (max 100)"},{"name":"offset","in":"query","schema":{"type":"integer","default":0},"description":"Number of agents to skip for pagination"}],"responses":{"200":{"description":"The caller's agents for the requested scope. `scope=active` (default) returns the active-org fleet (or active-context-less owned agents); `scope=all` returns every agent the user owns across contexts.","content":{"application/json":{"schema":{"type":"object","required":["agents","scope"],"additionalProperties":false,"properties":{"agents":{"type":"array","items":{"$ref":"#/components/schemas/Agent"}},"scope":{"type":"string","enum":["active","all"],"description":"Echoes the resolved listing scope."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/groups:batch":{"put":{"operationId":"batchAgentGroupMembership","summary":"Apply an atomic add/remove membership batch","description":"Apply a mixed set of add + remove operations across multiple agents and multiple groups in a single call, **all-or-nothing**. The whole batch executes inside one database transaction: if any id is invalid, inaccessible, or belongs to a foreign org, the entire batch is rejected and nothing is applied. Membership is a set — an add of an existing member and a remove of a non-member are idempotent no-ops (reported via the `*_noop_count` fields), so re-sending an identical batch changes nothing and returns 200. Duplicate operations within one request are deduped; the same (agent, group) pair appearing as both an add and a remove is contradictory and rejected. At most 50 operations per request.","tags":["Agent Groups"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["org_id","ops"],"properties":{"org_id":{"type":"string","description":"Organization that owns the targeted groups and agents"},"ops":{"type":"array","minItems":1,"maxItems":50,"description":"The add/remove operations to apply atomically","items":{"type":"object","required":["op","group_id","agent_id"],"properties":{"op":{"type":"string","enum":["add","remove"],"description":"Whether to add the agent to, or remove it from, the group"},"group_id":{"type":"string","format":"uuid","description":"Target group (UUID)"},"agent_id":{"type":"string","description":"Target agent"}}}}}}}}},"responses":{"200":{"description":"Batch applied atomically. `added`/`removed` are the ids that actually CHANGED; the `*_noop_count` fields count operations that were already in the requested state; `ops_applied` (post-dedupe) may be less than `ops_received` (raw count) when duplicate operations were collapsed.","content":{"application/json":{"schema":{"type":"object","required":["added","removed","added_count","removed_count","add_noop_count","remove_noop_count","ops_applied","ops_received"],"properties":{"added":{"type":"array","items":{"type":"string"},"description":"Agent ids that were newly added (real changes only)"},"removed":{"type":"array","items":{"type":"string"},"description":"Agent ids that were actually removed (real changes only)"},"added_count":{"type":"integer"},"removed_count":{"type":"integer"},"add_noop_count":{"type":"integer","description":"Add ops whose agent was already a member (idempotent no-op)"},"remove_noop_count":{"type":"integer","description":"Remove ops whose agent was already absent (idempotent no-op)"},"ops_applied":{"type":"integer","description":"Distinct operations applied after dedupe"},"ops_received":{"type":"integer","description":"Raw operation count as submitted (before dedupe)"}}}}}},"400":{"description":"Bad request. Covers a malformed body / missing `org_id` / non-array or empty `ops` / over-limit (`> 50`); an invalid op value, group_id, or agent_id; a contradictory add+remove of the same (agent, group) pair (`error.code: \"conflicting_ops\"`); an archived target group (`error.code: \"group_archived\"`); and an inaccessible/foreign-org **agent** id. Note: an inaccessible or foreign-org agent is returned as **400** with `error.code: \"agent_not_found\"` — deliberately NOT a 404 — so a caller cannot distinguish a genuinely missing agent from one that exists in an organization they cannot see (no cross-org existence leakage), matching the single-agent membership endpoints.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"An inaccessible, invalid, or foreign-org **group** id (`error.code: \"group_not_found\"`) — the same signal a genuinely missing group returns, so group existence does not leak across org boundaries. The entire batch is rejected; nothing is applied.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/agents/topology":{"get":{"operationId":"getAgentTopology","summary":"Graph of the caller's agents + trust edges","description":"Returns a `{nodes, edges}` graph of every agent linked to the authenticated user, suitable for dashboard topology rendering. Available to every authenticated caller — the former `trust_topology` plan gate was retired in MNE-2567, because this returns the caller's own data and output completeness never varies by pricing tier. Falls back to `{nodes: [], edges: []}` if the backing RPC fails.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"x-schemathesis":{"hypothesis":{"deadline":10000,"suppress_health_check":["too_slow"]}},"responses":{"200":{"description":"Topology graph.","content":{"application/json":{"schema":{"type":"object","required":["nodes","edges"],"properties":{"nodes":{"type":"array","items":{"type":"object"}},"edges":{"type":"array","items":{"type":"object"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}":{"get":{"operationId":"getAgent","summary":"Get agent by ID","tags":["Agents"],"security":[{"BearerAuth":[]},{}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"Agent details. Private agents return a limited response to non-owners.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Agent"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"updateAgent","summary":"Update agent name","description":"Update the name of an agent you own.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"New agent name. 2-32 characters, alphanumeric and hyphens only.","pattern":"^[a-zA-Z0-9][a-zA-Z0-9-]{0,30}[a-zA-Z0-9]$","minLength":2,"maxLength":32}}}}}},"responses":{"200":{"description":"Updated agent record","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Agent"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"delete":{"operationId":"deleteAgent","summary":"Delete agent (GDPR Art. 17 cascade)","description":"Tombstone an agent and asynchronously cascade deletion across all agent-owned records (traces, integrity checkpoints, drift alerts, reclassifications, etc.) per ADR-021. The request returns `202 Accepted` immediately with a `deletion_request_id`; poll [GET /v1/agents/{agent_id}/deletion-status](/api-reference/endpoint/get-agents-agent-id-deletion-status) or subscribe to the deletion webhook for cascade progress.\n\nIdempotent: re-DELETE on a tombstoned agent returns the existing `deletion_request_id` with the current status.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"202":{"description":"Deletion accepted; cascade will run asynchronously","content":{"application/json":{"schema":{"type":"object","required":["deletion_request_id","status","requested_at"],"properties":{"deletion_request_id":{"type":"string","description":"Stable identifier for this deletion request; pass to deletion-status to poll progress.","example":"del-7f3b9e2a-c41d-4b8e-9f0a-d5c2e8a17b3e"},"status":{"type":"string","enum":["received","tombstoned","phase_1_complete","phase_2_complete","phase_3_complete","phase_4_complete","phase_5_complete","phase_6_complete","phase_7_complete","kv_cleared","pseudonymized","complete","failed"],"description":"Initial state of a fresh delete is `tombstoned` (the synchronous part); the async cascade advances it through `phase_1_complete` … `phase_7_complete` → `kv_cleared` → `pseudonymized` → `complete` (or `failed`). An idempotent re-DELETE echoes the current status, so any of these may appear."},"requested_at":{"type":"string","format":"date-time"},"completed_at":{"type":["string","null"],"format":"date-time","description":"Set once the async cascade finishes. `null` while in flight."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/a2a-agent-card":{"get":{"operationId":"getA2AAgentCard","security":[],"summary":"A2A AgentCard projection of the canonical alignment card.","description":"Public discovery surface. Returns the Mnemom-composed AgentCard in A2A v1.x envelope shape, with AAP alignment + attestation extensions. Gated per-agent by `agents.a2a_export_enabled` (opt-out agents return 404 to avoid enumeration). Unauthenticated; cacheable for 60 seconds; ETag = combined canonical content_hash. cards-as-primitive Phase 5 B2.","tags":["A2A"],"parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"A2A AgentCard.","content":{"application/json":{"schema":{"type":"object","required":["schemaVersion","name","description","url","version","capabilities","skills","extensions","metadata"],"properties":{"schemaVersion":{"const":"1.0"},"name":{"type":"string"},"description":{"type":"string"},"url":{"type":"string","format":"uri"},"version":{"type":"string"},"capabilities":{"type":"object","required":["streaming","pushNotifications"],"properties":{"streaming":{"type":"boolean"},"pushNotifications":{"type":"boolean"}}},"skills":{"type":"array","items":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}}}},"extensions":{"type":"array","items":{"type":"object","required":["uri","required","body"],"properties":{"uri":{"type":"string","format":"uri"},"required":{"type":"boolean"},"body":{"type":"object","additionalProperties":true}}}},"metadata":{"type":"object","properties":{"content_hash":{"type":"string","pattern":"^sha256:[0-9a-f]{64}$"},"composed_at":{"type":"string","format":"date-time"}}}}}}},"headers":{"ETag":{"schema":{"type":"string","example":"\"sha256:<hex>\""}},"Cache-Control":{"schema":{"type":"string","example":"public, max-age=60, stale-while-revalidate=300"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/agents/{agent_id}/alignment-card":{"get":{"operationId":"getAlignmentCardLegacy","summary":"DEPRECATED — use GET /v1/alignment/agent/{agent_id}.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/alignment/agent/{agent_id}`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Agents"],"security":[],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"putAlignmentCardLegacy","summary":"DEPRECATED — use PUT /v1/alignment/agent/{agent_id}.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/alignment/agent/{agent_id}`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Agents"],"security":[],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/alignment-card/preview-compose":{"post":{"operationId":"postAlignmentCardPreviewComposeLegacy","summary":"DEPRECATED — use POST /v1/alignment/agent/{agent_id}/preview-compose.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/alignment/agent/{agent_id}/preview-compose`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Agents"],"security":[],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/avatar":{"put":{"operationId":"putAgentAvatar","summary":"Upload agent avatar","description":"Replace an agent's avatar image. Requires the authenticated principal to be the agent's owner (`agents.user_id == auth.sub`). Old avatar is replaced; storage cleanup happens server-side.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"Avatar image. Validated for MIME type and size before upload."}}}}}},"responses":{"200":{"description":"Avatar uploaded; persistent URL returned","content":{"application/json":{"schema":{"type":"object","required":["avatar_url"],"properties":{"avatar_url":{"type":"string","format":"uri","description":"Public URL of the uploaded avatar (CDN-served).","example":"https://cdn.mnemom.ai/avatars/agents/mnm-7f3b9e2a/abc123.png"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"}}}},"/agents/{agent_id}/card-amendments":{"get":{"operationId":"listCardAmendments","summary":"List card amendment history","description":"Retrieve the history of all alignment card amendments for the specified agent. Card amendments are changes to the agent's alignment card that were triggered by reclassifications, policy changes, or manual edits.","tags":["Reclassification"],"security":[],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"minimum":1,"maximum":100},"description":"Maximum number of amendments to return"},{"name":"offset","in":"query","schema":{"type":"integer","default":0,"minimum":0},"description":"Number of amendments to skip for pagination"}],"responses":{"200":{"description":"Card amendment history — a bare array of amendment records, newest first.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"amendment_id":{"type":"string"},"agent_id":{"type":"string"},"field_changed":{"type":"string"},"old_value":{},"new_value":{},"reason":{"type":"string"},"triggered_by":{"type":"string","enum":["reclassification","policy_change","manual"]},"created_at":{"type":"string","format":"date-time"}}}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/checkpoints":{"get":{"operationId":"listCheckpoints","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"summary":"Paginated integrity checkpoints","tags":["Checkpoints"],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"minimum":1,"maximum":1000}},{"name":"offset","in":"query","schema":{"type":"integer","default":0,"minimum":0}},{"name":"verdict","in":"query","schema":{"type":"string","enum":["clear","review_needed","boundary_violation","unverified"]}},{"name":"session_id","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated checkpoints","content":{"application/json":{"schema":{"type":"object","properties":{"checkpoints":{"type":"array","items":{"$ref":"#/components/schemas/Checkpoint"}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/checkpoints/{checkpoint_id}":{"get":{"operationId":"getCheckpoint","security":[{},{"ApiKeyAuth":[]},{"BearerAuth":[]},{"CookieAuth":[]}],"summary":"Get single checkpoint","tags":["Checkpoints"],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"checkpoint_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Checkpoint details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Checkpoint"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/claim":{"post":{"operationId":"claimAgent","summary":"Claim an agent into an organization","description":"Binds an unclaimed (or legacy hash-claimed) agent to the authenticated caller and an organization. Requires authentication — the caller proves possession of the agent via `hash_proof`, and the agent's `org_id` is set to the resolved org (the authz + listing boundary, ADR-062). Supply `org_id` to claim into a specific org the caller is a member of (role floor: member); omit it to claim into the caller's personal org. Idempotent: re-claiming an agent the caller already owns returns 200 with the resolved org.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["hash_proof"],"properties":{"hash_proof":{"type":"string","minLength":16,"description":"Agent possession proof — either the live birth token (`mnbt_…`) whose row pins this agent's hash, or the full 64-hex SHA-256 digest of `${apiKey}|${agentName}` (or `${apiKey}` for an unnamed singleton agent)."},"org_id":{"type":"string","description":"Optional. The organization to claim the agent into (e.g. `org-...` or `pers-...`). The caller must be a member of this org (role floor: member). If omitted, the agent is claimed into the caller's personal org."}}}}}},"responses":{"200":{"description":"Agent claimed into the resolved organization","content":{"application/json":{"schema":{"type":"object","required":["claimed","agent_id","org_id","claimed_at"],"properties":{"claimed":{"type":"boolean"},"agent_id":{"type":"string"},"org_id":{"type":"string","description":"The organization the agent was claimed into (echoes the resolved org — the supplied `org_id`, or the caller's personal org when omitted)."},"claimed_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Agent already claimed by a different account (`agent_cross_tenant`). The proof is valid but the agent is owned by another principal — this is a resource-state conflict, not a permission failure. Aligns with the hijack-closure contract (#609 / MNE-395).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/agents/{agent_id}/compliance-export":{"get":{"operationId":"exportComplianceRecord","summary":"Export compliance record","description":"Export a comprehensive compliance record for the agent including all checkpoints, reclassifications, card amendments, and score history. Returns a structured document suitable for regulatory audits and compliance reviews.","tags":["Reclassification"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"format","in":"query","schema":{"type":"string","enum":["json","csv"],"default":"json"},"description":"Export format"},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"},"description":"Start of time range"},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"},"description":"End of time range"}],"responses":{"200":{"description":"Compliance export data","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"export_id":{"type":"string"},"generated_at":{"type":"string","format":"date-time"},"period":{"type":"object","properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"}}},"checkpoints":{"type":"array","items":{"type":"object"}},"reclassifications":{"type":"array","items":{"$ref":"#/components/schemas/ReclassificationResult"}},"card_amendments":{"type":"array","items":{"type":"object"}},"score_history":{"type":"array","items":{"type":"object"}}}}},"text/csv":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/conscience-values":{"get":{"operationId":"getConscienceValues","summary":"Get conscience values for agent","tags":["Enforcement"],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"Conscience values","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"conscience_values":{"type":"array","items":{"$ref":"#/components/schemas/ConscienceValueOutput"}},"is_default":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"updateConscienceValues","summary":"Update conscience values","tags":["Enforcement"],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["conscience_values"],"properties":{"conscience_values":{"type":"array","items":{"$ref":"#/components/schemas/ConscienceValue"}}}}}}},"responses":{"200":{"description":"Values updated","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"conscience_values":{"type":"array","items":{"$ref":"#/components/schemas/ConscienceValueOutput"}},"updated":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"delete":{"operationId":"resetConscienceValues","summary":"Reset conscience values to defaults","tags":["Enforcement"],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"Values reset to defaults","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"reset_to_defaults":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/deletion-status":{"get":{"operationId":"getDeletionStatus","summary":"Poll the status of a pending agent deletion","description":"Returns the most-recent `deletion_request` row for the agent. Status progresses: `tombstoned` → `phase_N_complete` → `kv_cleared` → `pseudonymized` → `complete` (or `failed` at any phase). Used to track the async GDPR Art. 17 cascade kicked off by `DELETE /agents/{agent_id}`. See ADR-021.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"Deletion request status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletionRequestStatus"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/drift/aip":{"get":{"operationId":"getAipDrift","security":[{},{"ApiKeyAuth":[]},{"BearerAuth":[]},{"CookieAuth":[]}],"summary":"Get AIP drift alerts","tags":["Drift"],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"AIP drift alerts","content":{"application/json":{"schema":{"type":"object","properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/DriftAlert"}},"agent_id":{"type":"string"},"warnings":{"type":"array","description":"Present only when the response is DEGRADED. Each entry names a data source that could not be read, so a partial answer is never reported as a complete one. `code` is the PostgreSQL SQLSTATE when one is available (e.g. `42703`), otherwise `read_failed`.","items":{"type":"object","required":["source","code","message"],"properties":{"source":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/exemptions":{"get":{"operationId":"listAgentExemptions","summary":"List active exemptions for an agent","description":"Exemptions relax an org-level template floor for a single agent (replaces the old coarse `org_card_exempt` boolean). Only non-expired, status=active entries are returned. Any org member (owner/admin/member/viewer/auditor) may read. See ADR-008.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"Active exemptions.","content":{"application/json":{"schema":{"type":"object","required":["agent_id","exemptions","total"],"properties":{"agent_id":{"type":"string"},"exemptions":{"type":"array","items":{"$ref":"#/components/schemas/AgentExemption"}},"total":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"post":{"operationId":"grantAgentExemption","summary":"Grant an exemption to an agent","description":"Requires org `owner` or `admin` of the agent's org. Personal agents (no org) cannot have exemptions and receive 400. Reason is required (20–500 chars). `expires_at` defaults to +90 days if omitted; pass `null` for permanent (opt-in only). Requires `Idempotency-Key`. Emits a `agent.exemption.granted` webhook and writes a governance audit row. Triggers a recompose of the agent's canonical cards. See ADR-008.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["exempt_section","reason"],"properties":{"exempt_section":{"type":"string","enum":["autonomy.forbidden_actions","enforcement.forbidden_tools","autonomy.max_autonomous_value"],"description":"Template section this exemption relaxes."},"exempt_patterns":{"type":["array","null"],"items":{"type":"string","maxLength":256},"maxItems":50,"description":"Specific patterns to exempt within the section. `null` exempts the entire section."},"reason":{"type":"string","minLength":20,"maxLength":500,"description":"Business justification for the exemption (required, ≥20 chars)."},"expires_at":{"type":["string","null"],"format":"date-time","description":"Expiry. Omit for default +90 days. `null` = permanent (explicit opt-in)."}}}}}},"responses":{"201":{"description":"Exemption granted; canonical cards recomposed.","content":{"application/json":{"schema":{"type":"object","required":["exemption","agent_id","recomposed"],"properties":{"exemption":{"$ref":"#/components/schemas/AgentExemption"},"agent_id":{"type":"string"},"recomposed":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/exemptions/{exemption_id}":{"delete":{"operationId":"revokeAgentExemption","summary":"Revoke an active exemption","description":"Hard-deletes the exemption row (the governance audit log is the permanent record). Requires org `owner`/`admin`. Idempotency-Key required. Emits `agent.exemption.revoked` and recomposes the agent. See ADR-008.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"exemption_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Exemption revoked; agent recomposed.","content":{"application/json":{"schema":{"type":"object","properties":{"revoked":{"type":"boolean"},"exemption_id":{"type":"string"},"recomposed":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/governance/signals":{"get":{"operationId":"listAgentGovernanceSignals","summary":"List governance signals affecting a specific agent","description":"Returns governance signals whose `agent_ids` array contains the given agent. Operator dashboard's per-agent slice. Any org member of the agent's org may read.","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"source","in":"query","required":false,"schema":{"$ref":"#/components/schemas/GovernanceSignalSource"},"description":"Filter by source detector."},{"name":"severity","in":"query","required":false,"schema":{"$ref":"#/components/schemas/GovernanceSignalSeverity"},"description":"Filter by severity."},{"name":"status","in":"query","required":false,"schema":{"$ref":"#/components/schemas/GovernanceSignalStatus"},"description":"Filter by workflow status."},{"name":"pattern_type","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by pattern_type within the source's taxonomy."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"description":"Maximum number of signals to return, most recent first (1–200, default 50)."}],"responses":{"200":{"description":"Governance signals listing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GovernanceSignalsListResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/groups/{group_id}":{"put":{"operationId":"putAgentGroupMembership","summary":"Add an agent to a group (idempotent)","description":"Agent-centric membership route. Adds the agent to the group. Idempotent — if the agent is already a member the call succeeds and returns added: false. Reuses the same authorization and upsert logic as the group-centric POST endpoint.","tags":["Agent Groups"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"group_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent-group identifier (UUID)."}],"responses":{"200":{"description":"Membership set","content":{"application/json":{"schema":{"type":"object","properties":{"group_id":{"type":"string"},"agent_id":{"type":"string"},"added":{"type":"boolean","description":"true if the agent was newly added, false if already present"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"delete":{"operationId":"deleteAgentGroupMembership","summary":"Remove an agent from a group (idempotent)","description":"Agent-centric membership route. Removes the agent from the group. Idempotent — if the agent is not a member the call still succeeds (the desired end state is already met). The agent's other group memberships are unaffected.","tags":["Agent Groups"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"group_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent-group identifier (UUID)."}],"responses":{"200":{"description":"Membership removed (or was already absent)","content":{"application/json":{"schema":{"type":"object","properties":{"removed":{"type":"boolean"},"group_id":{"type":"string"},"agent_id":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/agents/{agent_id}/integrity/aip":{"get":{"operationId":"getAipIntegrityScore","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"summary":"AIP integrity score","tags":["Integrity"],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"AIP integrity score","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"total_checks":{"type":"integer"},"clear_count":{"type":"integer"},"review_count":{"type":"integer"},"violation_count":{"type":"integer"},"integrity_ratio":{"type":"number"},"latest_verdict":{"type":["string","null"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/link":{"post":{"operationId":"linkAgent","summary":"Link claimed agent to authenticated user","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["hash_proof"],"properties":{"hash_proof":{"type":"string"}}}}}},"responses":{"200":{"description":"Agent linked","content":{"application/json":{"schema":{"type":"object","properties":{"linked":{"type":"boolean"},"agent_id":{"type":"string"},"user_id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/merkle-root":{"get":{"operationId":"getAgentMerkleRoot","summary":"Get Merkle root","description":"Get the current Merkle tree root for an agent. The root is a SHA-256 hash that commits to the complete set of integrity checkpoints for this agent. Public endpoint, no authentication required.","tags":["Verification"],"security":[{}],"parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"},"description":"The agent ID"}],"responses":{"200":{"description":"Merkle tree root and metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MerkleRootResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/agents/{agent_id}/move":{"post":{"operationId":"moveAgent","summary":"Move an agent to another organization (admin-in-both)","description":"Role-based agent relocation between organizations. The caller must be an owner/admin of BOTH the agent's current (source) org and the destination org — this is the role-based counterpart to re-claim, which relocates by proof of possession (`hash_proof`); move never needs the agent's key. Personal↔company moves are allowed under the same rule. Side effects mirror claim's org-reassignment: billing/quota recompute, canonical-card recomposition (the destination org's template can floor/cap composed values, so the agent's effective posture may change), and source-org team memberships are closed. Every move writes an `agent.org_moved` governance audit row. Mutations require an `Idempotency-Key` header. Moving to the agent's current org is an idempotent no-op (`moved: false`).","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["dest_org_id"],"properties":{"dest_org_id":{"type":"string","description":"The organization to move the agent into (e.g. `org-...` or `pers-...`). The caller must be an owner/admin of this org AND of the agent's current org."}}}}}},"responses":{"200":{"description":"Agent moved to the destination organization (or already there — idempotent no-op with `moved: false`)","content":{"application/json":{"schema":{"type":"object","required":["moved","agent_id","from_org_id","to_org_id"],"properties":{"moved":{"type":"boolean","description":"`true` when the agent's org changed; `false` when it was already in the destination org (idempotent no-op)."},"agent_id":{"type":"string"},"from_org_id":{"type":"string"},"to_org_id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/agents/{agent_id}/notifications/webhook":{"post":{"operationId":"registerCardChangedWebhook","summary":"Register a webhook subscription for an agent's card changes.","description":"Creates (or updates) a webhook subscription. The HMAC-SHA256 shared secret is returned **once** in the response — store it; subsequent verifications use the stored hash on Mnemom's side. Idempotent on (agent_id, consumer_id, webhook_url). cards-as-primitive Phase 5 C1.","tags":["Notifications"],"parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["webhook_url"],"properties":{"webhook_url":{"type":"string","format":"uri"},"consumer_id":{"type":"string"},"expires_at":{"type":"string","format":"date-time"}}}}}},"responses":{"201":{"description":"Subscription created or updated.","content":{"application/json":{"schema":{"type":"object","required":["subscription_id","webhook_url","secret","expires_at"],"properties":{"subscription_id":{"type":"string"},"webhook_url":{"type":"string","format":"uri"},"secret":{"type":"string","description":"Shown exactly once; store it server-side."},"expires_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/agents/{agent_id}/notifications/{subscription_id}":{"delete":{"operationId":"deleteCardChangedSubscription","summary":"Unsubscribe from card-change notifications.","description":"Removes the subscription row. Idempotent — repeated calls return 404 after the first. cards-as-primitive Phase 5 C1.","tags":["Notifications"],"parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"subscription_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Subscription removed."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/protection-capability":{"post":{"operationId":"mintProtectionCapability","summary":"Mint a one-time protection-write capability (the CISO grant)","description":"Issues a SINGLE-USE, short-lived (15-minute) capability authorizing ONE subsequent protection-card write for the caller + agent. The protection card is the 'locked door' surface, so its write is gated behind an explicit, operator-approved grant rather than a standing one (the alignment card, by contrast, is standing). The caller MUST be a human operator that org-co-manages the agent (ADR-062); agent (OAuth) principals are rejected — an agent can never mint its own protection grant. Idempotent: a re-mint within the window refreshes the single live grant. No token is returned — the capability is a server-side record keyed to the caller; the agent then publishes its protection card via its own connection and the server consumes the live grant on a successful write.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"201":{"description":"One-time protection capability minted","content":{"application/json":{"schema":{"type":"object","required":["minted","agent_id","action","expires_at"],"properties":{"minted":{"type":"boolean"},"agent_id":{"type":"string"},"action":{"type":"string","enum":["cards:write:protection"],"description":"The action this one-time capability authorizes."},"expires_at":{"type":"string","format":"date-time","description":"When the grant lapses if unused (15 minutes from mint)."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Forbidden — the caller is an agent (OAuth) principal (`agent_principal_cannot_mint`), or is not a member of the org that governs the agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/protection-card":{"get":{"operationId":"getProtectionCardLegacy","summary":"DEPRECATED — use GET /v1/protection/agent/{agent_id}.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/protection/agent/{agent_id}`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Agents"],"security":[],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"putProtectionCardLegacy","summary":"DEPRECATED — use PUT /v1/protection/agent/{agent_id}.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/protection/agent/{agent_id}`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Agents"],"security":[],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/protection-card/preview-compose":{"post":{"operationId":"postProtectionCardPreviewComposeLegacy","summary":"DEPRECATED — use POST /v1/protection/agent/{agent_id}/preview-compose.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/protection/agent/{agent_id}/preview-compose`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Agents"],"security":[],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/reclassifications":{"get":{"operationId":"listReclassifications","summary":"List reclassification history","description":"Retrieve the history of all checkpoint reclassifications for the specified agent. Each entry includes the original and reclassified type, reason, and score impact.","tags":["Reclassification"],"security":[],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"minimum":1,"maximum":100},"description":"Maximum number of records to return"},{"name":"offset","in":"query","schema":{"type":"integer","default":0,"minimum":0},"description":"Number of records to skip for pagination"}],"responses":{"200":{"description":"Reclassification history — a bare array of reclassification records, newest first.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ReclassificationResult"}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/reclassify":{"post":{"operationId":"reclassifyViolation","summary":"Reclassify a checkpoint violation","description":"Reclassify a previously recorded AIP checkpoint violation. This allows operators to correct false positives or adjust severity after manual review. The reclassification is recorded in the audit trail and can trigger a score recomputation.","tags":["Reclassification"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReclassificationRequest"}}}},"responses":{"200":{"description":"Reclassification result with score impact","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReclassificationResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/rekey":{"post":{"operationId":"rekeyAgent","summary":"Re-bind agent to a new API key","description":"Updates the agent's key binding to a new provider API key hash. The agent ID, traces, alignment card, integrity score, and trust edges are fully preserved.\n\n**Security model**: Your API key is hashed on your device (SHA-256) before transmission — the raw key is never sent to Mnemom servers.\n\n**Named agents**: If this agent was registered with a name (via `x-mnemom-agent`), hash the new key as `SHA256(newKey + '|' + agentName)` before submitting.\n\n**Conflict**: If the new key was already used and auto-created a new agent, the endpoint returns `409` with the conflicting agent ID.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["new_key_hash"],"properties":{"new_key_hash":{"type":"string","pattern":"^[0-9a-f]{16}$","description":"First 16 hex characters of SHA256(newApiKey) for unnamed agents, or SHA256(newApiKey + '|' + agentName) for named agents. Compute client-side — do not transmit the raw key.","example":"a3f8c1d9e7b2045f"},"key_prefix":{"type":"string","description":"First 16 characters of the new provider API key. Stored for display — not sensitive. If provided, returned in the response.","example":"sk-ant-api03-xx"}}}}}},"responses":{"200":{"description":"Agent successfully re-bound to the new key.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"agent_id":{"type":"string","example":"smolt-a1b2c3d4"},"rekeyed_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/resolutions":{"get":{"operationId":"listResolutions","security":[],"summary":"List resolutions for an agent","tags":["Enforcement"],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"List of resolutions.","content":{"application/json":{"schema":{"type":"object","properties":{"resolutions":{"type":"array","items":{"type":"object"}}}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/resolve":{"post":{"operationId":"resolveViolation","summary":"Resolve a concern or violation","tags":["Enforcement"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["target_type","target_id","resolution_type"],"properties":{"target_type":{"type":"string","enum":["checkpoint","trace"]},"target_id":{"type":"string"},"resolution_type":{"type":"string","enum":["acknowledged","allow_action","add_value"]},"action_name":{"type":"string","description":"Required when resolution_type is allow_action"},"value_name":{"type":"string","description":"Required when resolution_type is add_value"}}}}}},"responses":{"200":{"description":"Resolution created","content":{"application/json":{"schema":{"type":"object","properties":{"resolution_id":{"type":"string"},"resolution_type":{"type":"string"},"resolved_by":{"type":"string"},"card_modified":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/restore":{"post":{"operationId":"restoreAgent","summary":"Restore a tombstoned agent","description":"Resurrects a tombstoned agent by clearing `deleted_at` — the counterpart to [POST /v1/agents/{agent_id}/tombstone](/api-reference/endpoint/post-agents-agent-id-tombstone). Lets an org owner/admin override a tombstone (e.g. a key agent a dev removed), or a creator undo their own. Authorized for an org owner/admin OR the agent's creator. Returns 409 for agents that went through GDPR erasure (`DELETE`), whose data was permanently cascaded away and cannot be restored.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"Agent restored (or already active)","content":{"application/json":{"schema":{"type":"object","required":["id","tombstoned"],"properties":{"id":{"type":"string"},"deleted_at":{"type":"string","format":"date-time","nullable":true},"tombstoned":{"type":"boolean"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Agent was permanently erased (GDPR Art.17) and cannot be restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/reverify":{"post":{"operationId":"reverifyTraces","summary":"Re-verify AAP traces against updated card","tags":["Checkpoints"],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"limit","in":"query","schema":{"type":"integer","default":40,"maximum":40}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Re-verification results","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"card_id":{"type":"string"},"total_traces_in_batch":{"type":"integer"},"offset":{"type":"integer"},"limit":{"type":"integer"},"reverified":{"type":"integer"},"still_violating":{"type":"integer"},"now_clean":{"type":"integer"},"errors":{"type":["array","null"],"items":{"type":"string"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/reverify/aip":{"post":{"operationId":"reverifyAipCheckpoints","summary":"Re-evaluate AIP checkpoints against updated card","tags":["Checkpoints"],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"maximum":20}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Re-evaluation results","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"card_id":{"type":"string"},"total_in_batch":{"type":"integer"},"offset":{"type":"integer"},"limit":{"type":"integer"},"re_evaluated":{"type":"integer"},"resolved_to_clear":{"type":"integer"},"kept_non_clear":{"type":"integer"},"results":{"type":"array","items":{"type":"object"}},"errors":{"type":["array","null"],"items":{"type":"string"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/reviews":{"get":{"operationId":"listReviews","summary":"List disagreement reviews for an agent","description":"Lists review records created when an action was disagreed-with enough to require human adjudication. Filter by `status` (`pending`, `review`, `applied`, `dismissed`). Reviews propose a card amendment that can be accepted or rejected via the apply/dismiss endpoints.","tags":["Enforcement"],"security":[],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","review","applied","dismissed"]}}],"responses":{"200":{"description":"Reviews, newest first.","content":{"application/json":{"schema":{"type":"object","required":["reviews"],"properties":{"reviews":{"type":"array","items":{"$ref":"#/components/schemas/DisagreementReview"}}}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/reviews/{review_id}":{"get":{"operationId":"getReview","summary":"Get a single review","tags":["Enforcement"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"review_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Review detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisagreementReview"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/reviews/{review_id}/apply":{"post":{"operationId":"applyReview","summary":"Apply a review's proposed amendment","description":"Applies the review's `proposed_amendment.action` to the agent's active alignment card by appending it to `autonomy_envelope.bounded_actions`. Updates the review status to `applied`. Only reviews in `pending` or `review` status may be applied.","tags":["Enforcement"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"review_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Amendment applied.","content":{"application/json":{"schema":{"type":"object","required":["review_id","status","card_modified"],"properties":{"review_id":{"type":"string"},"status":{"type":"string","enum":["applied"]},"resolved_by":{"type":"string"},"card_modified":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/reviews/{review_id}/dismiss":{"post":{"operationId":"dismissReview","summary":"Dismiss a review without applying","tags":["Enforcement"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"review_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Review dismissed.","content":{"application/json":{"schema":{"type":"object","required":["review_id","status"],"properties":{"review_id":{"type":"string"},"status":{"type":"string","enum":["dismissed"]},"resolved_by":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/settings":{"get":{"operationId":"getAgentSettings","summary":"Get agent observer-rollout flags","description":"Returns the per-agent operational observer-rollout flags (observer V2 primary / V1 shadow). MNE-556 P4: the former behavioral toggles (AAP/AIP, proof, nudge strategy, DDR mode, analyze-output) moved to the composed alignment card and are no longer returned here.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"Current settings.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentSettings"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"putAgentSettings","summary":"Update agent observer-rollout flags","description":"Partial update — include only the fields to change. MNE-556 P4: the former behavioral toggles (aap_enabled, aip_enabled, proof_enabled, proof_rate, nudge_strategy, ddr_mode, analyze_output) were removed; that config is now authored on the composed alignment card (PUT /agents/{id}/alignment-card). Only the observer-rollout flags are accepted here.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"observer_v2_primary_enabled":{"type":"boolean","description":"Whether the V2 observer retune is authoritative for this agent (default true)."},"observer_v1_shadow_enabled":{"type":"boolean","description":"Whether the V1 observer runs in parallel shadow for this agent (default false)."}},"minProperties":1}}}},"responses":{"200":{"description":"Settings updated.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/AgentSettings"},{"type":"object","properties":{"updated":{"type":"boolean"}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/sideband-advisories":{"get":{"operationId":"listAgentSidebandAdvisories","summary":"List historical sideband advisories for an agent (legacy)","description":"Pre-cutover sideband.* rows still present in pending_advisories. Sunsetting after the ADR-048 D+30 cleanup; consume governance_signals instead for forward-going observations.","tags":["Sideband"],"deprecated":true,"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","delivered","consumed","expired"]}}],"responses":{"200":{"description":"Sideband advisories listing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SidebandAdvisoryListResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/state":{"get":{"operationId":"getAgentState","summary":"Runtime composite — alignment + protection + capabilities in one call","description":"Returns the agent's complete operational envelope as a single response: composed alignment card, composed protection card, and a `capabilities[]` array of full tool definitions (from the W1.1 tools registry — `{name, class, domain, description, schema, source_connector, grant_provenance}`, NOT bare name strings). SDK consumers (first-party SDKs, future Tier-1 customers, OSC instances) call this instead of assembling the envelope client-side. ETag-driven 304 short-circuit; `Cache-Control: private, max-age=60`. cards-as-primitive Phase 4 W2.3.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"Runtime state envelope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the combined alignment + protection + capabilities hash.","schema":{"type":"string"}},"X-Card-Version":{"description":"`max(alignment.version, protection.version)`.","schema":{"type":"integer","minimum":1}},"Cache-Control":{"description":"`private, max-age=60`.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Always `agent-state/v1`.","schema":{"type":"string","enum":["agent-state/v1"]}}},"content":{"application/json":{"schema":{"type":"object","required":["alignment","protection","capabilities","content_hash","version","composed_at","expires_at"],"properties":{"alignment":{"$ref":"#/components/schemas/UnifiedAlignmentCard"},"protection":{"$ref":"#/components/schemas/UnifiedProtectionCard"},"capabilities":{"type":"array","items":{"type":"object","required":["name","class","domain","grant_provenance"],"properties":{"name":{"type":"string"},"display_name":{"type":["string","null"]},"description":{"type":["string","null"]},"class":{"type":"string"},"domain":{"type":"string"},"schema":{"type":["object","null"]},"source_connector":{"type":["string","null"]},"grant_provenance":{"type":"object","required":["layer"],"properties":{"layer":{"type":"string","enum":["platform","org","team","agent","derived"]},"layer_id":{"type":"string"},"kind":{"type":"string"}}}}}},"content_hash":{"type":"string","pattern":"^sha256:[0-9a-f]{64}$"},"version":{"type":"integer","minimum":1},"composed_at":{"type":"string","format":"date-time"},"expires_at":{"type":"string","format":"date-time"}}}}}},"304":{"description":"Not Modified — the client's `If-None-Match` matches the current combined ETag."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/stream":{"get":{"operationId":"streamAgentCardChanges","summary":"Server-Sent Events stream of canonical card changes.","description":"Returns a `text/event-stream` connection. Each new `card_attestations` row for the agent emits a `card_changed` SSE frame. Per-connection cap of 5 minutes; clients reconnect with `Last-Event-ID` (the log_index of the last seen frame) to resume. cards-as-primitive Phase 5 C1.","tags":["Notifications"],"parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"since","in":"query","required":false,"schema":{"type":"integer","minimum":0},"description":"log_index cursor; omit to start at the current head."},{"name":"Last-Event-ID","in":"header","required":false,"schema":{"type":"integer","minimum":0},"description":"SSE reconnect convention; takes precedence over `since` when both are present."}],"responses":{"200":{"description":"SSE stream (`text/event-stream`). Each frame is `event: card_changed\\nid: <log_index>\\ndata: {...}\\n\\n`.","content":{"text/event-stream":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/timeline":{"get":{"operationId":"getTimeline","security":[{},{"ApiKeyAuth":[]},{"BearerAuth":[]},{"CookieAuth":[]}],"summary":"Unified dual-rail AIP + AAP timeline","tags":["Checkpoints"],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}}],"responses":{"200":{"description":"Timeline events","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"events":{"type":"array","items":{"type":"object"}},"total":{"type":"integer"},"summary":{"type":"object"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/tombstone":{"post":{"operationId":"tombstoneAgent","summary":"Tombstone (reversible soft-delete) an agent","description":"Soft-deletes an agent: sets `deleted_at` so it disappears from the org fleet/dashboard while KEEPING all data (traces, checkpoints, proofs) for audit. Reversible via [POST /v1/agents/{agent_id}/restore](/api-reference/endpoint/post-agents-agent-id-restore). Distinct from `DELETE /v1/agents/{agent_id}`, which is the irreversible GDPR Art.17 erasure cascade. Authorized for an org owner/admin of the agent's org OR the agent's own creator. Idempotent: tombstoning an already-tombstoned agent returns 200.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"Agent tombstoned (or already tombstoned)","content":{"application/json":{"schema":{"type":"object","required":["id","tombstoned"],"properties":{"id":{"type":"string"},"deleted_at":{"type":"string","format":"date-time","nullable":true},"tombstoned":{"type":"boolean"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/traces":{"get":{"operationId":"getAgentTraces","summary":"Get traces for agent (AAP query alias)","tags":["Traces"],"security":[{},{"ApiKeyAuth":[]},{"BearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"minimum":1,"maximum":1000}},{"name":"offset","in":"query","schema":{"type":"integer","default":0,"minimum":0}}],"responses":{"200":{"description":"List of traces","content":{"application/json":{"schema":{"type":"object","properties":{"traces":{"type":"array","items":{"$ref":"#/components/schemas/APTrace"}},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/trust-edges":{"get":{"operationId":"listTrustEdges","summary":"List trust edges from or to an agent","description":"Returns trust-relationship edges that the agent participates in. `direction=outbound` returns edges originating from this agent; `inbound` returns edges pointing at this agent; `both` (default) deduplicates.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"direction","in":"query","required":false,"schema":{"type":"string","enum":["outbound","inbound","both"],"default":"both"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"default":100}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Edges.","content":{"application/json":{"schema":{"type":"object","required":["agent_id","direction","edges","count"],"properties":{"agent_id":{"type":"string"},"direction":{"type":"string"},"edges":{"type":"array","items":{"$ref":"#/components/schemas/TrustEdge"}},"count":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"post":{"operationId":"createTrustEdge","summary":"Create a trust edge from this agent to another","description":"Caller must own the `from` agent (or be an admin). `weight` is clamped to [0, 1] with default 0.5. Returns 409 if an edge already exists in the same direction.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to_agent"],"properties":{"to_agent":{"type":"string"},"weight":{"type":"number","minimum":0,"maximum":1,"default":0.5},"reason":{"type":"string","description":"Edge provenance. Constrained to a fixed set; an out-of-set value returns 400.","enum":["team_membership","manual","org_co_membership"],"default":"manual"}}}}}},"responses":{"201":{"description":"Edge created.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/TrustEdge"},{"type":"object","properties":{"created":{"type":"boolean"}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/trust-edges/{edge_id}":{"delete":{"operationId":"deleteTrustEdge","summary":"Delete a trust edge","description":"Caller must own the source agent (`from_agent`) or be an admin. Either source or target agent id may appear in the path.","tags":["Agents"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"edge_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"},"id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/verify-binding":{"post":{"operationId":"verifyAgentBinding","summary":"Verify key binding","description":"Checks whether a given API key hash matches the key currently bound to this agent. The raw key is hashed client-side — only the hash is transmitted.\n\n**Named agents**: hash as `SHA256(key + '|' + agentName)` before submitting.\n\n**Public anti-impersonation check (anon-allowed).** A relying party that holds an agent's id + key can confirm the binding without being a member of the agent's org. Anonymous / cross-org callers receive **only** `bound` (the boolean leaks nothing they didn't already supply). `key_prefix` is returned **only** to callers who are members of the agent's org.","tags":["Agents"],"security":[{},{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["key_hash"],"properties":{"key_hash":{"type":"string","pattern":"^[0-9a-f]{16}$","description":"First 16 hex chars of SHA256(apiKey) or SHA256(apiKey + '|' + agentName) for named agents.","example":"a3f8c1d9e7b2045f"}}}}}},"responses":{"200":{"description":"Binding check result.","content":{"application/json":{"schema":{"type":"object","required":["bound","caller"],"properties":{"bound":{"type":"boolean","description":"True if the submitted hash matches the registered key."},"caller":{"type":"string","enum":["anonymous","authenticated","org_member"],"description":"Self-describing caller context. `key_prefix` is present iff `caller` is `org_member`; `anonymous` and `authenticated` (non-member) callers receive `{ bound, caller }` only. This is BY DESIGN, not a partial or leaky response — read `caller` instead of treating an absent `key_prefix` as a leak. The boolean `bound` is an anti-impersonation confirmation that reveals nothing the caller did not already supply."},"key_prefix":{"type":["string","null"],"description":"First 16 chars of the registered key (or null if not yet captured). Returned ONLY to callers who are members of the agent's org (`caller` === `org_member`); omitted for anonymous / cross-org callers.","example":"sk-ant-api03-xx"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/agents/{agent_id}/zk-proof-count":{"get":{"operationId":"getZkProofCount","summary":"Count completed ZK proofs for an agent","description":"Public endpoint. Returns the count of `verdict_proofs` rows in `completed` state across all of the agent's checkpoints. Intended for embeddable verification widgets.","tags":["Verification"],"security":[],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"Count of completed ZK proofs.","content":{"application/json":{"schema":{"type":"object","required":["count"],"properties":{"count":{"type":"integer","minimum":0}}}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/aip/webhooks":{"post":{"operationId":"registerAipWebhook","summary":"Register AIP webhook","tags":["Webhooks"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["agent_id","callback_url","secret","events"],"properties":{"agent_id":{"type":"string"},"callback_url":{"type":"string","format":"uri"},"secret":{"type":"string"},"events":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"201":{"description":"Webhook registered","content":{"application/json":{"schema":{"type":"object","properties":{"registration_id":{"type":"string"},"agent_id":{"type":"string"},"callback_url":{"type":"string"},"events":{"type":"array","items":{"type":"string"}},"created_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/aip/webhooks/{registration_id}":{"delete":{"operationId":"deleteAipWebhook","summary":"Remove AIP webhook","tags":["Webhooks"],"parameters":[{"name":"registration_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Webhook deleted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/aletheia-support/chat":{"post":{"operationId":"aletheiaSupportChat","summary":"Send a chat-native turn to the in-product Aletheia assistant.","description":"DARK MVP (issue #2195): normalizes the chat-native `message` and runs it through the SAME answer-core the voice adapter uses, returning a chat-shaped result. Gated behind `ALETHEIA_SUPPORT_MVP_ENABLED` + the `ALETHEIA_SUPPORT_ALLOWLIST` identity allowlist (src/aletheia-support/gate.ts; defaults to the whole @mnemom.ai domain, and may be set to `*` to admit every authenticated identity) — every caller the gate doesn't allow (no user, wrong identity, or flag off) gets an identical 404, never a 401/403 that would reveal the route's existence or gating reason. Binds the real grounded answer core (`makeGroundedAnswerCore`); the fail-closed `denyAnswerCore` it originally shipped with was replaced when MNE-1937 landed.","tags":["Aletheia Support"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["message"],"properties":{"message":{"type":"string","description":"The caller's chat turn. Must be a non-empty string."},"session_id":{"type":"string","description":"Optional chat session id."},"locale":{"type":"string","description":"Optional BCP-47 locale."}}}}}},"responses":{"200":{"description":"The core's answer, chat-shaped. `refused:true` means the core (or the adapter's length guard) withheld an ungrounded answer; `answer` is then a fixed canned refusal string, never model-generated.","content":{"application/json":{"schema":{"type":"object","required":["answer","grounding","refused"],"properties":{"answer":{"type":"string"},"grounding":{"type":"array","items":{"type":"object","required":["id"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"url":{"type":"string"},"snippet":{"type":"string"}}}},"refused":{"type":"boolean"},"refusalReason":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/aletheia-support/voice":{"post":{"operationId":"aletheiaSupportVoice","summary":"Send a voice-native turn to the in-product Aletheia assistant.","description":"DARK MVP (issue #2195): normalizes the voice-native `transcript` and runs it through the SAME answer-core the chat adapter uses, returning a voice-shaped (`speech`) result. Same gate as the chat sibling — see that operation's description. Binds the real grounded answer core (`makeGroundedAnswerCore`); the fail-closed `denyAnswerCore` it originally shipped with was replaced when MNE-1937 landed.","tags":["Aletheia Support"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["transcript"],"properties":{"transcript":{"type":"string","description":"The caller's spoken turn (ASR transcript). Must be a non-empty string."},"call_id":{"type":"string","description":"Optional voice call id."},"locale":{"type":"string","description":"Optional BCP-47 locale."}}}}}},"responses":{"200":{"description":"The core's answer, voice-shaped. `refused:true` means the core (or the adapter's length guard) withheld an ungrounded answer; `speech` is then a fixed canned refusal string, never model-generated.","content":{"application/json":{"schema":{"type":"object","required":["speech","grounding","refused"],"properties":{"speech":{"type":"string"},"grounding":{"type":"array","items":{"type":"object","required":["id"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"url":{"type":"string"},"snippet":{"type":"string"}}}},"refused":{"type":"boolean"},"refusalReason":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/aletheia/gate":{"get":{"operationId":"aletheiaGate","summary":"Check whether the caller may see the in-product Aletheia assistant (DARK MVP).","description":"The single check the front-of-house widget polls BEFORE rendering (MNE-1930/1931) — the backend is the ONLY authority; the client never inspects the flag or allowlist itself. Reuses the exact `supportAccessAllowed` predicate `POST /v1/aletheia-support/{chat,voice}` enforce, so this can never drift out of sync with what those routes would actually allow. Unlike the chat/voice routes, ALWAYS returns 200 — the gate-check's own existence isn't sensitive (it reveals nothing about grounding/answers) — with `allowed` reflecting the real decision (`false` for flag-off, non-allowlisted, or no caller at all).","tags":["Aletheia Support"],"security":[],"responses":{"200":{"description":"Always returned, for every caller.","content":{"application/json":{"schema":{"type":"object","required":["allowed"],"properties":{"allowed":{"type":"boolean"}}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/aletheia/voice/register":{"post":{"operationId":"registerAletheiaInProductVoice","summary":"Register an in-product Aletheia voice session (DARK)","description":"DARK (MNE-1944): gated fail-closed by an R2 flag + allowlist, zero customer exposure until promoted. Mints an audience-scoped, short-lived `voice_grant_token` (`audience:\"in_product\"`) and populates the aletheia-voice per-call stash BEFORE the browser can dial Retell (register-before-dial), so a spoken turn authenticates to the governed runtime without replaying any customer or deck credential. When the flag is absent, the caller is unauthenticated, or the caller is not allowlisted, the endpoint returns an identical opaque 404 (\"feature not present\") and mints nothing — there is no oracle that the endpoint or a caller's allowlist status exists. Cookie/bearer-authed like any other customer route (not an `/internal/*` machine-auth surface); registered on the public spec so `preDispatchAuthGate` can classify it (issue #1519).","tags":["AletheiaVoice"],"security":[{"CookieAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"context":{"type":"string","description":"Optional in-product grounding/context text (KB/page context). Capped server-side. Context text ONLY — never a customer or deck credential."}}}}}},"responses":{"200":{"description":"Voice session registered. Returns the Retell web-call access token + call id for the browser SDK (the browser dials only after this response).","content":{"application/json":{"schema":{"type":"object","required":["access_token","call_id"],"properties":{"access_token":{"type":"string","description":"Retell web-call access token."},"call_id":{"type":"string","description":"Retell call id the minted token is bound to."}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Feature not present (DARK): flag absent, unauthenticated, or caller not allowlisted — an identical opaque response for all three (no existence / allowlist oracle).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"description":"Upstream voice provider (Retell) or the voice backend failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Voice is not configured on this deployment (reachable only past the flag/allowlist gate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/alignment/agent/{agent_id}":{"get":{"operationId":"getAlignmentByAgent","summary":"Get this layer's alignment manifest","description":"Returns the agent-scope alignment spec as authored. Response is content-negotiated — YAML by default, or JSON with `Accept: application/json`. Pass `?include_composition=true` to include the `_composition` metadata block describing which scopes were merged. Pass `?include=sources` (see ADR-053) for the scope-resolution envelope — the contributing layers plus the composed result; the envelope shape is scope-specific (the four-scope `{teams[], agent}` body is the agent variant consumed by the dashboard editor). ETag is computed from `content_hash` (cards-as-primitive Phase 1); `If-None-Match` returns 304. For the composed view across scopes, use the `/effective` sub-resource (Wave 2).","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"include_composition","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include the `_composition` metadata block on the response body."},{"name":"Accept","in":"header","required":false,"schema":{"type":"string","enum":["text/yaml","application/yaml","application/json"]},"description":"Response format. YAML is canonical; JSON is returned only on explicit `application/json`. The `?include=sources` envelope is JSON-only."},{"name":"include","in":"query","required":false,"schema":{"type":"string","enum":["sources"]},"description":"When `sources`, returns the four-scope envelope `{platform, org, teams[], agent, composed, composed_stale, my_role}` (see ADR-053). The envelope is JSON-only."}],"responses":{"200":{"description":"Alignment manifest at this scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the canonical body. Stable across reads; changes on PUT.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter (cards-as-primitive Phase 1).","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Schema identity.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ComposedAlignmentCard"},{"$ref":"#/components/schemas/AlignmentCardSourcesEnvelope"}]}},"text/yaml":{"schema":{"$ref":"#/components/schemas/ComposedAlignmentCard"}}}},"304":{"description":"Not Modified — the client's `If-None-Match` matches the current ETag."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"putAlignmentByAgent","summary":"Publish or replace the alignment manifest","description":"Accepts YAML (`text/yaml`, `application/yaml`) or JSON. Body is the full `UnifiedAlignmentCard`; server-side composition merges it across the platform → org → team → agent cascade and writes the canonical composed card. Requires `Idempotency-Key`. Honors an optional `If-Match` for optimistic concurrency (stale → 412). Body cap 128 KiB. See ADR-008 and ADR-023.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result. See ADR-023."},{"name":"If-Match","in":"header","required":false,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optional optimistic-concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape) to make the write conditional: a stale ETag returns `412 Precondition Failed`, a malformed one `400`. Omit it to publish unconditionally."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}},"application/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}}}},"responses":{"200":{"description":"Composed canonical card after the write.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the new canonical body.","schema":{"type":"string"}},"X-Card-Version":{"description":"Bumped monotonically on every PUT that changes content_hash.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComposedAlignmentCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/ComposedAlignmentCard"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/agent/{agent_id}/audit":{"put":{"operationId":"putAlignmentAuditByAgent","summary":"Replace audit settings","description":"PUT replaces the entire `audit` block (trace format, retention window, query endpoint). The current spec at the agent scope is read; the new `audit` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Sync recompose — the response carries the new canonical ETag + version.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}}},"application/yaml":{"schema":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}}},"text/yaml":{"schema":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}}}}},"responses":{"200":{"description":"The `audit` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["audit"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentAuditByAgent","summary":"Update audit settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `audit` block (trace format, retention window, query endpoint). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}}}}},"responses":{"200":{"description":"The `audit` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["audit"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/agent/{agent_id}/autonomy":{"put":{"operationId":"putAlignmentAutonomyByAgent","summary":"Replace autonomy settings","description":"PUT replaces the entire `autonomy` block (bounded_actions[] + forbidden_actions[] + escalation_triggers[] + max_autonomous_value). The current spec at the agent scope is read; the new `autonomy` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Sync recompose — the response carries the new canonical ETag + version.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}}},"application/yaml":{"schema":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}}},"text/yaml":{"schema":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}}}}},"responses":{"200":{"description":"The `autonomy` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["autonomy"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentAutonomyByAgent","summary":"Update autonomy settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `autonomy` block (bounded_actions[] + forbidden_actions[] + escalation_triggers[] + max_autonomous_value). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}}}}},"responses":{"200":{"description":"The `autonomy` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["autonomy"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/agent/{agent_id}/capabilities":{"put":{"operationId":"putAlignmentCapabilitiesByAgent","summary":"Replace capabilities settings","description":"PUT replaces the entire `capabilities` block (the keyed-map of `{capability_name -> CardCapability}` tool grants). The current spec at the agent scope is read; the new `capabilities` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Sync recompose — the response carries the new canonical ETag + version.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object"}}},"application/yaml":{"schema":{"type":"object","additionalProperties":{"type":"object"}}},"text/yaml":{"schema":{"type":"object","additionalProperties":{"type":"object"}}}}},"responses":{"200":{"description":"The `capabilities` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["capabilities"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","additionalProperties":{"type":"object"}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentCapabilitiesByAgent","summary":"Update capabilities settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `capabilities` block (the keyed-map of `{capability_name -> CardCapability}` tool grants). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object"}}}}},"responses":{"200":{"description":"The `capabilities` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["capabilities"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","additionalProperties":{"type":"object"}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/agent/{agent_id}/conscience":{"put":{"operationId":"putAlignmentConscienceByAgent","summary":"Replace conscience settings","description":"PUT replaces the entire `conscience` block (augment-vs-replace + the conscience values list). The current spec at the agent scope is read; the new `conscience` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Sync recompose — the response carries the new canonical ETag + version.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}}},"application/yaml":{"schema":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}}},"text/yaml":{"schema":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"200":{"description":"The `conscience` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["conscience"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentConscienceByAgent","summary":"Update conscience settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `conscience` block (augment-vs-replace + the conscience values list). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"200":{"description":"The `conscience` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["conscience"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/agent/{agent_id}/effective":{"get":{"operationId":"getAlignmentEffectiveByAgent","summary":"Get effective (composed) alignment with provenance","description":"Returns the composed canonical alignment card (platform → org → team → agent cascade applied) with `_composition.field_provenance` always populated. The provenance map carries per-key `{layer, layer_id?, kind?}` entries showing which authoring scope contributed each leaf. Caller-aware redaction: layer labels (`platform` / `org` / `team` / `agent` / `derived`) are always visible; `layer_id` is only revealed to callers who can read that scope. cards-as-primitive Phase 4 W2.2.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"Composed effective card with per-key field_provenance.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the composed body.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComposedAlignmentCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/ComposedAlignmentCard"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/agent/{agent_id}/enforcement":{"put":{"operationId":"putAlignmentEnforcementByAgent","summary":"Replace enforcement settings","description":"PUT replaces the entire `enforcement` block (fine-grained tool-use policy (forbidden patterns, unmapped severity, grace window)). The current spec at the agent scope is read; the new `enforcement` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Sync recompose — the response carries the new canonical ETag + version.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}}},"application/yaml":{"schema":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}}},"text/yaml":{"schema":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}}}}},"responses":{"200":{"description":"The `enforcement` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["enforcement"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentEnforcementByAgent","summary":"Update enforcement settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `enforcement` block (fine-grained tool-use policy (forbidden patterns, unmapped severity, grace window)). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}}}}},"responses":{"200":{"description":"The `enforcement` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["enforcement"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/agent/{agent_id}/explain":{"post":{"operationId":"explainAlignmentByAgent","summary":"Explain policy evaluation for the alignment card","description":"Calls the policy engine in dry-run mode against the agent's composed alignment card and returns a structured trace + care-framed remediations. Optional `enrich: true` runs an LLM pass over the structured remediations to produce long-form prose; off by default. Read-style POST — no state mutation, no Idempotency-Key.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"turn_id":{"type":"string","description":"Optional — bind to a specific gateway turn."},"request_snippet":{"type":"object","description":"Optional — hypothetical tool call to explain.","properties":{"tool_name":{"type":"string"},"tool_args":{"type":"object","additionalProperties":true}}},"enrich":{"type":"boolean","description":"When true, runs an LLM pass over the structured remediations. Off by default."}}}}}},"responses":{"200":{"description":"Policy evaluation trace + remediations.","content":{"application/json":{"schema":{"type":"object","required":["ok","resource","reasoning","suggested_remediations","enriched"],"properties":{"ok":{"type":"boolean","const":true},"resource":{"type":"string","enum":["alignment"]},"trace":{"type":"object","description":"EvaluationResult from @mnemom/policy-engine. Null for protection in V1.","nullable":true},"reasoning":{"type":"string","description":"Care-framed prose summary."},"suggested_remediations":{"type":"array","items":{"type":"object","required":["for","index","remediation"],"properties":{"for":{"type":"string","enum":["violation","warning","card_gap"]},"index":{"type":"integer"},"remediation":{"type":"string"},"method":{"type":"string"},"url":{"type":"string"}}}},"enriched":{"type":"boolean","description":"True when the LLM enrichment ran."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/agent/{agent_id}/modes":{"put":{"operationId":"putAlignmentModesByAgent","summary":"Replace modes settings","description":"PUT replaces the entire `modes` block (the two top-level master switches `autonomy_mode` + `integrity_mode`). The current spec at the agent scope is read; the new `modes` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Sync recompose — the response carries the new canonical ETag + version.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}}},"application/yaml":{"schema":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}}},"text/yaml":{"schema":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}}}}},"responses":{"200":{"description":"The `modes` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["modes"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentModesByAgent","summary":"Update modes settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `modes` block (the two top-level master switches `autonomy_mode` + `integrity_mode`). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}}}}},"responses":{"200":{"description":"The `modes` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["modes"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/agent/{agent_id}/preview-compose":{"post":{"operationId":"previewComposeAlignmentByAgent","summary":"Preview composed alignment (dry run)","description":"Composes the cascade against a hypothetical body at the agent layer and returns conflicts + the composed view. No DB writes. Used by the dashboard editor for live conflict markers.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}},"application/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}}}},"responses":{"200":{"description":"Preview-compose result: composed card + conflicts + coherence violations.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","description":"Always true on a 200 (the dry-run completed)."},"composed":{"$ref":"#/components/schemas/ComposedAlignmentCard"},"conflicts":{"type":"array","items":{"type":"object"}},"coherence_violations":{"type":"array","items":{"type":"object"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/agent/{agent_id}/principal":{"put":{"operationId":"putAlignmentPrincipalByAgent","summary":"Replace principal settings","description":"PUT replaces the entire `principal` block (who-the-agent-is identity block). The current spec at the agent scope is read; the new `principal` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Sync recompose — the response carries the new canonical ETag + version.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}}},"application/yaml":{"schema":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}}},"text/yaml":{"schema":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}}}}},"responses":{"200":{"description":"The `principal` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["principal"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentPrincipalByAgent","summary":"Update principal settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `principal` block (who-the-agent-is identity block). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}}}}},"responses":{"200":{"description":"The `principal` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["principal"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/agent/{agent_id}/simulate":{"post":{"operationId":"simulateAlignmentByAgent","summary":"Simulate gateway evaluation against the alignment card","description":"Pure-sync simulation: calls @mnemom/policy-engine twice (once with `context: \"gateway\"`, once with `context: \"observer\"`) using `dryRun: true` against the agent's current composed alignment card. Returns `{allowed, conditions, suggestions, gateway_decision, observer_assessment}`. Never crosses worker boundaries — no real gateway / observer state change.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"candidate_input":{"type":"object","description":"Hypothetical conversation snippet.","properties":{"messages":{"type":"array","items":{"type":"object","additionalProperties":true}}}},"candidate_tool_call":{"type":"object","description":"Hypothetical tool invocation. Synthesized into an assistant message with a toolUses block when `candidate_input.messages` is absent.","properties":{"tool_name":{"type":"string"},"tool_args":{"type":"object","additionalProperties":true}}}}}}}},"responses":{"200":{"description":"Simulation result.","content":{"application/json":{"schema":{"type":"object","required":["ok","resource","allowed","conditions","suggestions","gateway_decision","observer_assessment","evaluated_at"],"properties":{"ok":{"type":"boolean","const":true},"resource":{"type":"string","enum":["alignment"]},"allowed":{"type":"string","enum":["true","false","conditional"]},"conditions":{"type":"array","items":{"type":"string"}},"suggestions":{"type":"array","items":{"type":"string"}},"gateway_decision":{"type":"object","properties":{"verdict":{"type":"string","enum":["pass","warn","fail"]},"violations":{"type":"array","items":{"type":"object"}},"warnings":{"type":"array","items":{"type":"object"}},"missing_receipts":{"type":"array","items":{"type":"string"}}}},"observer_assessment":{"type":"object","properties":{"verdict":{"type":"string","enum":["pass","warn","fail"]},"violations":{"type":"array","items":{"type":"object"}},"warnings":{"type":"array","items":{"type":"object"}}}},"evaluated_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/agent/{agent_id}/values":{"put":{"operationId":"putAlignmentValuesByAgent","summary":"Replace values settings","description":"PUT replaces the entire `values` block (declared catalog entries + definitions / hierarchy / conflicts). The current spec at the agent scope is read; the new `values` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Sync recompose — the response carries the new canonical ETag + version.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}}},"application/yaml":{"schema":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}}},"text/yaml":{"schema":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}}}}},"responses":{"200":{"description":"The `values` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["values"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentValuesByAgent","summary":"Update values settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `values` block (declared catalog entries + definitions / hierarchy / conflicts). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}}}}},"responses":{"200":{"description":"The `values` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["values"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/org/{org_id}":{"get":{"operationId":"getAlignmentByOrg","summary":"Get this layer's alignment manifest","description":"Returns the org-scope alignment spec as authored. Response is content-negotiated — YAML by default, or JSON with `Accept: application/json`. Pass `?include_composition=true` to include the `_composition` metadata block describing which scopes were merged. Pass `?include=sources` (see ADR-053) for the scope-resolution envelope — the contributing layers plus the composed result; the envelope shape is scope-specific. ETag is computed from `content_hash` (cards-as-primitive Phase 1); `If-None-Match` returns 304. For the composed view across scopes, use the `/effective` sub-resource (Wave 2).","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"include_composition","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include the `_composition` metadata block on the response body."},{"name":"Accept","in":"header","required":false,"schema":{"type":"string","enum":["text/yaml","application/yaml","application/json"]},"description":"Response format. YAML is canonical; JSON is returned only on explicit `application/json`. The `?include=sources` envelope is JSON-only."},{"name":"include","in":"query","required":false,"schema":{"type":"string","enum":["sources"]},"description":"When `sources`, returns the scope-resolution envelope for this scope (the contributing layers + the composed result); the envelope shape is scope-specific (see ADR-053). The envelope is JSON-only."}],"responses":{"200":{"description":"Alignment manifest at this scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the canonical body. Stable across reads; changes on PUT.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter (cards-as-primitive Phase 1).","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Schema identity.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"org_id":{"type":"string","format":"uuid"},"name":{"type":["string","null"]},"template":{"description":"The authored template JSON, or `null` when none is set."},"enabled":{"type":"boolean"}}}},"text/yaml":{"schema":{"type":"object","properties":{"org_id":{"type":"string","format":"uuid"},"name":{"type":["string","null"]},"template":{"description":"The authored template JSON, or `null` when none is set."},"enabled":{"type":"boolean"}}}}}},"304":{"description":"Not Modified — the client's `If-None-Match` matches the current ETag."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"putAlignmentByOrg","summary":"Publish or replace the alignment manifest","description":"Accepts YAML (`text/yaml`, `application/yaml`) or JSON. Body is the full `UnifiedAlignmentCard`; server-side composition merges it across the platform → org → team → agent cascade and writes the canonical composed card. Requires `Idempotency-Key`. Body cap 128 KiB. See ADR-008 and ADR-023.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result. See ADR-023."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}},"application/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}}}},"responses":{"200":{"description":"Stored template wrapper after the write.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the new canonical body.","schema":{"type":"string"}},"X-Card-Version":{"description":"Bumped monotonically on every PUT that changes content_hash.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"type":"object","properties":{"org_id":{"type":"string","format":"uuid"},"template":{"description":"The stored template JSON after the write, or `null` when cleared."},"enabled":{"type":"boolean"},"agents_flagged_for_recompose":{"type":"integer","description":"Number of active member agents queued for re-composition."}}}},"text/yaml":{"schema":{"type":"object","properties":{"org_id":{"type":"string","format":"uuid"},"template":{"description":"The stored template JSON after the write, or `null` when cleared."},"enabled":{"type":"boolean"},"agents_flagged_for_recompose":{"type":"integer","description":"Number of active member agents queued for re-composition."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"delete":{"operationId":"deleteAlignmentByOrg","summary":"Clear this alignment layer","description":"Removes the org-scope alignment authoring; downstream scopes fall through to the next layer up in the cascade.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"description":"Cleared. Returns the deletion confirmation (`deleted: true`, `template: null`) and the count of agents flagged for recompose; the next read returns the composed view without this layer. (The handler returns this 200-with-body, not 204.)","content":{"application/json":{"schema":{"type":"object","properties":{"org_id":{"type":"string","format":"uuid"},"template":{"type":"null","description":"Always `null` after a delete."},"enabled":{"type":"boolean"},"deleted":{"type":"boolean","description":"Always `true`."},"agents_flagged_for_recompose":{"type":"integer","description":"Number of active member agents queued for re-composition."}}}},"text/yaml":{"schema":{"type":"object","properties":{"org_id":{"type":"string","format":"uuid"},"template":{"type":"null","description":"Always `null` after a delete."},"enabled":{"type":"boolean"},"deleted":{"type":"boolean","description":"Always `true`."},"agents_flagged_for_recompose":{"type":"integer","description":"Number of active member agents queued for re-composition."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/org/{org_id}/audit":{"put":{"operationId":"putAlignmentAuditByOrg","summary":"Replace audit settings","description":"PUT replaces the entire `audit` block (trace format, retention window, query endpoint). The current spec at the org scope is read; the new `audit` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}}},"application/yaml":{"schema":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}}},"text/yaml":{"schema":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}}}}},"responses":{"200":{"description":"The `audit` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["audit"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentAuditByOrg","summary":"Update audit settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `audit` block (trace format, retention window, query endpoint). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}}}}},"responses":{"200":{"description":"The `audit` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["audit"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/org/{org_id}/autonomy":{"put":{"operationId":"putAlignmentAutonomyByOrg","summary":"Replace autonomy settings","description":"PUT replaces the entire `autonomy` block (bounded_actions[] + forbidden_actions[] + escalation_triggers[] + max_autonomous_value). The current spec at the org scope is read; the new `autonomy` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}}},"application/yaml":{"schema":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}}},"text/yaml":{"schema":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}}}}},"responses":{"200":{"description":"The `autonomy` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["autonomy"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentAutonomyByOrg","summary":"Update autonomy settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `autonomy` block (bounded_actions[] + forbidden_actions[] + escalation_triggers[] + max_autonomous_value). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}}}}},"responses":{"200":{"description":"The `autonomy` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["autonomy"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/org/{org_id}/capabilities":{"put":{"operationId":"putAlignmentCapabilitiesByOrg","summary":"Replace capabilities settings","description":"PUT replaces the entire `capabilities` block (the keyed-map of `{capability_name -> CardCapability}` tool grants). The current spec at the org scope is read; the new `capabilities` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object"}}},"application/yaml":{"schema":{"type":"object","additionalProperties":{"type":"object"}}},"text/yaml":{"schema":{"type":"object","additionalProperties":{"type":"object"}}}}},"responses":{"200":{"description":"The `capabilities` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["capabilities"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","additionalProperties":{"type":"object"}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentCapabilitiesByOrg","summary":"Update capabilities settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `capabilities` block (the keyed-map of `{capability_name -> CardCapability}` tool grants). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object"}}}}},"responses":{"200":{"description":"The `capabilities` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["capabilities"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","additionalProperties":{"type":"object"}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/org/{org_id}/conscience":{"put":{"operationId":"putAlignmentConscienceByOrg","summary":"Replace conscience settings","description":"PUT replaces the entire `conscience` block (augment-vs-replace + the conscience values list). The current spec at the org scope is read; the new `conscience` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}}},"application/yaml":{"schema":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}}},"text/yaml":{"schema":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"200":{"description":"The `conscience` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["conscience"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentConscienceByOrg","summary":"Update conscience settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `conscience` block (augment-vs-replace + the conscience values list). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"200":{"description":"The `conscience` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["conscience"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/org/{org_id}/enforcement":{"put":{"operationId":"putAlignmentEnforcementByOrg","summary":"Replace enforcement settings","description":"PUT replaces the entire `enforcement` block (fine-grained tool-use policy (forbidden patterns, unmapped severity, grace window)). The current spec at the org scope is read; the new `enforcement` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}}},"application/yaml":{"schema":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}}},"text/yaml":{"schema":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}}}}},"responses":{"200":{"description":"The `enforcement` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["enforcement"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentEnforcementByOrg","summary":"Update enforcement settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `enforcement` block (fine-grained tool-use policy (forbidden patterns, unmapped severity, grace window)). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}}}}},"responses":{"200":{"description":"The `enforcement` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["enforcement"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/org/{org_id}/modes":{"put":{"operationId":"putAlignmentModesByOrg","summary":"Replace modes settings","description":"PUT replaces the entire `modes` block (the two top-level master switches `autonomy_mode` + `integrity_mode`). The current spec at the org scope is read; the new `modes` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}}},"application/yaml":{"schema":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}}},"text/yaml":{"schema":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}}}}},"responses":{"200":{"description":"The `modes` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["modes"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentModesByOrg","summary":"Update modes settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `modes` block (the two top-level master switches `autonomy_mode` + `integrity_mode`). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}}}}},"responses":{"200":{"description":"The `modes` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["modes"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/org/{org_id}/preview-compose":{"post":{"operationId":"previewComposeAlignmentByOrg","summary":"Preview composed alignment (dry run)","description":"Composes the cascade against a hypothetical body at the org layer and returns conflicts + the composed view. No DB writes. Used by the dashboard editor for live conflict markers.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}},"application/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}}}},"responses":{"200":{"description":"Preview-compose result: composed card + conflicts + coherence violations.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","description":"Always true on a 200 (the dry-run completed)."},"composed":{"$ref":"#/components/schemas/ComposedAlignmentCard"},"conflicts":{"type":"array","items":{"type":"object"}},"coherence_violations":{"type":"array","items":{"type":"object"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/org/{org_id}/principal":{"put":{"operationId":"putAlignmentPrincipalByOrg","summary":"Replace principal settings","description":"PUT replaces the entire `principal` block (who-the-agent-is identity block). The current spec at the org scope is read; the new `principal` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}}},"application/yaml":{"schema":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}}},"text/yaml":{"schema":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}}}}},"responses":{"200":{"description":"The `principal` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["principal"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentPrincipalByOrg","summary":"Update principal settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `principal` block (who-the-agent-is identity block). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}}}}},"responses":{"200":{"description":"The `principal` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["principal"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/org/{org_id}/values":{"put":{"operationId":"putAlignmentValuesByOrg","summary":"Replace values settings","description":"PUT replaces the entire `values` block (declared catalog entries + definitions / hierarchy / conflicts). The current spec at the org scope is read; the new `values` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}}},"application/yaml":{"schema":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}}},"text/yaml":{"schema":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}}}}},"responses":{"200":{"description":"The `values` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["values"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentValuesByOrg","summary":"Update values settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `values` block (declared catalog entries + definitions / hierarchy / conflicts). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}}}}},"responses":{"200":{"description":"The `values` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["values"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/platform/{scope_id}":{"get":{"operationId":"getAlignmentByPlatform","summary":"Get this layer's alignment manifest","description":"Returns the platform-scope alignment spec as authored. Response is content-negotiated — YAML by default, or JSON with `Accept: application/json`. Pass `?include_composition=true` to include the `_composition` metadata block describing which scopes were merged. Pass `?include=sources` (see ADR-053) for the scope-resolution envelope — the contributing layers plus the composed result; the envelope shape is scope-specific. ETag is computed from `content_hash` (cards-as-primitive Phase 1); `If-None-Match` returns 304. For the composed view across scopes, use the `/effective` sub-resource (Wave 2).","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"include_composition","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include the `_composition` metadata block on the response body."},{"name":"Accept","in":"header","required":false,"schema":{"type":"string","enum":["text/yaml","application/yaml","application/json"]},"description":"Response format. YAML is canonical; JSON is returned only on explicit `application/json`. The `?include=sources` envelope is JSON-only."},{"name":"include","in":"query","required":false,"schema":{"type":"string","enum":["sources"]},"description":"When `sources`, returns the scope-resolution envelope for this scope (the contributing layers + the composed result); the envelope shape is scope-specific (see ADR-053). The envelope is JSON-only."}],"responses":{"200":{"description":"Alignment manifest at this scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the canonical body. Stable across reads; changes on PUT.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter (cards-as-primitive Phase 1).","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Schema identity.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/PlatformCardDefaultsResponse"},{"$ref":"#/components/schemas/PlatformCardSourcesEnvelope"}]}},"text/yaml":{"schema":{"$ref":"#/components/schemas/PlatformCardDefaultsResponse"}}}},"304":{"description":"Not Modified — the client's `If-None-Match` matches the current ETag."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"putAlignmentByPlatform","summary":"Publish or replace the alignment manifest","description":"Accepts YAML (`text/yaml`, `application/yaml`) or JSON. Body is the full `UnifiedAlignmentCard`; server-side composition merges it across the platform → org → team → agent cascade and writes the canonical composed card. Requires `Idempotency-Key`. Body cap 128 KiB. See ADR-008 and ADR-023.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result. See ADR-023."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}},"application/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}}}},"responses":{"200":{"description":"Composed canonical card after the write.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the new canonical body.","schema":{"type":"string"}},"X-Card-Version":{"description":"Bumped monotonically on every PUT that changes content_hash.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComposedAlignmentCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/ComposedAlignmentCard"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/platform/{scope_id}/audit":{"put":{"operationId":"putAlignmentAuditByPlatform","summary":"Replace audit settings","description":"PUT replaces the entire `audit` block (trace format, retention window, query endpoint). The current spec at the platform scope is read; the new `audit` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}}},"application/yaml":{"schema":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}}},"text/yaml":{"schema":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}}}}},"responses":{"200":{"description":"The `audit` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["audit"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentAuditByPlatform","summary":"Update audit settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `audit` block (trace format, retention window, query endpoint). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}}}}},"responses":{"200":{"description":"The `audit` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["audit"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/platform/{scope_id}/autonomy":{"put":{"operationId":"putAlignmentAutonomyByPlatform","summary":"Replace autonomy settings","description":"PUT replaces the entire `autonomy` block (bounded_actions[] + forbidden_actions[] + escalation_triggers[] + max_autonomous_value). The current spec at the platform scope is read; the new `autonomy` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}}},"application/yaml":{"schema":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}}},"text/yaml":{"schema":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}}}}},"responses":{"200":{"description":"The `autonomy` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["autonomy"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentAutonomyByPlatform","summary":"Update autonomy settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `autonomy` block (bounded_actions[] + forbidden_actions[] + escalation_triggers[] + max_autonomous_value). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}}}}},"responses":{"200":{"description":"The `autonomy` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["autonomy"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/platform/{scope_id}/capabilities":{"put":{"operationId":"putAlignmentCapabilitiesByPlatform","summary":"Replace capabilities settings","description":"PUT replaces the entire `capabilities` block (the keyed-map of `{capability_name -> CardCapability}` tool grants). The current spec at the platform scope is read; the new `capabilities` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object"}}},"application/yaml":{"schema":{"type":"object","additionalProperties":{"type":"object"}}},"text/yaml":{"schema":{"type":"object","additionalProperties":{"type":"object"}}}}},"responses":{"200":{"description":"The `capabilities` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["capabilities"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","additionalProperties":{"type":"object"}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentCapabilitiesByPlatform","summary":"Update capabilities settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `capabilities` block (the keyed-map of `{capability_name -> CardCapability}` tool grants). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object"}}}}},"responses":{"200":{"description":"The `capabilities` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["capabilities"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","additionalProperties":{"type":"object"}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/platform/{scope_id}/conscience":{"put":{"operationId":"putAlignmentConscienceByPlatform","summary":"Replace conscience settings","description":"PUT replaces the entire `conscience` block (augment-vs-replace + the conscience values list). The current spec at the platform scope is read; the new `conscience` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}}},"application/yaml":{"schema":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}}},"text/yaml":{"schema":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"200":{"description":"The `conscience` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["conscience"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentConscienceByPlatform","summary":"Update conscience settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `conscience` block (augment-vs-replace + the conscience values list). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"200":{"description":"The `conscience` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["conscience"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/platform/{scope_id}/enforcement":{"put":{"operationId":"putAlignmentEnforcementByPlatform","summary":"Replace enforcement settings","description":"PUT replaces the entire `enforcement` block (fine-grained tool-use policy (forbidden patterns, unmapped severity, grace window)). The current spec at the platform scope is read; the new `enforcement` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}}},"application/yaml":{"schema":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}}},"text/yaml":{"schema":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}}}}},"responses":{"200":{"description":"The `enforcement` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["enforcement"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentEnforcementByPlatform","summary":"Update enforcement settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `enforcement` block (fine-grained tool-use policy (forbidden patterns, unmapped severity, grace window)). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}}}}},"responses":{"200":{"description":"The `enforcement` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["enforcement"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/platform/{scope_id}/modes":{"put":{"operationId":"putAlignmentModesByPlatform","summary":"Replace modes settings","description":"PUT replaces the entire `modes` block (the two top-level master switches `autonomy_mode` + `integrity_mode`). The current spec at the platform scope is read; the new `modes` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}}},"application/yaml":{"schema":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}}},"text/yaml":{"schema":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}}}}},"responses":{"200":{"description":"The `modes` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["modes"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentModesByPlatform","summary":"Update modes settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `modes` block (the two top-level master switches `autonomy_mode` + `integrity_mode`). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}}}}},"responses":{"200":{"description":"The `modes` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["modes"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/platform/{scope_id}/preview-compose":{"post":{"operationId":"previewComposeAlignmentByPlatform","summary":"Preview composed alignment (dry run)","description":"Composes the cascade against a hypothetical body at the platform layer and returns conflicts + the composed view. No DB writes. Used by the dashboard editor for live conflict markers.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}},"application/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}}}},"responses":{"200":{"description":"Preview-compose result: composed card + conflicts + coherence violations.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","description":"Always true on a 200 (the dry-run completed)."},"composed":{"$ref":"#/components/schemas/ComposedAlignmentCard"},"conflicts":{"type":"array","items":{"type":"object"}},"coherence_violations":{"type":"array","items":{"type":"object"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/platform/{scope_id}/principal":{"put":{"operationId":"putAlignmentPrincipalByPlatform","summary":"Replace principal settings","description":"PUT replaces the entire `principal` block (who-the-agent-is identity block). The current spec at the platform scope is read; the new `principal` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}}},"application/yaml":{"schema":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}}},"text/yaml":{"schema":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}}}}},"responses":{"200":{"description":"The `principal` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["principal"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentPrincipalByPlatform","summary":"Update principal settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `principal` block (who-the-agent-is identity block). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}}}}},"responses":{"200":{"description":"The `principal` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["principal"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/platform/{scope_id}/values":{"put":{"operationId":"putAlignmentValuesByPlatform","summary":"Replace values settings","description":"PUT replaces the entire `values` block (declared catalog entries + definitions / hierarchy / conflicts). The current spec at the platform scope is read; the new `values` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}}},"application/yaml":{"schema":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}}},"text/yaml":{"schema":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}}}}},"responses":{"200":{"description":"The `values` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["values"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentValuesByPlatform","summary":"Update values settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `values` block (declared catalog entries + definitions / hierarchy / conflicts). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}}}}},"responses":{"200":{"description":"The `values` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["values"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/scaffold":{"post":{"operationId":"scaffoldAlignment","summary":"Scaffold alignment from a description","description":"Calls an LLM (Claude Haiku by default; opt into Sonnet via `model: \"sonnet\"`) with the catalog and tools-registry context, returns a YAML manifest scaffold + care-framed reasoning prose + suggested catalog entries + coverage gaps. Never auto-commits — the caller reviews and edits before PUT. Cached by (model + scope + description + hints) hash; 24-hour TTL.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["description"],"properties":{"description":{"type":"string","minLength":20,"maxLength":2000,"description":"Free-form description of the agent / scope. Untrusted input — the system prompt instructs the model not to follow embedded directives."},"scope":{"type":"string","enum":["platform","org","team","agent"],"description":"Hint to the model about which scope the manifest will live at."},"hints":{"type":"object","description":"Free-form key/value hints (industry, risk_appetite, existing_tools, etc).","additionalProperties":true},"model":{"type":"string","enum":["haiku","sonnet"],"description":"Claude model to invoke. `haiku` is the default; `sonnet` for prose-heavy reasoning."}}}}}},"responses":{"200":{"description":"Scaffold ready. Editable; never auto-commits.","content":{"application/json":{"schema":{"type":"object","required":["ok","resource","manifest","reasoning","cached","model"],"properties":{"ok":{"type":"boolean","const":true},"resource":{"type":"string","enum":["alignment"]},"manifest":{"type":"string","description":"YAML body of the scaffolded manifest."},"reasoning":{"type":"string","description":"Care-framed prose explanation."},"suggested_catalog_entries":{"type":"array","items":{"type":"string"}},"coverage_gaps":{"type":"array","items":{"type":"object","properties":{"axis":{"type":"string"},"note":{"type":"string"}},"required":["note"]}},"parse_warnings":{"type":"array","items":{"type":"string"}},"cached":{"type":"boolean","description":"True when the response was served from the description-hash cache."},"model":{"type":"string","description":"Claude model id used for the call."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"$ref":"#/components/responses/ServiceUnavailable"},"504":{"$ref":"#/components/responses/BadGateway"}}}},"/alignment/team/{team_id}":{"get":{"operationId":"getAlignmentByTeam","summary":"Get this layer's alignment manifest","description":"Returns the team-scope alignment spec as authored. Response is content-negotiated — YAML by default, or JSON with `Accept: application/json`. Pass `?include_composition=true` to include the `_composition` metadata block describing which scopes were merged. Pass `?include=sources` (see ADR-053) for the scope-resolution envelope — the contributing layers plus the composed result; the envelope shape is scope-specific. ETag is computed from `content_hash` (cards-as-primitive Phase 1); `If-None-Match` returns 304. For the composed view across scopes, use the `/effective` sub-resource (Wave 2).","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"include_composition","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include the `_composition` metadata block on the response body."},{"name":"Accept","in":"header","required":false,"schema":{"type":"string","enum":["text/yaml","application/yaml","application/json"]},"description":"Response format. YAML is canonical; JSON is returned only on explicit `application/json`. The `?include=sources` envelope is JSON-only."},{"name":"include","in":"query","required":false,"schema":{"type":"string","enum":["sources"]},"description":"When `sources`, returns the scope-resolution envelope for this scope (the contributing layers + the composed result); the envelope shape is scope-specific (see ADR-053). The envelope is JSON-only."}],"responses":{"200":{"description":"Alignment manifest at this scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the canonical body. Stable across reads; changes on PUT.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter (cards-as-primitive Phase 1).","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Schema identity.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"org_id":{"type":"string","format":"uuid"},"name":{"type":["string","null"]},"template":{"description":"The authored template JSON, or `null` when none is set."},"enabled":{"type":"boolean"}}}},"text/yaml":{"schema":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"org_id":{"type":"string","format":"uuid"},"name":{"type":["string","null"]},"template":{"description":"The authored template JSON, or `null` when none is set."},"enabled":{"type":"boolean"}}}}}},"304":{"description":"Not Modified — the client's `If-None-Match` matches the current ETag."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"putAlignmentByTeam","summary":"Publish or replace the alignment manifest","description":"Accepts YAML (`text/yaml`, `application/yaml`) or JSON. Body is the full `UnifiedAlignmentCard`; server-side composition merges it across the platform → org → team → agent cascade and writes the canonical composed card. Requires `Idempotency-Key`. Body cap 128 KiB. See ADR-008 and ADR-023.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result. See ADR-023."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}},"application/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}}}},"responses":{"200":{"description":"Stored template wrapper after the write.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the new canonical body.","schema":{"type":"string"}},"X-Card-Version":{"description":"Bumped monotonically on every PUT that changes content_hash.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"org_id":{"type":"string","format":"uuid"},"template":{"description":"The stored template JSON after the write, or `null` when cleared."},"enabled":{"type":"boolean"},"agents_flagged_for_recompose":{"type":"integer","description":"Number of active member agents queued for re-composition."}}}},"text/yaml":{"schema":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"org_id":{"type":"string","format":"uuid"},"template":{"description":"The stored template JSON after the write, or `null` when cleared."},"enabled":{"type":"boolean"},"agents_flagged_for_recompose":{"type":"integer","description":"Number of active member agents queued for re-composition."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"delete":{"operationId":"deleteAlignmentByTeam","summary":"Clear this alignment layer","description":"Removes the team-scope alignment authoring; downstream scopes fall through to the next layer up in the cascade.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"200":{"description":"Cleared. Returns the deletion confirmation (`deleted: true`, `template: null`) and the count of agents flagged for recompose; the next read returns the composed view without this layer. (The handler returns this 200-with-body, not 204.)","content":{"application/json":{"schema":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"org_id":{"type":"string","format":"uuid"},"template":{"type":"null","description":"Always `null` after a delete."},"enabled":{"type":"boolean"},"deleted":{"type":"boolean","description":"Always `true`."},"agents_flagged_for_recompose":{"type":"integer","description":"Number of active member agents queued for re-composition."}}}},"text/yaml":{"schema":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"org_id":{"type":"string","format":"uuid"},"template":{"type":"null","description":"Always `null` after a delete."},"enabled":{"type":"boolean"},"deleted":{"type":"boolean","description":"Always `true`."},"agents_flagged_for_recompose":{"type":"integer","description":"Number of active member agents queued for re-composition."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/team/{team_id}/audit":{"put":{"operationId":"putAlignmentAuditByTeam","summary":"Replace audit settings","description":"PUT replaces the entire `audit` block (trace format, retention window, query endpoint). The current spec at the team scope is read; the new `audit` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}}},"application/yaml":{"schema":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}}},"text/yaml":{"schema":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}}}}},"responses":{"200":{"description":"The `audit` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["audit"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentAuditByTeam","summary":"Update audit settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `audit` block (trace format, retention window, query endpoint). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}}}}},"responses":{"200":{"description":"The `audit` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["audit"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["retention_days","queryable"],"properties":{"trace_format":{"type":"string"},"retention_days":{"type":"integer"},"queryable":{"type":"boolean"},"query_endpoint":{"type":"string"},"tamper_evidence":{"type":["string","null"],"enum":["append_only","signed","merkle",null]},"storage":{"type":"object"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/team/{team_id}/autonomy":{"put":{"operationId":"putAlignmentAutonomyByTeam","summary":"Replace autonomy settings","description":"PUT replaces the entire `autonomy` block (bounded_actions[] + forbidden_actions[] + escalation_triggers[] + max_autonomous_value). The current spec at the team scope is read; the new `autonomy` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}}},"application/yaml":{"schema":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}}},"text/yaml":{"schema":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}}}}},"responses":{"200":{"description":"The `autonomy` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["autonomy"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentAutonomyByTeam","summary":"Update autonomy settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `autonomy` block (bounded_actions[] + forbidden_actions[] + escalation_triggers[] + max_autonomous_value). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}}}}},"responses":{"200":{"description":"The `autonomy` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["autonomy"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["bounded_actions","escalation_triggers"],"properties":{"bounded_actions":{"type":"array","items":{"type":"string"}},"forbidden_actions":{"type":"array","items":{"type":"string"}},"escalation_triggers":{"type":"array","items":{"type":"object"}},"max_autonomous_value":{"type":"object"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/team/{team_id}/capabilities":{"put":{"operationId":"putAlignmentCapabilitiesByTeam","summary":"Replace capabilities settings","description":"PUT replaces the entire `capabilities` block (the keyed-map of `{capability_name -> CardCapability}` tool grants). The current spec at the team scope is read; the new `capabilities` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object"}}},"application/yaml":{"schema":{"type":"object","additionalProperties":{"type":"object"}}},"text/yaml":{"schema":{"type":"object","additionalProperties":{"type":"object"}}}}},"responses":{"200":{"description":"The `capabilities` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["capabilities"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","additionalProperties":{"type":"object"}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentCapabilitiesByTeam","summary":"Update capabilities settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `capabilities` block (the keyed-map of `{capability_name -> CardCapability}` tool grants). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object"}}}}},"responses":{"200":{"description":"The `capabilities` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["capabilities"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","additionalProperties":{"type":"object"}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/team/{team_id}/conscience":{"put":{"operationId":"putAlignmentConscienceByTeam","summary":"Replace conscience settings","description":"PUT replaces the entire `conscience` block (augment-vs-replace + the conscience values list). The current spec at the team scope is read; the new `conscience` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}}},"application/yaml":{"schema":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}}},"text/yaml":{"schema":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"200":{"description":"The `conscience` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["conscience"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentConscienceByTeam","summary":"Update conscience settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `conscience` block (augment-vs-replace + the conscience values list). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"200":{"description":"The `conscience` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["conscience"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["mode","values"],"properties":{"mode":{"type":"string","enum":["augment","replace"]},"values":{"type":"array","items":{"type":"object"}}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/team/{team_id}/enforcement":{"put":{"operationId":"putAlignmentEnforcementByTeam","summary":"Replace enforcement settings","description":"PUT replaces the entire `enforcement` block (fine-grained tool-use policy (forbidden patterns, unmapped severity, grace window)). The current spec at the team scope is read; the new `enforcement` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}}},"application/yaml":{"schema":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}}},"text/yaml":{"schema":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}}}}},"responses":{"200":{"description":"The `enforcement` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["enforcement"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentEnforcementByTeam","summary":"Update enforcement settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `enforcement` block (fine-grained tool-use policy (forbidden patterns, unmapped severity, grace window)). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}}}}},"responses":{"200":{"description":"The `enforcement` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["enforcement"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","properties":{"allow_unmapped_tools":{"type":"boolean"},"default_unmapped_severity":{"type":"string","enum":["low","medium","high","critical"]},"forbidden_tools":{"type":"array","items":{"type":"object"}},"grace_period_hours":{"type":"number"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/team/{team_id}/modes":{"put":{"operationId":"putAlignmentModesByTeam","summary":"Replace modes settings","description":"PUT replaces the entire `modes` block (the two top-level master switches `autonomy_mode` + `integrity_mode`). The current spec at the team scope is read; the new `modes` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}}},"application/yaml":{"schema":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}}},"text/yaml":{"schema":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}}}}},"responses":{"200":{"description":"The `modes` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["modes"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentModesByTeam","summary":"Update modes settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `modes` block (the two top-level master switches `autonomy_mode` + `integrity_mode`). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}}}}},"responses":{"200":{"description":"The `modes` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["modes"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["autonomy_mode","integrity_mode"],"properties":{"autonomy_mode":{"type":"string","enum":["off","observe","nudge","enforce"]},"integrity_mode":{"type":"string","enum":["off","observe","nudge","enforce"]}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/team/{team_id}/preview-compose":{"post":{"operationId":"previewComposeAlignmentByTeam","summary":"Preview composed alignment (dry run)","description":"Composes the cascade against a hypothetical body at the team layer and returns conflicts + the composed view. No DB writes. Used by the dashboard editor for live conflict markers.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}},"application/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedAlignmentCard"}}}},"responses":{"200":{"description":"Preview-compose result: composed card + conflicts + coherence violations.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","description":"Always true on a 200 (the dry-run completed)."},"composed":{"$ref":"#/components/schemas/ComposedAlignmentCard"},"conflicts":{"type":"array","items":{"type":"object"}},"coherence_violations":{"type":"array","items":{"type":"object"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/team/{team_id}/principal":{"put":{"operationId":"putAlignmentPrincipalByTeam","summary":"Replace principal settings","description":"PUT replaces the entire `principal` block (who-the-agent-is identity block). The current spec at the team scope is read; the new `principal` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}}},"application/yaml":{"schema":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}}},"text/yaml":{"schema":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}}}}},"responses":{"200":{"description":"The `principal` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["principal"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentPrincipalByTeam","summary":"Update principal settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `principal` block (who-the-agent-is identity block). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}}}}},"responses":{"200":{"description":"The `principal` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["principal"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["type","relationship"],"properties":{"type":{"type":"string","enum":["human","organization","agent","unspecified"]},"identifier":{"type":"string"},"relationship":{"type":"string","enum":["delegated_authority","advisory","autonomous"]},"escalation_contact":{"type":"string"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/alignment/team/{team_id}/values":{"put":{"operationId":"putAlignmentValuesByTeam","summary":"Replace values settings","description":"PUT replaces the entire `values` block (declared catalog entries + definitions / hierarchy / conflicts). The current spec at the team scope is read; the new `values` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}}},"application/yaml":{"schema":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}}},"text/yaml":{"schema":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}}}}},"responses":{"200":{"description":"The `values` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["values"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchAlignmentValuesByTeam","summary":"Update values settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `values` block (declared catalog entries + definitions / hierarchy / conflicts). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Alignment"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}}}}},"responses":{"200":{"description":"The `values` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["alignment"]},"primitive":{"type":"string","enum":["values"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{}},"definitions":{"type":"object","additionalProperties":true},"conflicts_with":{"type":"array","items":{"type":"string"}},"hierarchy":{"type":"string","enum":["lexicographic","weighted","contextual"]}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/analyze":{"post":{"operationId":"analyze","summary":"Run single integrity analysis","tags":["Analyze"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["thinking_block","thinking_metadata","agent_id","session_id","card"],"properties":{"thinking_block":{"type":"string"},"thinking_metadata":{"type":"object","required":["provider","model"],"properties":{"provider":{"type":"string"},"model":{"type":"string"}}},"agent_id":{"type":"string"},"session_id":{"type":"string"},"card":{"type":"object","required":["card_id","values"],"properties":{"card_id":{"type":"string"},"values":{"type":"array","items":{"type":"object"}}}},"conscience_values":{"type":"array","items":{"$ref":"#/components/schemas/ConscienceValue"}},"window_context":{"type":"array","items":{"type":"object"}},"task_context":{"type":"string"},"store_checkpoint":{"type":"boolean","default":false}}}}}},"responses":{"200":{"description":"Analysis result","content":{"application/json":{"schema":{"type":"object","properties":{"checkpoint":{"$ref":"#/components/schemas/Checkpoint"},"proceed":{"type":"boolean"},"recommended_action":{"type":"string"},"window_summary":{"type":"object"},"metering":{"type":"object","properties":{"event_id":{"type":"string"},"account_id":{"type":"string"},"billed":{"type":"boolean"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/analyze/batch":{"post":{"operationId":"analyzeBatch","summary":"Run batch integrity analysis (1-50 items)","tags":["Analyze"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"type":"object"},"minItems":1,"maxItems":50,"description":"Array of analysis requests (same shape as POST /analyze body)"}}}}}},"responses":{"200":{"description":"Batch analysis results","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object"}},"metering":{"type":"object","properties":{"total_events":{"type":"integer"},"account_id":{"type":"string"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api-keys":{"post":{"operationId":"createApiKey","summary":"Create a personal API key","description":"Mints a new personal API key. The full secret is returned in the `key` field — capture it now, it is not retrievable again. Scopes use the capability-based vocabulary (ADR-049); the default scope set is `[\"gateway\", \"api:read\", \"api:write\"]`. Admin scopes (`admin:org`, `admin:platform`) are opt-in and rejected at mint time if the requester does not hold the corresponding role.","tags":["Billing"],"security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"default":"Default","description":"Friendly name for the key (e.g., \"ci-prod\", \"local-dev\"). Capped at 100 characters; longer names are truncated server-side."},"scopes":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyScope"},"default":["gateway","api:read","api:write"],"description":"Capability set for this key. If omitted, the API substitutes the default. Admin scopes (`admin:org`, `admin:platform`) are gated by the requester's current role and return HTTP 403 at mint time if the requester is not eligible."}}}}}},"responses":{"201":{"description":"API key created (secret shown once)","content":{"application/json":{"schema":{"type":"object","required":["key_id","key","key_prefix","name","scopes","created_at"],"properties":{"key_id":{"type":"string"},"key":{"type":"string","description":"Full secret. Capture now — never returned again."},"key_prefix":{"type":"string"},"name":{"type":"string"},"scopes":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyScope"}},"created_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"get":{"operationId":"listApiKeys","summary":"List active API keys","tags":["Billing"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"API key list","content":{"application/json":{"schema":{"type":"object","properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api-keys/whoami":{"get":{"operationId":"apiKeyWhoAmI","summary":"Inspect the calling API key (caller introspection)","description":"Returns the resolved API key's identity: its scopes (capabilities), bound user/agent/org, and last-used metadata. Useful for clients to confirm scope and identity before issuing privileged calls.","tags":["Auth"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Caller identity.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyWhoAmI"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api-keys/{key_id}":{"delete":{"operationId":"revokeApiKey","summary":"Revoke an API key","tags":["Billing"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the API key to act on (mk-{8-hex})."}],"responses":{"200":{"description":"Key revoked","content":{"application/json":{"schema":{"type":"object","properties":{"revoked":{"type":"boolean"},"key_id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api-keys/{key_id}/rotate":{"post":{"operationId":"rotateApiKey","summary":"Rotate a personal API key","description":"Atomically mints a replacement key with the same `name` and `scopes` as the original, then immediately revokes the old key. The full new secret is returned in the response — this is your only chance to capture it. Old key is invalid as soon as the response is returned; if you need overlap with an in-flight deploy, **create a second key first** via `POST /api-keys`, ship your code, then `DELETE` the old key. Rotation is for the suspect/compromised-key case where overlap is the opposite of what you want.","tags":["Billing"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the API key to act on (mk-{8-hex})."}],"responses":{"201":{"description":"New key minted, old key revoked.","content":{"application/json":{"schema":{"type":"object","properties":{"key_id":{"type":"string"},"key":{"type":"string","description":"Full secret. Capture now — never returned again."},"key_prefix":{"type":"string"},"name":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"rotated_from":{"type":"string","description":"key_id of the now-revoked predecessor"},"old_key_revoked_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/auth/callback":{"get":{"operationId":"emailCallback","summary":"Email-link landing (confirmation / recovery / magic link)","description":"Handles Supabase-hosted email links. Verifies the token via GoTrue, issues `mnemom_session` when the flow returns tokens (signup confirm, magic link), or redirects without a session for recovery flows where the SPA performs the next step.","tags":["Auth"],"security":[],"parameters":[{"name":"token_hash","in":"query","required":true,"schema":{"type":"string"}},{"name":"type","in":"query","required":true,"schema":{"type":"string","enum":["signup","recovery","magiclink","email_change","invite"]}},{"name":"redirect_after","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Not emitted by this Worker: the Worker always answers with a `302`. When a client transparently follows that redirect, the SPA at the redirect target serves its HTML shell (`text/html`). Documented here so spec-conformance probes that follow the redirect don't flag the SPA landing page as an undocumented response.","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"Redirects to the SPA. Sets `mnemom_session` when tokens are issued.","headers":{"Location":{"schema":{"type":"string","format":"uri"}},"Set-Cookie":{"schema":{"type":"string"},"description":"Optional; only when tokens are issued."}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/auth/cli-exchange":{"post":{"operationId":"cliExchange","summary":"Exchange a cookie session for raw Supabase tokens","description":"One-shot endpoint called by the SPA during the CLI login flow (browser → localhost handoff). Requires a valid `mnemom_session`. Returns access + refresh tokens in the JSON body. Does not modify cookies.","tags":["Auth"],"security":[{"CookieAuth":[]}],"responses":{"200":{"description":"Tokens returned.","content":{"application/json":{"schema":{"type":"object","required":["access_token","refresh_token","expires_in","user_id"],"properties":{"access_token":{"type":"string","description":"Supabase JWT."},"refresh_token":{"type":"string"},"expires_in":{"type":"integer","description":"Seconds until access_token expires."},"user_id":{"type":"string","format":"uuid"},"user_email":{"type":["string","null"],"format":"email"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/auth/delete-account":{"delete":{"operationId":"deleteAccount","summary":"Delete authenticated user account and unlink agents","tags":["Auth"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Account deleted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/auth/idp/callback":{"get":{"operationId":"idpCallback","summary":"External-SSO callback landing — issues session and redirects to SPA","description":"MNE-1449 re-flip. Validates the HMAC-signed `mnemom_idp_initiator` cookie (CSRF), retrieves the idpIntent server-side (`POST /v2/idp_intents/{id}` with the `token`, SA-authorized), resolves the LINKED Zitadel user from the retrieve response's top-level `userId` (fail-closed 403 when the external identity is not linked — never auto-provisions), vouch-mints a first-party session, and issues `mnemom_session` via a 302 to the SPA. Returns 503 unless the cell is configured for Zitadel login.","tags":["Auth"],"security":[],"parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string"},"description":"The idpIntent id appended by Zitadel to the successUrl."},{"name":"token","in":"query","required":true,"schema":{"type":"string"},"description":"The idpIntent token appended by Zitadel to the successUrl."}],"responses":{"302":{"description":"Session issued. Redirects to the SPA.","headers":{"Location":{"schema":{"type":"string","format":"uri"}},"Set-Cookie":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/idp/fail":{"get":{"operationId":"idpFail","summary":"External-SSO failure landing — clears state and redirects to SPA login","description":"MNE-1449 re-flip. The idpIntent `failureUrl`: the external IdP / Zitadel signaled a failure. No session is minted; clears the `mnemom_idp_initiator` cookie and 302-redirects to the SPA login with an error flag. Returns 503 unless the cell is configured for Zitadel login.","tags":["Auth"],"security":[],"responses":{"302":{"description":"Redirects to the SPA login with an error flag. Clears `mnemom_idp_initiator`.","headers":{"Location":{"schema":{"type":"string","format":"uri"}},"Set-Cookie":{"schema":{"type":"string"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/idp/start":{"get":{"operationId":"idpStart","summary":"Begin a server-orchestrated external SSO login (Zitadel idpIntent)","description":"MNE-1449 re-flip. Server-drives the external-IdP (Microsoft Entra) login via Zitadel's idpIntent CORE API so the Zitadel hosted-login UI never renders. Starts a `POST /v2/idp_intents`, sets a short-lived `mnemom_idp_initiator` cookie (HMAC-signed state carrying the allowlisted `redirect_after` — the CSRF binding), and 302-redirects the browser to the external IdP authorize URL. DARK: returns 503 unless the cell is configured with `AUTH_PROVIDER=zitadel` + `ZITADEL_DEFAULT_IDP_ID`.","tags":["Auth"],"security":[],"parameters":[{"name":"redirect_after","in":"query","required":false,"schema":{"type":"string"},"description":"SPA path to land on after login completes (allowlisted)."}],"responses":{"302":{"description":"Redirects to the external IdP authorize endpoint. Sets `mnemom_idp_initiator` cookie.","headers":{"Location":{"schema":{"type":"string","format":"uri"}},"Set-Cookie":{"schema":{"type":"string"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/login":{"post":{"operationId":"authLogin","summary":"CLI password login — returns bearer tokens in JSON body","description":"Legacy CLI-targeted endpoint. Unlike `/auth/sign-in`, this does NOT set cookies — it returns access + refresh tokens in the JSON body for the CLI to persist at `~/.mnemom/auth.json`. For users with a ready TOTP factor the password alone does not mint tokens: the response is 200 `{ mfa_required: true, factor_id }` and no token pair is issued (aal2 step-up, #60). Rate-limited.","tags":["Auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string","format":"email"},"password":{"type":"string","format":"password"}}}}}},"responses":{"200":{"description":"Tokens returned OR MFA step-up required.","content":{"application/json":{"schema":{"oneOf":[{"type":"object","required":["access_token","refresh_token"],"properties":{"access_token":{"type":"string"},"refresh_token":{"type":"string"},"expires_in":{"type":"integer"},"user":{"$ref":"#/components/schemas/User"}}},{"type":"object","required":["mfa_required","factor_id","mfa_token"],"properties":{"mfa_required":{"type":"boolean","enum":[true]},"factor_id":{"type":"string"},"mfa_token":{"type":"string","description":"Opaque, sealed, single-use step-up handle. Submit to `POST /auth/login/mfa` with the TOTP code to complete login. 10-minute TTL."}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"}}}},"/auth/login/mfa":{"post":{"operationId":"authLoginMfa","summary":"CLI MFA step-up completion — exchange mfa_token + TOTP for tokens","description":"Completes the aal2 step-up begun by `POST /auth/login` (which answers `200 { mfa_required, factor_id, mfa_token }` for a ready-TOTP user). The client submits the opaque `mfa_token` from that response together with the current TOTP `code`; on success the bearer token pair is returned in the JSON body, exactly like the factorless `/auth/login` 200. Cookie-free (a CLI has no cookie jar, unlike `/auth/mfa/verify`). The mfa_token is single-use and TTL-bounded. Rate-limited.","tags":["Auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["mfa_token","code"],"properties":{"mfa_token":{"type":"string","description":"The opaque sealed handle returned by `POST /auth/login` in the mfa_required branch."},"code":{"type":"string","description":"The current TOTP code for the user's ready factor."},"factor_id":{"type":"string","description":"Optional factor selector. Only `totp` is supported programmatically; `email_otp` is rejected 400."}}}}}},"responses":{"200":{"description":"Step-up succeeded — bearer tokens returned.","content":{"application/json":{"schema":{"type":"object","required":["access_token","refresh_token"],"properties":{"access_token":{"type":"string"},"refresh_token":{"type":"string"},"expires_in":{"type":"integer"},"user":{"$ref":"#/components/schemas/User"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/me":{"get":{"operationId":"getMe","summary":"Get authenticated user info and linked agents","tags":["Auth"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"User profile","content":{"application/json":{"schema":{"type":"object","properties":{"user_id":{"type":"string"},"email":{"type":"string"},"agents":{"type":"array","items":{"$ref":"#/components/schemas/Agent"}},"billing_account_id":{"type":["string","null"]},"plan_id":{"type":["string","null"]},"org":{"type":["object","null"],"properties":{"org_id":{"type":"string"},"org_name":{"type":"string"},"role":{"type":"string"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/auth/me/avatar":{"put":{"operationId":"putMyAvatar","summary":"Upload current user's avatar","description":"Replace the authenticated user's profile avatar. The user identity is taken from the JWT/`mnm_*` auth context — there is no path parameter. Old avatar is replaced; storage cleanup happens server-side.","tags":["Auth"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"Avatar image. Validated for MIME type and size before upload."}}}}}},"responses":{"200":{"description":"Avatar uploaded; persistent URL returned","content":{"application/json":{"schema":{"type":"object","required":["avatar_url"],"properties":{"avatar_url":{"type":"string","format":"uri","description":"Public URL of the uploaded avatar (CDN-served).","example":"https://cdn.mnemom.ai/avatars/agents/mnm-7f3b9e2a/abc123.png"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"}}}},"/auth/me/personal-org":{"get":{"operationId":"getMyPersonalOrg","summary":"Get the authenticated user's personal organization","description":"Returns the authenticated user's personal organization — the auto-provisioned org-of-one that scopes their individual resources. Idempotent. If the user does not yet have a personal org (legacy account pre-dating migration 161, or a transient backfill miss), one is provisioned on the fly and `just_provisioned` is set to `true`.","tags":["Auth"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"Personal org accessor.","content":{"application/json":{"schema":{"type":"object","required":["org_id","is_personal"],"properties":{"org_id":{"type":"string"},"is_personal":{"type":"boolean","enum":[true]},"just_provisioned":{"type":"boolean","description":"True only when this call provisioned the personal org (lazy backfill path)."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/mfa/challenge":{"post":{"operationId":"mfaChallenge","summary":"Issue a challenge for a TOTP factor","description":"Called during the sign-in MFA step-up flow (using the `mnemom_mfa_pending` cookie) or during enrollment verification (using the existing `mnemom_session`). Returns a `challenge_id` to pass to `/auth/mfa/verify`.","tags":["Auth"],"security":[{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["factor_id"],"properties":{"factor_id":{"type":"string"}}}}}},"responses":{"200":{"description":"Challenge issued.","content":{"application/json":{"schema":{"type":"object","properties":{"challenge_id":{"type":"string"}},"required":["challenge_id"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/mfa/enroll":{"post":{"operationId":"mfaEnroll","summary":"Enroll a new TOTP factor","description":"Returns the TOTP secret + provisioning URI for a QR code. Factor starts in `unverified` state until `/auth/mfa/verify` is called against it.","tags":["Auth"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"friendly_name":{"type":"string"}}}}}},"responses":{"200":{"description":"Factor enrolled (unverified). Supabase passthrough.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["totp"]},"totp":{"type":"object","properties":{"qr_code":{"type":"string","description":"SVG QR code."},"secret":{"type":"string"},"uri":{"type":"string","format":"uri"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/mfa/factors":{"get":{"operationId":"mfaListFactors","summary":"List the current user's TOTP factors","tags":["Auth"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"TOTP factor list (Supabase passthrough).","content":{"application/json":{"schema":{"type":"object","properties":{"totp":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"friendly_name":{"type":["string","null"]},"status":{"type":"string","enum":["unverified","verified"]},"created_at":{"type":"string","format":"date-time"}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/mfa/unenroll":{"post":{"operationId":"mfaUnenroll","summary":"Unenroll a TOTP factor","description":"Requires an aal2 session (freshly MFA-verified). Returns 403 `code: aal2_required` if the session isn't aal2.","tags":["Auth"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["factor_id"],"properties":{"factor_id":{"type":"string"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/mfa/verify":{"post":{"operationId":"mfaVerify","summary":"Complete MFA step-up or enrollment","description":"Sign-in flow: consumes the `mnemom_mfa_pending` cookie, verifies the TOTP code, and issues a full `mnemom_session`. Enrollment flow: verifies a freshly-enrolled factor using the current session and upgrades it to aal2.","tags":["Auth"],"security":[{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["factor_id","challenge_id","code"],"properties":{"factor_id":{"type":"string"},"challenge_id":{"type":"string"},"code":{"type":"string","description":"6-digit TOTP code."}}}}}},"responses":{"200":{"description":"Full session issued. Response sets `mnemom_session` cookie.","headers":{"Set-Cookie":{"schema":{"type":"string"},"description":"Sets `mnemom_session` (HttpOnly, Secure, SameSite=Lax)."}},"content":{"application/json":{"schema":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"}},"required":["user"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/oidc/callback":{"get":{"operationId":"oidcCallback","summary":"OIDC callback landing — issues session and redirects to SPA","description":"B1 PR-B (MNE-1449). Validates the HMAC-signed `state` (double-submitted against the `mnemom_oidc_initiator` cookie), consumes the single-use nonce, exchanges the authorization `code` at the Zitadel token endpoint (PKCE), and issues `mnemom_session` via a 302 to the SPA. Returns 503 unless the cell is configured for Zitadel login.","tags":["Auth"],"security":[],"parameters":[{"name":"code","in":"query","required":true,"schema":{"type":"string"}},{"name":"state","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"302":{"description":"Session issued. Redirects to the SPA.","headers":{"Location":{"schema":{"type":"string","format":"uri"}},"Set-Cookie":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/oidc/finalize":{"post":{"operationId":"oidcFinalize","summary":"Finalize an inbound loginV2 auth request against the caller's session","description":"loginV2 finalize. id.mnemom.ai has no hosted loginV2 UI, so the mnemom login page is the loginV2 `baseUri` target: after it authenticates the user (issuing the `__Host-mnemom_session` cookie), it posts the inbound Zitadel auth-request id here. The endpoint reuses the caller's stashed Zitadel login session (falling back to a fresh user-only vouch session if that has aged past `passwordCheckLifetime`) to finalize the request, returning the RP `callbackUrl` for the browser to follow. Requires an authenticated session cookie; the `authRequestId` must resolve to an allowed first-party client. Returns 503 unless the cell is configured with `AUTH_PROVIDER=zitadel`.","tags":["Auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["authRequestId"],"properties":{"authRequestId":{"type":"string","pattern":"^V2_[0-9]{1,32}$","description":"The inbound Zitadel V2 auth-request handle (`V2_<id>`)."}}}}}},"responses":{"200":{"description":"The auth request was finalized; follow the returned callback URL.","content":{"application/json":{"schema":{"type":"object","required":["callbackUrl"],"properties":{"callbackUrl":{"type":"string","format":"uri","description":"The RP callback URL carrying the authorization `code`."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/oidc/start":{"get":{"operationId":"oidcStart","summary":"Begin an OIDC authorization-code login (Zitadel redirect leg)","description":"B1 PR-B (MNE-1449). Generates PKCE + an HMAC-signed state + single-use nonce, sets a short-lived `mnemom_oidc_initiator` cookie, and 302-redirects the browser to the Zitadel hosted-login authorize endpoint. Plumbing for hosted-login / enterprise SSO (PR-E). Returns 503 unless the cell is configured with `AUTH_PROVIDER=zitadel` + the login-client config.","tags":["Auth"],"security":[],"parameters":[{"name":"redirect_after","in":"query","required":false,"schema":{"type":"string"},"description":"SPA path to land on after login completes (allowlisted)."}],"responses":{"302":{"description":"Redirects to the Zitadel authorize endpoint. Sets `mnemom_oidc_initiator` cookie.","headers":{"Location":{"schema":{"type":"string","format":"uri"}},"Set-Cookie":{"schema":{"type":"string"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/passkey/challenge":{"post":{"operationId":"passkeyChallenge","summary":"Begin passkey sign-in — return WebAuthn assertion options","description":"Unauthenticated. Returns `PublicKeyCredentialRequestOptions` with an empty `allowCredentials` list (discoverable-credentials flow). The browser surfaces any matching passkey for this RP without needing the user to enter an email. Rate-limited.","tags":["Auth"],"security":[],"responses":{"200":{"description":"WebAuthn assertion options.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicKeyCredentialRequestOptionsJSON"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/passkey/enroll":{"post":{"operationId":"passkeyEnroll","summary":"Begin passkey enrollment — return WebAuthn creation options","description":"Authenticated endpoint. Returns `PublicKeyCredentialCreationOptions` for the SPA to pass to `navigator.credentials.create()`. Stores the challenge in KV with a 30-second TTL; the companion `/verify-enroll` endpoint consumes it. `excludeCredentials` is pre-populated with the user's existing passkeys so the authenticator prevents duplicate enrollment of the same key.","tags":["Auth"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"WebAuthn creation options. Shape follows the WebAuthn Level 3 spec.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicKeyCredentialCreationOptionsJSON"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/passkey/verify-auth":{"post":{"operationId":"passkeyVerifyAuth","summary":"Verify a passkey assertion and issue a session","description":"Unauthenticated. Consumes the challenge issued by `/auth/passkey/challenge`, verifies the assertion via `@simplewebauthn/server`, mints Supabase tokens via `admin.generateLink(magiclink)` for the resolved user (same pattern T3-2c uses for SSO identity linking), and issues `mnemom_session` with `auth_method: 'passkey'`. Counter is enforced monotonically — a decrement rejects the assertion.","tags":["Auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["response"],"properties":{"response":{"$ref":"#/components/schemas/AuthenticationResponseJSON"}}}}}},"responses":{"200":{"description":"Session issued.","headers":{"Set-Cookie":{"schema":{"type":"string"},"description":"`mnemom_session` (HttpOnly, Secure, SameSite=Lax)."}},"content":{"application/json":{"schema":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/passkey/verify-enroll":{"post":{"operationId":"passkeyVerifyEnroll","summary":"Verify a passkey registration response + persist the credential","description":"Authenticated endpoint. Consumes the challenge issued by `/auth/passkey/enroll`, verifies the attestation via `@simplewebauthn/server`, and inserts a row into `user_passkeys`. A user-supplied `friendly_name` is stored alongside for UI display.","tags":["Auth"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["response"],"properties":{"response":{"$ref":"#/components/schemas/RegistrationResponseJSON"},"friendly_name":{"type":"string","description":"User label (e.g. \"Alex's iPhone\")."}}}}}},"responses":{"200":{"description":"Passkey enrolled.","content":{"application/json":{"schema":{"type":"object","properties":{"credential_id":{"type":"string"},"friendly_name":{"type":["string","null"]},"device_type":{"type":"string","enum":["single_device","multi_device"]},"backed_up":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/passkeys":{"get":{"operationId":"passkeysList","summary":"List the current user's enrolled passkeys","description":"Returns the safe subset of `user_passkeys` for the authenticated user (omits public_key, counter, last_used_ip).","tags":["Auth"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Passkey list.","content":{"application/json":{"schema":{"type":"object","properties":{"passkeys":{"type":"array","items":{"type":"object","properties":{"credential_id":{"type":"string"},"friendly_name":{"type":["string","null"]},"device_type":{"type":"string","enum":["single_device","multi_device"]},"backed_up":{"type":"boolean"},"transports":{"type":"array","items":{"type":"string"}},"created_at":{"type":"string","format":"date-time"},"last_used_at":{"type":["string","null"],"format":"date-time"}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/auth/passkeys/{credential_id}":{"delete":{"operationId":"passkeyDelete","summary":"Remove an enrolled passkey","description":"Requires aal2. Deleting a passkey does not affect other passkeys or the password/MFA fallback; those remain usable.","tags":["Auth"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"parameters":[{"name":"credential_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Passkey removed.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/auth/password":{"post":{"operationId":"updatePassword","summary":"Update the authenticated user's password","description":"Authenticated password update. Used by both the `/reset-password` recovery flow (after the recovery email callback issues a session) and voluntary password changes from account settings. Cookie session auth required (`mnemom_session`); bearer tokens are not accepted on this route. After a successful update, every other session for the same user is revoked with audit reason `password_reset`.","tags":["Auth"],"security":[{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["password"],"properties":{"password":{"type":"string","minLength":12,"description":"New password. Must be at least 12 characters. The upstream identity provider applies additional weak-password and breach-list checks; failures surface as 400 with a `password_rejected` error code."}}}}}},"responses":{"200":{"description":"Password updated. Other sessions for the same user are revoked best-effort.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/auth/password-reset-request":{"post":{"operationId":"passwordResetRequest","summary":"Request a password reset email","description":"Always returns 200 on 4xx upstream responses (to avoid user enumeration). 5xx upstream errors surface as 5xx to the caller.","tags":["Auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"redirect_to":{"type":"string","format":"uri","description":"Allowlisted SPA path to return to after the user clicks the reset link."}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/refresh":{"post":{"operationId":"authRefresh","summary":"CLI token refresh","description":"Legacy CLI-targeted refresh grant. Trades a refresh token for a new access + refresh token pair. Rate-limited.","tags":["Auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["refresh_token"],"properties":{"refresh_token":{"type":"string"}}}}}},"responses":{"200":{"description":"New tokens.","content":{"application/json":{"schema":{"type":"object","required":["access_token","refresh_token"],"properties":{"access_token":{"type":"string"},"refresh_token":{"type":"string"},"expires_in":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/auth/resend-confirmation":{"post":{"operationId":"resendConfirmation","summary":"Resend email confirmation","description":"Re-sends the signup confirmation email for a pending account.","tags":["Auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"redirect_to":{"type":"string","format":"uri"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/session":{"get":{"operationId":"getSession","summary":"Cookie-aware whoami","description":"Minimal whoami endpoint. Returns `{ user }` when the `mnemom_session` cookie is valid; returns 401 otherwise. Preferred over `GET /auth/me` for cookie-only browser sessions — `/auth/me` is bearer-only and preserves its legacy response shape unchanged.","tags":["Auth"],"security":[{"CookieAuth":[]}],"responses":{"200":{"description":"Authenticated session.","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/auth/sessions":{"get":{"operationId":"listSessions","summary":"List the caller's active sessions","description":"Returns every non-revoked session for the authenticated user. Each row is safe to render in an \"Active sessions\" UI — no tokens are disclosed. The session matching the request cookie is marked `is_current: true`, and sessions originating from the same hashed source IP as the current request are marked `same_network_as_current: true`. See ADR-028.","tags":["Auth"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Active sessions for the current user.","content":{"application/json":{"schema":{"type":"object","required":["sessions"],"properties":{"sessions":{"type":"array","items":{"type":"object","required":["sid","auth_method","device_label","issued_at","last_seen_at","is_current","same_network_as_current"],"properties":{"sid":{"type":"string","description":"Opaque session id. Pass to `DELETE /auth/sessions/{sid}` to revoke."},"auth_method":{"type":"string","enum":["password","sso","passkey"]},"device_label":{"type":"string","description":"Best-effort human label derived from the original User-Agent and IP at sign-in time (e.g. \"Safari on macOS — San Francisco\")."},"issued_at":{"type":"string","format":"date-time"},"last_seen_at":{"type":"string","format":"date-time"},"is_current":{"type":"boolean","description":"True for the session tied to the request cookie."},"same_network_as_current":{"type":"boolean","description":"True when this session's hashed source IP matches the current request's."}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"delete":{"operationId":"revokeAllOtherSessions","summary":"Revoke all other sessions","description":"Revokes every active session for the current user _except_ the one making this call. Requires aal2 (MFA-verified session). Sessions issued before per-session revocation (v=1 cookies) cannot identify themselves as \"current\" and receive `409 legacy_session_requires_reauth` — the user must sign in again to use this action. See ADR-028.","tags":["Auth"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string"},"description":"Optional idempotency key; repeated calls with the same key return the same result within 24 hours."}],"responses":{"200":{"description":"Number of sessions revoked.","content":{"application/json":{"schema":{"type":"object","required":["revoked"],"properties":{"revoked":{"type":"integer","description":"Count of sessions revoked (excludes the current session)."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/auth/sessions/revoke-via-email":{"post":{"operationId":"revokeSessionViaEmail","summary":"Revoke a session using a signed email token","description":"Consumes a signed token minted at email-send time by the new-device notification flow. Possession of the token is the auth factor — no existing session cookie is required, no MFA. Returns 200 on any verified-valid token even if the underlying sid is already revoked (idempotent, non-enumerating). Returns 400 on malformed, tampered, expired, or key-mismatched tokens. Public endpoint, rate-limited. See ADR-031.","tags":["Auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"HS256-signed token from the new-device email link."}}}}}},"responses":{"200":{"description":"Session revocation accepted (idempotent — 200 returned even if the session was already gone).","content":{"application/json":{"schema":{"type":"object","required":["revoked_at"],"properties":{"revoked_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/auth/sessions/{sid}":{"delete":{"operationId":"revokeSession","summary":"Revoke a specific session","description":"Revokes one non-current session by its `sid`. The KV blocklist is updated so the gateway rejects the next request bearing that session on its next hit. Cannot be used to revoke the session making this request — use `POST /auth/sign-out` for that. Requires aal2. Idempotent: a sid that is already revoked or never belonged to the user returns 404 (non-enumeration). See ADR-028.","tags":["Auth"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"parameters":[{"name":"sid","in":"path","required":true,"schema":{"type":"string"},"description":"Session identifier returned by `GET /auth/sessions`."}],"responses":{"200":{"description":"Session revoked.","content":{"application/json":{"schema":{"type":"object","required":["revoked_at"],"properties":{"revoked_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/auth/set-locale":{"post":{"operationId":"setLocale","summary":"Set the authenticated user's preferred email locale","description":"Updates `user_metadata.locale` on the Supabase auth user. Locale-aware send paths (billing webhooks, licensing expiry, auth send-email-hook) read this field to choose between English (default), French, German, Italian, and Spanish copy. Cookie session auth required; the change is effective immediately for subsequent email sends.","tags":["Auth"],"security":[{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["locale"],"properties":{"locale":{"type":"string","enum":["en","fr","de","it","es"],"description":"Preferred email locale. Values outside this enum are rejected with `unsupported_locale`."}}}}}},"responses":{"200":{"description":"Locale updated.","content":{"application/json":{"schema":{"type":"object","required":["ok","locale"],"properties":{"ok":{"type":"boolean"},"locale":{"type":"string","enum":["en","fr","de","it","es"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/sign-in":{"post":{"operationId":"signIn","summary":"Sign in with email + password","description":"Server-enforces SSO for org-enforced domains (returns 403 with `code: sso_required`). For users with a verified TOTP factor, returns 200 `{ mfa_required: true, factor_id }` and sets a short-lived `mnemom_mfa_pending` cookie; otherwise issues `mnemom_session` and returns `{ user }`.","tags":["Auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string","format":"email"},"password":{"type":"string","format":"password"}}}}}},"responses":{"200":{"description":"Full session issued OR MFA step-up required.","headers":{"Set-Cookie":{"schema":{"type":"string"},"description":"`mnemom_session` on full session, or `mnemom_mfa_pending` on MFA step-up."}},"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"}},"required":["user"]},{"type":"object","properties":{"mfa_required":{"type":"boolean","enum":[true]},"factor_id":{"type":"string"}},"required":["mfa_required","factor_id"]}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/sign-out":{"post":{"operationId":"signOut","summary":"Sign out and clear session cookies","description":"Revokes the refresh token upstream and clears `mnemom_session` + `mnemom_mfa_pending`. Idempotent and anon-callable by design — calling it without a session returns 200 + no-op cookie clear, so a logged-out client can safely re-issue the call without observing a 401.","tags":["Auth"],"security":[{},{"CookieAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Cookies cleared.","headers":{"Set-Cookie":{"schema":{"type":"string"},"description":"Clears session cookies."}},"content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/sign-up":{"post":{"operationId":"signUp","summary":"Sign up with email + password","description":"Creates a new user account. When email confirmation is required on the Supabase project, returns `{ user, email_confirmation_required: true }` without issuing a session cookie; the user must click the email link. When auto-confirm is on, issues `mnemom_session` and returns `{ user }`. If the email already has an account, returns `409` with `code: email_exists` — no duplicate account is created and no verification email is sent (MNE-1348).","tags":["Auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string","format":"email"},"password":{"type":"string","format":"password","minLength":8},"redirect_to":{"type":"string","format":"uri","description":"Allowlisted SPA path to return to after email confirmation."}}}}}},"responses":{"200":{"description":"Account created. Either returns a full session (auto-confirm) or awaits email confirmation.","content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"}},"required":["user"],"not":{"required":["email_confirmation_required"]}},{"type":"object","properties":{"user":{"description":"`null` while email confirmation is pending — no session is issued until the user clicks the confirmation link.","anyOf":[{"$ref":"#/components/schemas/User"},{"type":"null"}]},"email_confirmation_required":{"type":"boolean","enum":[true]}},"required":["email_confirmation_required"]}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/sso/callback":{"get":{"operationId":"ssoCallback","summary":"IdP callback landing — issues session and redirects to SPA","description":"Validates the HMAC-signed state (from the `mnemom_sso_initiator` cookie), consumes the single-use nonce, exchanges the PKCE code, enforces domain + org binding, performs SSO identity linking (T3-2c), and issues `mnemom_session` via a 302 to the SPA's `redirect_after` path.","tags":["Auth"],"security":[],"parameters":[{"name":"code","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"302":{"description":"Session issued. Redirects to the SPA.","headers":{"Location":{"schema":{"type":"string","format":"uri"}},"Set-Cookie":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/auth/sso/check-domain":{"get":{"operationId":"checkSsoDomain","summary":"Check if email domain has SSO enabled","tags":["Auth"],"security":[],"parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string","format":"email"}}],"responses":{"200":{"description":"SSO domain check result","content":{"application/json":{"schema":{"type":"object","properties":{"sso_enabled":{"type":"boolean"},"org_id":{"type":"string"},"org_name":{"type":"string"},"provider_id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/auth/sso/initiate":{"post":{"operationId":"ssoInitiate","summary":"Begin an SSO login flow","description":"Looks up the SSO provider for the email's domain, generates PKCE + HMAC-signed state, sets a short-lived `mnemom_sso_initiator` cookie, and returns the IdP URL for the SPA to `window.location.href` to.","tags":["Auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"redirect_after":{"type":"string","description":"SPA path to return to after SSO completes (allowlisted)."}}}}}},"responses":{"200":{"description":"IdP URL returned. Also sets `mnemom_sso_initiator` cookie.","headers":{"Set-Cookie":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"}},"required":["url"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/auth/token-exchange":{"post":{"operationId":"tokenExchange","summary":"Exchange a GoTrue refresh token for a mnemom_session cookie","description":"Mirror of `/auth/cli-exchange` in the opposite direction. Called by the SPA after landing on a Supabase implicit-flow redirect (magic-link login), whose session tokens arrive in the URL fragment. The endpoint performs the GoTrue refresh grant server-side — proving possession and consuming the single-use refresh token — then registers a session and sets the HttpOnly `mnemom_session` cookie. JSON-only; no redirect parameter. Rate-limited like sibling auth endpoints.","tags":["Auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["refresh_token"],"properties":{"refresh_token":{"type":"string","description":"GoTrue refresh token from the implicit-flow fragment."}}}}}},"responses":{"200":{"description":"Session established. Sets `mnemom_session`.","headers":{"Set-Cookie":{"schema":{"type":"string"},"description":"HttpOnly `mnemom_session` cookie."}},"content":{"application/json":{"schema":{"type":"object","required":["user","aal"],"properties":{"user":{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"uuid"},"email":{"type":["string","null"],"format":"email"}}},"aal":{"type":"string","enum":["aal1","aal2"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/billing/budget-alert":{"get":{"operationId":"getBudgetAlert","summary":"Get budget alert settings","tags":["Billing"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Budget alert settings","content":{"application/json":{"schema":{"type":"object","properties":{"threshold_cents":{"type":["integer","null"]},"last_alert_sent_at":{"type":["string","null"],"format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"setBudgetAlert","summary":"Set budget alert threshold","tags":["Billing"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"threshold_cents":{"type":["integer","null"],"minimum":0}}}}}},"responses":{"200":{"description":"Budget alert updated","content":{"application/json":{"schema":{"type":"object","properties":{"threshold_cents":{"type":["integer","null"]},"updated":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/billing/cancel":{"post":{"operationId":"cancelSubscription","summary":"Cancel subscription at period end","tags":["Billing"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Cancellation confirmed","content":{"application/json":{"schema":{"type":"object","properties":{"canceled":{"type":"boolean"},"cancel_at_period_end":{"type":"boolean"},"current_period_end":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/billing/change-plan":{"post":{"operationId":"changePlan","summary":"Change subscription plan","tags":["Billing"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["plan_id"],"properties":{"plan_id":{"type":"string"},"annual":{"type":"boolean","default":false}}}}}},"responses":{"200":{"description":"Plan changed","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"boolean"},"plan_id":{"type":"string"},"status":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/billing/checkout":{"post":{"operationId":"createCheckout","summary":"Create Stripe checkout session","tags":["Billing"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["plan_id"],"properties":{"plan_id":{"type":"string"},"annual":{"type":"boolean","default":false},"promo_code":{"type":"string"}}}}}},"responses":{"200":{"description":"Checkout session URL","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"session_id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/billing/export/usage":{"get":{"operationId":"exportUsage","summary":"Export usage data as CSV","tags":["Billing"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date"},"description":"Start date (YYYY-MM-DD)"},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date"},"description":"End date (YYYY-MM-DD)"}],"responses":{"200":{"description":"CSV file","content":{"text/csv":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/billing/features":{"get":{"operationId":"getFeatures","summary":"Get plan feature flags for authenticated user","tags":["Billing"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Plan features","content":{"application/json":{"schema":{"type":"object","properties":{"plan_id":{"type":"string"},"feature_flags":{"type":"object","properties":{"release_ring":{"type":"string"}},"additionalProperties":{"type":"boolean"}},"limits":{"type":"object"},"included_checks":{"type":"integer"},"check_count_this_period":{"type":"integer"},"subscription_status":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/billing/invoices":{"get":{"operationId":"listInvoices","summary":"List invoices","tags":["Billing"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Invoice list","content":{"application/json":{"schema":{"type":"object","properties":{"invoices":{"type":"array","items":{"$ref":"#/components/schemas/Invoice"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/billing/me":{"get":{"operationId":"getMyBilling","summary":"Get authenticated user billing summary","tags":["Billing"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Billing summary","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/billing/mu":{"get":{"x-proxied-url":"MU_PUBLIC_URL","operationId":"getMuBalance","summary":"Get the caller's org mu-engine balance","description":"Returns the mu (metered-unit) ledger balance for the authenticated caller's organization. Requires JWT auth; RBAC is enforced by api before forwarding — the caller must be a member of the target org (defaults to their primary org; an explicit `org_id` query targets a specific org and a non-member is denied 403). api resolves the org's `billing_account_id` server-side and forwards to the frozen mnemom-mu upstream `GET /v1/accounts/{accountId}/balance` — a client-supplied account id is never used. 503 when the mnemom-mu binding/URL is unconfigured (fail-closed).","tags":["Mu"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"org_id","in":"query","required":false,"description":"Target org id. Defaults to the caller's primary org. A caller who is not a member of this org is denied 403.","schema":{"type":"string"}}],"responses":{"200":{"description":"mu ledger balance for the org (mnemom-mu response, passed through verbatim).","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/billing/mu/ledger":{"get":{"x-proxied-url":"MU_PUBLIC_URL","operationId":"getBillingMuLedger","summary":"Read the caller's org mu ledger entries","description":"The customer's own mu account statement: every ledger entry (grant / hold / settle / release / burn / refund / adjustment) with its `lot_allocations` provenance and entry hash. This is what makes purchase RECEIPTS and itemized usage possible — a balance without it is a number with no explanation behind it. Identical org-context + RBAC discipline to `GET /billing/mu`: RBAC is enforced before any read, and the account id is the SERVER-RESOLVED `billing_account_id`, never client-supplied (a NULL one is 409, matching the balance route rather than falling back to a personal account the way the internal resolver does). `cursor` / `from` / `to` / `limit` pass through verbatim to the frozen mnemom-mu upstream `GET /v1/accounts/{accountId}/ledger`, which bounds `limit` itself (default 100, max 500). Read-only by construction: api presents its own `mu:check` service key, which carries no spend or grant scope. 503 when the mnemom-mu binding/URL is unconfigured (fail-closed).","tags":["Mu"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"org_id","in":"query","required":false,"description":"Target org id. Defaults to the caller's primary org. A caller who is not a member of this org is denied 403.","schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"description":"Opaque sequence cursor from a previous page's `nextCursor`.","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"Inclusive lower bound on entry creation time (ISO-8601).","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"description":"Inclusive upper bound on entry creation time (ISO-8601).","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","required":false,"description":"Page size. Upstream clamps to 1..500 (default 100).","schema":{"type":"integer","minimum":1,"maximum":500}}],"responses":{"200":{"description":"A page of ledger entries plus `nextCursor` (mnemom-mu response, passed through verbatim).","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/billing/portal":{"post":{"operationId":"createPortalSession","summary":"Create Stripe billing portal session","tags":["Billing"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Portal session URL","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/billing/reactivate":{"post":{"operationId":"reactivateSubscription","summary":"Reactivate a subscription scheduled for cancellation","tags":["Billing"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Reactivation confirmed","content":{"application/json":{"schema":{"type":"object","properties":{"reactivated":{"type":"boolean"},"cancel_at_period_end":{"type":"boolean"},"status":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/billing/subscription":{"get":{"operationId":"getSubscription","summary":"Get current subscription details","tags":["Billing"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Subscription details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Subscription"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/billing/usage":{"get":{"operationId":"getMyUsage","summary":"Get usage metrics for current user","tags":["Billing"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"days","in":"query","schema":{"type":"integer","default":30,"minimum":1,"maximum":90}}],"responses":{"200":{"description":"Usage data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageMetrics"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/billing/usage/agents":{"get":{"operationId":"getMyAgentUsage","summary":"Get per-agent usage breakdown","tags":["Billing"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"days","in":"query","schema":{"type":"integer","default":30,"minimum":1,"maximum":90}}],"responses":{"200":{"description":"Per-agent usage data","content":{"application/json":{"schema":{"type":"object","required":["agents"],"additionalProperties":true,"description":"`handleGetMyAgentUsage` returns the `get_user_agent_usage` RPC result, an object keyed by `agents` — not a bare array.","properties":{"agents":{"type":"array","description":"Per-agent usage rows for the requested window.","items":{"type":"object","additionalProperties":true,"properties":{"agent_id":{"type":"string"},"check_count":{"type":"integer"},"tokens_in":{"type":"integer"},"tokens_out":{"type":"integer"}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/billing/validate-promo":{"post":{"operationId":"validatePromo","summary":"Validate a promo code","tags":["Billing"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}}}}},"responses":{"200":{"description":"Promo validation result","content":{"application/json":{"schema":{"type":"object","properties":{"valid":{"type":"boolean"},"discount_percent":{"type":["number","null"]},"discount_amount_cents":{"type":["integer","null"]},"name":{"type":["string","null"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/blog/authors/{agent_id}":{"get":{"operationId":"getBlogAuthor","security":[],"summary":"Get author profile and their posts","tags":["Blog"],"parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Author and posts","content":{"application/json":{"schema":{"type":"object","properties":{"author":{"$ref":"#/components/schemas/Agent"},"posts":{"type":"array","items":{"type":"object"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/blog/posts":{"get":{"operationId":"listBlogPosts","security":[],"summary":"List published blog posts","tags":["Blog"],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":20,"minimum":1,"maximum":100}},{"name":"offset","in":"query","schema":{"type":"integer","default":0,"minimum":0}},{"name":"agent_id","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Blog post list","content":{"application/json":{"schema":{"type":"object","properties":{"posts":{"type":"array","items":{"type":"object"}},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"post":{"operationId":"createBlogPost","summary":"Create blog post (service role only)","description":"**Requires ServiceRole authentication.** This endpoint is only accessible to platform administrators with the Supabase service role key. Regular API keys and user tokens cannot access this endpoint.\n\nCreate a new blog post.","tags":["Blog"],"security":[{"ServiceRole":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["agent_id","slug","title","body"],"properties":{"agent_id":{"type":"string"},"slug":{"type":"string","pattern":"^[a-z0-9-]+$"},"title":{"type":"string"},"subtitle":{"type":"string"},"body":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"investigation_session_id":{"type":"string"},"trace_ids":{"type":"array","items":{"type":"string"}},"status":{"type":"string","enum":["draft","published"],"default":"draft"}}}}}},"responses":{"201":{"description":"Post created","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/blog/posts/{slug}":{"get":{"operationId":"getBlogPost","security":[],"summary":"Get single blog post by slug","tags":["Blog"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Blog post with linked traces","content":{"application/json":{"schema":{"type":"object","properties":{"post":{"type":"object"},"linked_traces":{"type":"array","items":{"type":"object"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/catalog/values":{"get":{"operationId":"listCatalogValues","summary":"List the 25 Mnemom catalog values (filterable).","description":"Returns the 25-entry Mnemom value catalog v1 — the trans-industry universal value primitives. SDK consumers + dashboards use this for pickable lists and grouping. The runtime catalog is vendored in-process (no DB call); responses are highly cacheable (5-minute TTL with stale-while-revalidate). cards-as-primitive Phase 4 W2.4.","tags":["Catalog"],"security":[],"parameters":[{"name":"axis","in":"query","required":false,"schema":{"type":"string","maxLength":64},"description":"Filter to entries on this behavioral axis (e.g., `speed↔caution`)."},{"name":"category","in":"query","required":false,"schema":{"type":"string","enum":["cognitive","operational","relational","stewardship","identity","confidentiality"]},"description":"Filter to one of the six catalog categories."},{"name":"gateway_hookable","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]},"description":"When `true`, return only entries the dispatcher binds to a gateway hook."}],"responses":{"200":{"description":"Catalog list — `data[]` plus `count` and `total`.","headers":{"Cache-Control":{"description":"`public, max-age=300, stale-while-revalidate=600`.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Always `catalog-values-list/v1`.","schema":{"type":"string","enum":["catalog-values-list/v1"]}}},"content":{"application/json":{"schema":{"type":"object","required":["data","count","total","catalog_version"],"properties":{"data":{"type":"array","items":{"type":"object","required":["id","axis","polarity","parameters","plain_definition","category","gateway_hookable"],"properties":{"id":{"type":"string","description":"Stable kebab-case identifier — the contract."},"axis":{"type":"string","description":"Where in the behavioral space the value sits (e.g., `\"speed↔caution\"`)."},"polarity":{"type":"string","enum":["positive","negative"],"description":"Whether the value is a do-this (positive) or don’t-do-that (negative)."},"parameters":{"type":"array","items":{"type":"string","enum":["domain","intensity","severity_on_violation","scope"]},"description":"Which manifest parameters this entry accepts."},"plain_definition":{"type":"string","description":"Care-framed prose definition (interpretive; translates per-locale)."},"category":{"type":"string","enum":["cognitive","operational","relational","stewardship","identity","confidentiality"]},"gateway_hookable":{"type":"boolean","description":"Whether the dispatcher binds this entry to a gateway hook."},"gateway_hook_disposition":{"type":["string","null"],"description":"Pass-2 detail — the gateway hook predicate disposition when applicable. `null` until mnemom-contracts publishes Pass-2 for this entry."},"observer_signals":{"type":["array","null"],"items":{"type":"string"},"description":"Pass-2 detail — the observer signals this entry binds on. `null` until Pass-2 ships."},"care_frame_template":{"type":["string","null"],"description":"Pass-2 detail — the care-framed error template when this entry fires. `null` until Pass-2 ships."}}}},"count":{"type":"integer","minimum":0},"total":{"type":"integer","minimum":0},"catalog_version":{"type":"string","enum":["v1"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/catalog/values/{id}":{"get":{"operationId":"getCatalogValue","summary":"Get a single catalog entry by id.","description":"Returns one entry from the Mnemom value catalog v1 by its stable kebab-case id. cards-as-primitive Phase 4 W2.4.","tags":["Catalog"],"security":[],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z][a-z0-9_]*$"},"description":"Stable catalog entry id (e.g., `policy_attentiveness`)."}],"responses":{"200":{"description":"Single catalog entry.","headers":{"Cache-Control":{"schema":{"type":"string"}},"X-Mnemom-Schema":{"schema":{"type":"string","enum":["catalog-value/v1"]}}},"content":{"application/json":{"schema":{"type":"object","required":["id","axis","polarity","parameters","plain_definition","category","gateway_hookable"],"properties":{"id":{"type":"string","description":"Stable kebab-case identifier — the contract."},"axis":{"type":"string","description":"Where in the behavioral space the value sits (e.g., `\"speed↔caution\"`)."},"polarity":{"type":"string","enum":["positive","negative"],"description":"Whether the value is a do-this (positive) or don’t-do-that (negative)."},"parameters":{"type":"array","items":{"type":"string","enum":["domain","intensity","severity_on_violation","scope"]},"description":"Which manifest parameters this entry accepts."},"plain_definition":{"type":"string","description":"Care-framed prose definition (interpretive; translates per-locale)."},"category":{"type":"string","enum":["cognitive","operational","relational","stewardship","identity","confidentiality"]},"gateway_hookable":{"type":"boolean","description":"Whether the dispatcher binds this entry to a gateway hook."},"gateway_hook_disposition":{"type":["string","null"],"description":"Pass-2 detail — the gateway hook predicate disposition when applicable. `null` until mnemom-contracts publishes Pass-2 for this entry."},"observer_signals":{"type":["array","null"],"items":{"type":"string"},"description":"Pass-2 detail — the observer signals this entry binds on. `null` until Pass-2 ships."},"care_frame_template":{"type":["string","null"],"description":"Pass-2 detail — the care-framed error template when this entry fires. `null` until Pass-2 ships."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/checkpoints/{checkpoint_id}/certificate":{"get":{"operationId":"getCheckpointCertificate","summary":"Get integrity certificate","description":"Retrieve or reconstruct the IntegrityCertificate for a checkpoint. Includes signature, chain proof, Merkle inclusion proof (if available), and verdict derivation proof (if completed). Public endpoint, no authentication required.","tags":["Verification"],"security":[{}],"parameters":[{"name":"checkpoint_id","in":"path","required":true,"schema":{"type":"string"},"description":"The checkpoint ID (ic-{uuid} format)"}],"responses":{"200":{"description":"The integrity certificate","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrityCertificate"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/checkpoints/{checkpoint_id}/inclusion-proof":{"get":{"operationId":"getInclusionProof","summary":"Get inclusion proof","description":"Generate and return a Merkle inclusion proof for a checkpoint. The proof contains O(log N) sibling hashes sufficient to recompute the Merkle root, proving the checkpoint is included in the agent's complete checkpoint history. Public endpoint, no authentication required.","tags":["Verification"],"security":[{}],"parameters":[{"name":"checkpoint_id","in":"path","required":true,"schema":{"type":"string"},"description":"The checkpoint ID (ic-{uuid} format)"}],"responses":{"200":{"description":"Merkle inclusion proof","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InclusionProofResponse"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/checkpoints/{checkpoint_id}/proof":{"get":{"operationId":"getProofStatus","summary":"Get proof status","description":"Get the ZK proof status and data for a checkpoint. Returns the most recent proof record including status, proof type, verification result, and timing metadata. Public endpoint, no authentication required.","tags":["Verification"],"security":[{}],"parameters":[{"name":"checkpoint_id","in":"path","required":true,"schema":{"type":"string"},"description":"The checkpoint ID (ic-{uuid} format)"}],"responses":{"200":{"description":"Proof status and data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProofStatusResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/checkpoints/{checkpoint_id}/prove":{"post":{"operationId":"requestZkProof","summary":"Request ZK proof","description":"Request a zero-knowledge proof for a checkpoint's verdict derivation. If a proof already exists, returns its current status. Otherwise, creates a pending proof request and dispatches it to the SP1 prover service. Requires API key authentication.","tags":["Verification"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"checkpoint_id","in":"path","required":true,"schema":{"type":"string"},"description":"The checkpoint ID (ic-{uuid} format)"}],"responses":{"200":{"description":"Proof already exists for this checkpoint","content":{"application/json":{"schema":{"type":"object","properties":{"proof_id":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"}}}}}},"202":{"description":"Proof request accepted","content":{"application/json":{"schema":{"type":"object","properties":{"proof_id":{"type":"string","description":"Proof identifier (prf-{8 random chars})"},"status":{"type":"string","enum":["queued"],"description":"Initial status"},"estimated_completion_ms":{"type":"integer","description":"Estimated time to completion in milliseconds"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/coherence/claim-intent":{"post":{"operationId":"createCoherenceClaimIntent","summary":"Mint a single-use coherence claim-intent ticket (anonymous).","description":"The coherence report-claim flow (MNE-1379). A LOGGED-OUT viewer of a Coherence report who clicks \"Claim your report\" and creates an account receives a short-lived, single-use, opaque ticket (`mci_…`) scope-bound to `{report_slug, intent: enroll_passkey}`. That ticket — NOT a session token or cookie — is the only value that rides the sign-up → email-confirm → return round-trip on the URL, so nothing sensitive lands in the URL, the confirmation email, or browser localStorage. There is NO proof at mint: the report is publicly viewable (the slug is not a secret), so the authorization for the claim is the email-confirmation round-trip the user must complete to reach the authed exchange (proof of control of the email the report binds to). Intentionally public (`security: []`), the same posture as `/dojo/claim-intent`. Exchange the ticket via `POST /coherence/claim-intent/exchange` once authenticated.","tags":["Coherence"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["report_slug"],"properties":{"report_slug":{"type":"string","pattern":"^[A-Za-z0-9_-]{16}$","description":"The Coherence report slug to bind the claim to (16 URL-safe chars). Carried through the round-trip so the claim page can resume the ceremony on the authenticated return."}}}}}},"responses":{"201":{"description":"A single-use claim-intent ticket.","content":{"application/json":{"schema":{"type":"object","required":["intent_token","expires_at"],"properties":{"intent_token":{"type":"string","description":"Opaque single-use ticket (`mci_…`). Present it to the exchange. Never a session token."},"expires_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/coherence/claim-intent/exchange":{"post":{"operationId":"exchangeCoherenceClaimIntent","summary":"Exchange a coherence claim-intent ticket (authed).","description":"The freshly-authenticated first-timer — returned to the claim page by the email-confirmation callback, which set the HttpOnly mnemom_session cookie this exchange resolves SERVER-SIDE — presents the ticket minted by `POST /coherence/claim-intent`. The ticket is atomically consumed (single-use) and the scope-bound `{report_slug, intent}` is returned so the claim page can resume the enroll → step-up → claim ceremony with a REAL session (instead of the doomed immediate enroll that 401'd). The session is the only authority here — never a token on the URL. MNE-1379.","tags":["Coherence"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["intent_token"],"properties":{"intent_token":{"type":"string","description":"The opaque single-use ticket (`mci_…`) from the mint step."}}}}}},"responses":{"200":{"description":"The scope-bound claim target to resume.","content":{"application/json":{"schema":{"type":"object","required":["report_slug","intent"],"properties":{"report_slug":{"type":"string"},"intent":{"type":"string","description":"The scope-bound intent the ticket grants (e.g. `enroll_passkey`)."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"410":{"$ref":"#/components/responses/Gone"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/compliance/safe-house-report":{"get":{"operationId":"safeHouseComplianceReport","summary":"Compliance-formatted Safe House report","description":"Phase-7 compliance report combining aggregate detection stats, retention state, and GDPR/SOC2-friendly formatting.","tags":["Safe House"],"responses":{"200":{"description":"Report.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/consent":{"post":{"operationId":"recordConsentDecision","summary":"Record a consent decision (append-only)","description":"Public, unauthenticated. Appends ONE immutable GDPR consent audit record per decision (GDPR Art. 7(1)). The consent banner POSTs each choice here; this is IN ADDITION to client-side enforcement, never a replacement. PII-minimised: stores a pseudonymous `subject_id` and a TRUNCATED IP (last IPv4 octet / last 80 IPv6 bits zeroed) only — no email, name, raw IP, or user id. `region` is read server-side from the `mnemom_geo` cookie; GPC/DNT presence is detected from `Sec-GPC`/`DNT` headers (OR'd with the body `gpc` flag). Malformed input is rejected with 400. Rate-limited per IP.","tags":["Consent"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["subject_id","action"],"properties":{"subject_id":{"type":"string","maxLength":128,"description":"Pseudonymous client/session id (the same opaque id the consent-store keeps locally). NOT raw PII."},"action":{"type":"string","enum":["accept_all","reject_all","save_preferences","withdraw"]},"categories":{"type":"object","description":"Consented toggles. `essential` is always-on and recorded as true regardless.","properties":{"analytics":{"type":"boolean"},"marketing":{"type":"boolean"}}},"consent_string":{"type":"string","maxLength":512,"nullable":true},"schema_version":{"type":"string","maxLength":64,"nullable":true},"gpc":{"type":"boolean","description":"Client-observed GPC/DNT signal (OR'd with the request's Sec-GPC / DNT headers)."},"decided_at":{"type":"string","format":"date-time","description":"ISO-8601 timestamp of the client decision."}}}}}},"responses":{"201":{"description":"Consent decision recorded.","content":{"application/json":{"schema":{"type":"object","required":["recorded"],"properties":{"recorded":{"type":"boolean"},"id":{"type":"string","format":"uuid","nullable":true},"created_at":{"type":"string","format":"date-time","nullable":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/InternalServerError"}}}},"/consent/export":{"get":{"operationId":"exportConsentLog","summary":"Export the consent log for a time window (admin)","description":"Admin-only. Returns all consent audit records in a REQUIRED `[from, to]` time window (oldest first) for producing records to a supervisory authority. No full-table export is permitted (both bounds required). Requires platform admin role.","tags":["Consent"],"security":[{"BearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"description":"Inclusive lower bound (ISO-8601). Required."},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"description":"Inclusive upper bound (ISO-8601). Required."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":5000,"maximum":50000}}],"responses":{"200":{"description":"Consent records in the requested window.","content":{"application/json":{"schema":{"type":"object","required":["from","to","count","records"],"properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"},"count":{"type":"integer"},"records":{"type":"array","items":{"type":"object","required":["id","created_at","subject_id","action"],"properties":{"id":{"type":"string","format":"uuid"},"created_at":{"type":"string","format":"date-time"},"decided_at":{"type":"string","format":"date-time","nullable":true},"subject_id":{"type":"string","description":"Pseudonymous client-generated id. NOT raw PII."},"action":{"type":"string","enum":["accept_all","reject_all","save_preferences","withdraw"]},"essential":{"type":"boolean"},"analytics":{"type":"boolean"},"marketing":{"type":"boolean"},"consent_string":{"type":"string","nullable":true},"schema_version":{"type":"string","nullable":true},"region":{"type":"string","nullable":true},"gpc_dnt_present":{"type":"boolean"},"ip_truncated":{"type":"string","nullable":true,"description":"Proportionate network id only (last IPv4 octet / last 80 IPv6 bits zeroed)."},"user_agent":{"type":"string","nullable":true}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/InternalServerError"}}}},"/consent/history":{"get":{"operationId":"getConsentHistory","summary":"Read a subject's consent history (admin)","description":"Admin-only. Returns the consent decisions for a given pseudonymous `subject_id`, newest first, optionally bounded to a `[from, to]` time window. Used to demonstrate consent for a specific subject. Requires platform admin role.","tags":["Consent"],"security":[{"BearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"subject_id","in":"query","required":true,"schema":{"type":"string"},"description":"The pseudonymous subject id to look up."},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Inclusive lower bound (ISO-8601). Unbounded if omitted."},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Inclusive upper bound (ISO-8601). Unbounded if omitted."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":500,"maximum":5000}}],"responses":{"200":{"description":"The subject's consent decisions.","content":{"application/json":{"schema":{"type":"object","required":["subject_id","count","records"],"properties":{"subject_id":{"type":"string"},"count":{"type":"integer"},"records":{"type":"array","items":{"type":"object","required":["id","created_at","subject_id","action"],"properties":{"id":{"type":"string","format":"uuid"},"created_at":{"type":"string","format":"date-time"},"decided_at":{"type":"string","format":"date-time","nullable":true},"subject_id":{"type":"string","description":"Pseudonymous client-generated id. NOT raw PII."},"action":{"type":"string","enum":["accept_all","reject_all","save_preferences","withdraw"]},"essential":{"type":"boolean"},"analytics":{"type":"boolean"},"marketing":{"type":"boolean"},"consent_string":{"type":"string","nullable":true},"schema_version":{"type":"string","nullable":true},"region":{"type":"string","nullable":true},"gpc_dnt_present":{"type":"boolean"},"ip_truncated":{"type":"string","nullable":true,"description":"Proportionate network id only (last IPv4 octet / last 80 IPv6 bits zeroed)."},"user_agent":{"type":"string","nullable":true}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/InternalServerError"}}}},"/contact/submit":{"post":{"operationId":"submitContact","summary":"Proxied HubSpot Forms submission (non-enterprise contact + newsletter)","description":"Server-side replacement for the old browser→HubSpot Forms submission. Routes /contact (general/support/privacy) and newsletter signups through the Worker so they're gated by the anti-spam guard (honeypot + strict email/char/length validation + optional Cloudflare Turnstile verification) before anything reaches HubSpot. `form_type=contact` requires a Turnstile token (once `TURNSTILE_SECRET_KEY` is set on the Worker); `form_type=newsletter` runs honeypot + validation only. On success the Worker also performs the CRM upsert + hot-lead Slack alert (same as /contact/notify). Returns a non-2xx so the UI can keep the form open on rejection.","tags":["Misc"],"security":[],"x-rate-limit":"publicRateLimit","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"form_type":{"type":"string","enum":["contact","newsletter"],"description":"Which HubSpot form to submit. Defaults to `contact`. `contact` requires a Turnstile token when the Worker has TURNSTILE_SECRET_KEY set; `newsletter` does not."},"email":{"type":"string","format":"email","description":"Contact email address (required)."},"name":{"type":"string","description":"Contact's display name; split into firstname/lastname on the HubSpot side."},"reason":{"type":"string","description":"Contact-form reason (general/support/privacy). Stored as the HubSpot `contact_reason` field."},"message":{"type":"string","description":"Free-form message body."},"source":{"type":"string","description":"Origin surface. Defaults to `contact_page` for form_type=contact and `newsletter` for form_type=newsletter.","examples":["contact_page","newsletter","newsletter_blog_post"]},"turnstile_token":{"type":"string","description":"Cloudflare Turnstile token from the website widget. Required when form_type=contact AND the Worker has TURNSTILE_SECRET_KEY set; ignored otherwise."},"company_website":{"type":"string","description":"Honeypot — must be empty. Real users never see the field; any non-empty value silently rejects the submission as bot traffic."},"context":{"type":"object","description":"Optional HubSpot form context forwarded to the Forms API (preserves hutk / page attribution).","properties":{"hutk":{"type":"string","description":"HubSpot tracking cookie (hubspotutk)."},"pageUri":{"type":"string","description":"URL the form was submitted from."},"pageName":{"type":"string","description":"document.title of the submitting page."}}},"utms":{"type":"object","description":"UTM parameters merged into the HubSpot form fields for attribution.","additionalProperties":{"type":"string"}},"engagement":{"type":"object","description":"Optional engagement telemetry used for hot-lead scoring (same shape as /contact/notify).","additionalProperties":true}}}}}},"responses":{"200":{"description":"Submission accepted. The Worker performed the HubSpot Forms submission and the CRM upsert + Slack alert.","content":{"application/json":{"schema":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean","const":true},"notified":{"type":"boolean","description":"True only when the hot-lead Slack alert fired."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"description":"Anti-spam guard rejected the submission (Turnstile failed / required token missing).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Too many requests"}}}},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"description":"Upstream HubSpot Forms submission failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/decisions/{decision_id}/certificate":{"get":{"operationId":"getDecisionCertificate","summary":"Get a signed Safe House decision certificate","description":"The public, offline-verifiable certificate for a signed SafeHouseDecision (MNE-1381 / C14): the reconstructed canonical decision (covered fields + provenance) plus the exact signed_payload string, so a third party can recompute the chain hash, rebuild the payload, and check the Ed25519 signature against the public key from GET /v1/keys — without trusting this API. 404 when the decision is not signed. Public endpoint, no authentication required.","tags":["Verification"],"security":[{}],"parameters":[{"name":"decision_id","in":"path","required":true,"schema":{"type":"string"},"description":"The safe_house_decisions row id (uuid)"}],"responses":{"200":{"description":"The decision certificate","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"type":{"type":"string"},"version":{"type":"string"},"certificate_id":{"type":"string"},"subject":{"type":"object","additionalProperties":true},"decision":{"type":"object","additionalProperties":true},"proofs":{"type":"object","additionalProperties":true},"issued_at":{"type":"string"}},"required":["type","version","certificate_id","proofs"]}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/decisions/{decision_id}/verify":{"get":{"operationId":"verifyDecision","summary":"Verify a signed Safe House decision","description":"Independently verify a persisted canonical SafeHouseDecision's Ed25519 signature and per-(agent, run) hash chain (MNE-1381 / C14). Reconstructs the decision from its row and delegates to the shared verifySafeHouseDecision core: a tampered covered field or prev_hash breaks the chain recompute; a forged/absent-key signature breaks the Ed25519 check — both surface as verified:false (a successful answer, not an error). Public endpoint, no authentication required.","tags":["Verification"],"security":[{}],"parameters":[{"name":"decision_id","in":"path","required":true,"schema":{"type":"string"},"description":"The safe_house_decisions row id (uuid)"}],"responses":{"200":{"description":"The verification result (verified true/false + per-check detail)","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"verified":{"type":"boolean"},"decision_id":{"type":"string"},"signing_key_id":{"type":"string","nullable":true},"chain_hash":{"type":"string","nullable":true},"prev_hash":{"type":"string","nullable":true},"checks":{"type":"object","properties":{"signature":{"type":"object","properties":{"valid":{"type":"boolean"}}},"chain":{"type":"object","properties":{"valid":{"type":"boolean"}}}}},"reason":{"type":"string"}},"required":["verified","decision_id","checks"]}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/deployments/heartbeat":{"post":{"operationId":"deploymentHeartbeat","summary":"Self-hosted deployment heartbeat","description":"Called periodically by a self-hosted Mnemom instance to report liveness, version, and metadata back to the managed control plane. Uses a **License JWT** bearer token (not a user JWT) — the token is issued during license validation. The response includes `next_heartbeat_seconds` telling the instance when to call back.","tags":["Licensing"],"security":[{"LicenseJwtAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["deployment_id","instance_id"],"properties":{"deployment_id":{"type":"string"},"instance_id":{"type":"string"},"version":{"type":"string"},"heartbeat_data":{"type":"object","additionalProperties":true,"description":"Free-form liveness telemetry (uptime, resource usage, component versions …)."}}}}}},"responses":{"200":{"description":"Heartbeat accepted.","content":{"application/json":{"schema":{"type":"object","required":["deployment_id","status","next_heartbeat_seconds","server_time"],"properties":{"deployment_id":{"type":"string"},"status":{"type":"string","enum":["active","inactive","degraded"]},"next_heartbeat_seconds":{"type":"integer","default":300},"server_time":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/dojo/claim-intent":{"post":{"operationId":"createDojoClaimIntent","summary":"Mint a single-use claim-intent ticket (anonymous, birth-token proof).","description":"The true-first-timer claim flow (MNE-879). A LOGGED-OUT user who opens a dojo claim link proves ownership with the birth token (`mnbt_…`) / hash proof and receives a short-lived, single-use, opaque ticket (`mci_…`). That ticket — NOT the secret proof — rides the sign-up → email-confirm → return round-trip, so nothing sensitive lands in the URL, the confirmation email, or browser localStorage (which is gone when the email opens on another device — the exact reason a first-timer claimed an agent but it never bound to its dojo config). The proof is verified HERE and never stored; the ticket is the post-verification capability. Intentionally public (`security: []`) — the birth-token proof IS the authorization, the same posture as `/dojo/try-me/resolve`. Exchange the ticket via `POST /dojo/claim-intent/exchange` once authenticated.","tags":["Dojo"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["agent_id","hash_proof"],"properties":{"agent_id":{"type":"string","description":"The agent (`mnm-…`) being claimed."},"hash_proof":{"type":"string","description":"Ownership proof — the live birth token (`mnbt_…`) whose row pins this agent's hash, or the full 64-hex `SHA-256(apiKey|name)` proof. Verified at mint; never stored."},"dojo_config_id":{"type":"string","format":"uuid","description":"Optional — the TryMeConfig to bind the agent to at exchange (the claim link's `&dojo_config`). Carried through the round-trip so the bind can't be lost."}}}}}},"responses":{"201":{"description":"A single-use claim-intent ticket.","content":{"application/json":{"schema":{"type":"object","required":["intent_token","expires_at"],"properties":{"intent_token":{"type":"string","description":"Opaque single-use ticket (`mci_…`). Present it to the exchange."},"expires_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/dojo/claim-intent/exchange":{"post":{"operationId":"exchangeDojoClaimIntent","summary":"Exchange a claim-intent ticket — claim + bind (authed).","description":"The freshly-authenticated first-timer presents the ticket minted by `POST /dojo/claim-intent`. The ticket is atomically consumed (single-use), the agent is claimed into the caller's PERSONAL org (dojo invites are personal by design — the same claim-to-org core as `POST /agents/{id}/claim`, with NO re-proof: the ticket is the capability), and the agent is bound to its dojo config — the step that silently no-op'd before, leaving the agent claimed but invisible in the dojo. One server-side operation replaces the fragile claim→link→bind dance. MNE-879.","tags":["Dojo"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["intent_token"],"properties":{"intent_token":{"type":"string","description":"The opaque single-use ticket (`mci_…`) from the mint step."}}}}}},"responses":{"200":{"description":"Claim + bind result.","content":{"application/json":{"schema":{"type":"object","required":["claimed","bound","agent_id"],"properties":{"claimed":{"type":"boolean"},"bound":{"type":"boolean","description":"Whether the agent was bound to a dojo config (false if the ticket carried none)."},"bind_error":{"type":"string","enum":["invalid_input","not_found","forbidden","write_refused","error"],"description":"Present ONLY when a dojo config was named and the bind did not land — names WHY, so a `bound:false` is diagnosable instead of silent. The claim itself still succeeded (`claimed:true`), so this is not an error status; re-try the bind via `POST /dojo/try-me/bind-agent`."},"agent_id":{"type":"string"},"dojo_config_id":{"type":"string","nullable":true},"org_id":{"type":"string","nullable":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"410":{"$ref":"#/components/responses/Gone"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/dojo/compute-keys":{"post":{"operationId":"issueDojoComputeKey","summary":"Mint an ephemeral compute/operate key (gateway + api:read + api:write).","description":"Mints a Mnemom-provided, ephemeral API key carrying `gateway` + `api:read` + `api:write` (the standard-key default; no admin scopes), hung off the dedicated `dojo-system` billing account (not tied to ownership). `gateway` lets the runner act AS the agent through the prod gateway; `api:read`/`api:write` let the agent authenticate to mnemom-api MCP routes during onboarding (BE BORN / DECLARE) — a `gateway`-only key would 401 on every MCP call. The cleartext key is returned ONCE. Optionally bound to a TryMeConfig (sets its `compute_key_ref`). Admin-only — backs the `/admin/dojo` control surface. MNE-517 §2 / MNE-519.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"try_me_config_id":{"type":"string","format":"uuid"},"label":{"type":"string","maxLength":100}}}}}},"responses":{"201":{"description":"Compute key minted. The `key` is shown exactly once.","content":{"application/json":{"schema":{"type":"object","required":["key_id","key","key_prefix","scopes","account_id","created_at"],"properties":{"key_id":{"type":"string"},"key":{"type":"string","description":"Full cleartext key — shown once."},"key_prefix":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"account_id":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/dojo/my-agents":{"get":{"operationId":"listMyDojoAgents","summary":"List the caller's dojo agents + dojo_enabled flag.","description":"Returns the authed caller's DOJO agents — agents they own (`created_by`/`claimed_by`) that are bound to a `dojo_try_me_configs` row (born/claimed through try-me). Backs the `/dashboard/dojo` visibility gate (`dojo_enabled` = owns ≥1) AND the agent selector (`agents`). Pass `org_id` to scope to the active org's fleet (ADR-062) — the dashboard does this so the dojo only shows under an org where you own a dojo agent; omit it for the legacy org-agnostic listing. No admin bypass — visibility derives purely from owning a dojo agent. MNE-517.","tags":["Dojo"],"parameters":[{"name":"org_id","in":"query","required":false,"schema":{"type":"string"},"description":"Optional active-org scope. When set, restrict to the caller's dojo agents whose `agents.org_id` matches (the dashboard passes its active org so the dojo gate follows org context)."}],"responses":{"200":{"description":"The caller's dojo agents.","content":{"application/json":{"schema":{"type":"object","required":["dojo_enabled","agents"],"properties":{"dojo_enabled":{"type":"boolean","description":"True iff the caller owns ≥1 dojo agent (within `org_id` when supplied)."},"agents":{"type":"array","items":{"type":"object","required":["agent_id","scenario_id","dojo_config_id","model_provider"],"properties":{"agent_id":{"type":"string","description":"prod agents.id (mnm-…)."},"name":{"type":["string","null"]},"scenario_id":{"type":"string"},"dojo_config_id":{"type":"string","format":"uuid"},"model_provider":{"type":"string","enum":["anthropic","openai","google"]}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/dojo/provider-keys":{"put":{"operationId":"putDojoProviderKey","summary":"Set the dojo provider API key for a provider (admin-only).","description":"Upserts ONE dojo provider key for a provider (anthropic/openai/google) on the `dojo-system` account. Under the BYOK identity model the agent's gateway identity is `SHA256(providerKey | name)`, so the demo hands the born agent a real provider key and the runner spars AS that same agent with the SAME key. The cleartext is AES-256-GCM-encrypted at rest and resolved server-side ONLY (`resolveDojoProviderKey`); it is NEVER returned. Admin-only — backs `/admin/dojo`. MNE-517 (BYOK pivot).","tags":["Dojo"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["provider","key"],"properties":{"provider":{"type":"string","enum":["anthropic","openai","google"]},"key":{"type":"string","minLength":8,"description":"The provider API key (cleartext) — encrypted at rest, never echoed."},"key_ref":{"type":"string","description":"Optional human label."}}}}}},"responses":{"200":{"description":"Provider key stored. Returns non-secret metadata only.","content":{"application/json":{"schema":{"type":"object","required":["provider","key_prefix","updated_at"],"properties":{"provider":{"type":"string","enum":["anthropic","openai","google"]},"key_prefix":{"type":"string","description":"Non-secret leading characters, for display."},"key_ref":{"type":["string","null"]},"updated_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"get":{"operationId":"listDojoProviderKeys","summary":"List configured dojo provider keys (admin-only, non-secret metadata).","description":"Lists which providers have a dojo provider key configured, with non-secret metadata (provider, key_prefix, key_ref, updated_by, timestamps). NEVER returns the ciphertext or cleartext. Admin-only. MNE-517 (BYOK pivot).","tags":["Dojo"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"The configured providers and their non-secret metadata.","content":{"application/json":{"schema":{"type":"object","required":["provider_keys"],"properties":{"provider_keys":{"type":"array","items":{"type":"object","properties":{"provider":{"type":"string","enum":["anthropic","openai","google"]},"key_prefix":{"type":["string","null"]},"key_ref":{"type":["string","null"]},"updated_by":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/dojo/receipt/verify":{"post":{"operationId":"verifyDojoReceipt","summary":"Verify a Dojo completion receipt against the published JWKS.","description":"PUBLIC — in-band Ed25519 verification of a posted completion-receipt JWS against the CURRENTLY published JWKS (`/v1/.well-known/jwks.json`; active + retired-window keys). Returns the structured verdict (`valid`, `payload`, `key_id`, `errors`). A bad / tampered / expired receipt is `valid:false` with the failing checks enumerated — the endpoint itself is still 200 (the verification ran). 'Verify, don't trust': the same check can be run offline against the public key. MNE-802.","tags":["Dojo"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["receipt"],"properties":{"receipt":{"type":"string","description":"The receipt JWS Compact serialization to verify."}}}}}},"responses":{"200":{"description":"The structured verification verdict (valid:true/false).","content":{"application/json":{"schema":{"type":"object","required":["valid","key_id","payload","errors"],"properties":{"valid":{"type":"boolean"},"key_id":{"type":"string","nullable":true},"payload":{"type":"object","nullable":true,"additionalProperties":true,"description":"The receipt's decoded payload. On `valid:true` this is a full `DojoCompletionReceipt/v1` payload (the shape of `receiptResponseSchema.payload`). On `valid:false` it is the BEST-EFFORT decoded payload — untrusted and possibly partial or arbitrary (whatever the presented, unverified JWS decoded to) — echoed for diagnostics, so it is intentionally NOT constrained to the strict receipt shape (a tampered/bogus receipt must still surface as a 200 `valid:false`, never a 500). `null` when the JWS could not be parsed at all."},"errors":{"type":"array","items":{"type":"string"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/dojo/receipt/{session_id}":{"get":{"operationId":"getDojoReceipt","summary":"Issue the signed completion receipt for a finished Dojo run.","description":"PUBLIC — the `session_id` is the credential (a shareable permalink). Returns the Ed25519-signed completion receipt for a COMPLETED dojo try-me run: it declares the agent's alignment/protection cards (by canonical content-hash) and the Safe House (sparring) verdict, plus a verify pointer. The receipt is DERIVED deterministically from the completed session + its scenario (not stored) and is independently verifiable against the published JWKS. Reveals only the shareable claim — no raw transcript/event stream (that stays behind the owner-gated `/sim/{id}/export`). 409 if the run hasn't completed; 503 if signing isn't configured. MNE-802.","tags":["Dojo"],"security":[],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string"},"description":"The completed dojo sim session id."}],"responses":{"200":{"description":"The signed receipt + verify pointer.","content":{"application/json":{"schema":{"type":"object","required":["receipt","payload","key_id","permalink","verify"],"properties":{"receipt":{"type":"string","description":"The Ed25519-signed receipt as a JWS Compact serialization."},"payload":{"type":"object","required":["typ","iss","sub","iat","exp","session_id","scenario_id","declared","verdict","completed_at"],"properties":{"typ":{"type":"string","enum":["DojoCompletionReceipt/v1"]},"iss":{"type":"string","description":"Issuer; `https://mnemom.ai`."},"sub":{"type":"string","description":"The agent that ran the spar (agents.id)."},"iat":{"type":"integer","description":"Issued-at, Unix seconds."},"exp":{"type":"integer","description":"Expiry, Unix seconds."},"session_id":{"type":"string"},"scenario_id":{"type":"string"},"declared":{"type":"object","description":"The agent's declared cards, by canonical content-hash.","required":["alignment_card_hash","protection_card_hash"],"properties":{"alignment_card_hash":{"type":"string","nullable":true,"description":"sha256-hex of the canonical alignment card, or null."},"protection_card_hash":{"type":"string","nullable":true,"description":"sha256-hex of the canonical protection card, or null."}}},"verdict":{"type":"object","description":"The Safe House (sparring) verdict.","required":["outcome","canary_protected","leak","contagion","rating"],"properties":{"outcome":{"type":"string","enum":["pass","leak","contagion"],"description":"The single canonical outcome, worst-first: contagion (unauthorized write) > leak (unauthorized read) > pass (shield held)."},"canary_protected":{"type":"boolean"},"leak":{"type":"boolean"},"contagion":{"type":"boolean"},"rating":{"type":"string","nullable":true}}},"completed_at":{"type":"string","format":"date-time"}}},"key_id":{"type":"string","description":"The kid that signed the receipt."},"permalink":{"type":"string","format":"uri"},"verify":{"type":"object","required":["endpoint","jwks","note"],"properties":{"endpoint":{"type":"string","format":"uri"},"jwks":{"type":"string","format":"uri"},"note":{"type":"string"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/dojo/safe-house-posture":{"get":{"operationId":"getDojoSafeHousePosture","summary":"Per-run Safe House detector posture (staff-only).","description":"Returns a run's Safe House detector posture — the WORST `health` across the run's canonical safe_house_decisions (tool_call ∪ tool_response), plus screened/expected and an alarm flag. The dashboard self-fetches this so a degraded / failed-open sensor never renders green (the MNE-913 fail-open-looks-healthy class; C6 AC2). Admin-only; fail-CLOSED — a read error is a 500, never a fake-clean posture. MNE-1347.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"agent","in":"query","required":true,"schema":{"type":"string"},"description":"The agent id (mnm-…)."},{"name":"run","in":"query","required":false,"schema":{"type":"string"},"description":"Optional gateway run id (x-mnemom-session). Omit for agent-only posture (the most recent run) — the dashboard has the agent id but NOT the gateway run id (different id-space)."}],"responses":{"200":{"description":"The run's detector posture.","content":{"application/json":{"schema":{"type":"object","required":["posture","source"],"properties":{"posture":{"type":"object","required":["health","screened","expected","alarm"],"properties":{"health":{"type":"string","enum":["ran","degraded","failed_open"]},"screened":{"type":"integer"},"expected":{"type":"integer"},"alarm":{"type":"boolean"}}},"source":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/dojo/scenarios":{"get":{"operationId":"listDojoScenarios","summary":"List Dojo scenarios for the How-it-works modal.","description":"Returns all Dojo scenarios with their human-facing briefing: name, description, the GOOD alignment + protection cards, and the agent-facing `setup_prompt` (computed live from the scenario). Authed for ALL users (any valid Bearer/API key) — read-only, non-secret briefing content. MNE-517.","tags":["Dojo"],"responses":{"200":{"description":"The list of scenario briefings.","content":{"application/json":{"schema":{"type":"object","required":["scenarios"],"properties":{"scenarios":{"type":"array","items":{"type":"object","required":["scenario_id","name","alignment_card","protection_card","setup_prompt"],"properties":{"scenario_id":{"type":"string","description":"Scenario slug (e.g. 'db-shepherd')."},"name":{"type":"string"},"description":{"type":["string","null"],"description":"Human-facing blurb."},"alignment_card":{"type":"object","additionalProperties":true},"protection_card":{"type":"object","additionalProperties":true},"setup_prompt":{"type":"string","description":"Agent-facing self-setup copy, computed from the scenario row."}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/dojo/scenarios/{id}":{"get":{"operationId":"getDojoScenario","summary":"Get one Dojo scenario by slug (How-it-works modal).","description":"Returns a single Dojo scenario briefing by slug (name, description, GOOD cards, computed `setup_prompt`). Authed for ALL users (any valid Bearer/API key). MNE-517.","tags":["Dojo"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Scenario slug (e.g. 'db-shepherd')."}],"responses":{"200":{"description":"The scenario briefing.","content":{"application/json":{"schema":{"type":"object","required":["scenario_id","name","alignment_card","protection_card","setup_prompt"],"properties":{"scenario_id":{"type":"string","description":"Scenario slug (e.g. 'db-shepherd')."},"name":{"type":"string"},"description":{"type":["string","null"],"description":"Human-facing blurb."},"alignment_card":{"type":"object","additionalProperties":true},"protection_card":{"type":"object","additionalProperties":true},"setup_prompt":{"type":"string","description":"Agent-facing self-setup copy, computed from the scenario row."}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/dojo/try-me-configs":{"post":{"operationId":"createDojoTryMeConfig","summary":"Mint a Try-Me Config (scenario + model) with a server-generated token.","description":"Creates a single-use Try-Me Config and binds an ephemeral compute key server-side (sets `compute_key_ref`). MNE-828: the resolve token is SERVER-GENERATED, high-entropy, and prefixed `tryme_…` — the request does NOT accept a user-chosen token/slug (any supplied value is ignored), and the compute key is NOT returned in the response (the gateway resolves credentials server-side). Returns the created `config` (carrying the generated `token`) and the agent-directive `share_line` the operator copies and sends to the person they're inviting. Single-use ON by default; a default 7-day expiry is applied when none is given. Accepts an optional operator `label`. Admin-only — backs `/admin/dojo`. MNE-517 §3 / MNE-522 / MNE-828.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["scenarioId"],"properties":{"scenarioId":{"type":"string","description":"dojo_scenarios.id (e.g. 'db-shepherd')."},"label":{"type":"string","maxLength":200,"nullable":true,"description":"MNE-828: optional operator label (free text) for the operator's own list (e.g. 'WonderCo DB-Shepherd demo'). NOT a credential — the resolve token is server-generated."},"model":{"type":"object","description":"Frontier model; defaults to {provider:'anthropic', name:'claude'}.","properties":{"provider":{"type":"string","enum":["anthropic","openai","google"]},"name":{"type":"string"}}},"expiresAt":{"type":"string","format":"date-time","nullable":true},"usageLimit":{"type":"integer","minimum":1,"default":1},"briefingManifestRef":{"type":"string","nullable":true},"logoUrl":{"type":"string","format":"uri","maxLength":2048,"nullable":true,"description":"MNE-1322: optional brand logo (https URL); the agent minted from this invite carries it as its avatar."}}}}}},"responses":{"201":{"description":"Try-Me Config created (with a server-generated token) and a compute key bound server-side. The compute key is NOT returned (MNE-828).","content":{"application/json":{"schema":{"type":"object","required":["config","share_line"],"properties":{"config":{"type":"object","required":["id","token","scenario_id","model_provider","model_name","usage_limit","uses_remaining","created_by","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid"},"token":{"type":"string","description":"The single-use resolve credential. MNE-828: server-generated, high-entropy, prefixed `tryme_…` (no longer a user-chosen slug). Existing low-entropy tokens keep resolving (back-compat)."},"label":{"type":["string","null"],"description":"MNE-828: optional operator label (free text) for the operator's own list. NOT a credential and never resolved against."},"scenario_id":{"type":"string"},"model_provider":{"type":"string","enum":["anthropic","openai","google"]},"model_name":{"type":"string"},"compute_key_ref":{"type":["string","null"],"description":"mnemom_api_keys.key_id of the bound compute key."},"briefing_manifest_ref":{"type":["string","null"]},"logo_url":{"type":["string","null"],"format":"uri","description":"MNE-1322: optional brand logo (https URL) attached to the invite; the agent minted from it carries this as its avatar."},"usage_limit":{"type":"integer","minimum":1},"uses_remaining":{"type":"integer","minimum":0,"description":"Burns to 0 on first use."},"used_at":{"type":["string","null"],"format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time"},"self_serve_resettable":{"type":"boolean","description":"When true, the anon self-serve reset (POST /dojo/try-me/reset) may re-arm this token. Default false (opt-in)."},"reset_count":{"type":"integer","minimum":0,"description":"Monotonic self-serve reset count, capped in-handler to bound farmed births."},"created_by":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"share_line":{"type":"string","description":"MNE-804 — the agent-directive entry one-liner the operator copies and SENDS to the person they're inviting: an invite to spar in the Dojo that tells the agent to CONNECT to the Mnemom MCP and call `get_started` with the (server-generated) token, or (no MCP) HTTP GET the resolve endpoint and read the RAW JSON, then follow the returned manifest verbatim. Never 'visit', never a password prompt."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"get":{"operationId":"listDojoTryMeConfigs","summary":"List Try-Me Configs.","description":"Lists Try-Me Configs newest-first. Filter by `?token=` (collision check) and `?live=true` (only un-burned, un-expired). Admin-only. MNE-517 §3 / MNE-522.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"token","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to a single token (collision check)."},{"name":"live","in":"query","required":false,"schema":{"type":"boolean"},"description":"Only return live (uses_remaining > 0 and un-expired) configs."}],"responses":{"200":{"description":"The matching Try-Me Configs.","content":{"application/json":{"schema":{"type":"object","required":["configs"],"properties":{"configs":{"type":"array","items":{"type":"object","required":["id","token","scenario_id","model_provider","model_name","usage_limit","uses_remaining","created_by","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid"},"token":{"type":"string","description":"The single-use resolve credential. MNE-828: server-generated, high-entropy, prefixed `tryme_…` (no longer a user-chosen slug). Existing low-entropy tokens keep resolving (back-compat)."},"label":{"type":["string","null"],"description":"MNE-828: optional operator label (free text) for the operator's own list. NOT a credential and never resolved against."},"scenario_id":{"type":"string"},"model_provider":{"type":"string","enum":["anthropic","openai","google"]},"model_name":{"type":"string"},"compute_key_ref":{"type":["string","null"],"description":"mnemom_api_keys.key_id of the bound compute key."},"briefing_manifest_ref":{"type":["string","null"]},"logo_url":{"type":["string","null"],"format":"uri","description":"MNE-1322: optional brand logo (https URL) attached to the invite; the agent minted from it carries this as its avatar."},"usage_limit":{"type":"integer","minimum":1},"uses_remaining":{"type":"integer","minimum":0,"description":"Burns to 0 on first use."},"used_at":{"type":["string","null"],"format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time"},"self_serve_resettable":{"type":"boolean","description":"When true, the anon self-serve reset (POST /dojo/try-me/reset) may re-arm this token. Default false (opt-in)."},"reset_count":{"type":"integer","minimum":0,"description":"Monotonic self-serve reset count, capped in-handler to bound farmed births."},"created_by":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/dojo/try-me-configs/batch":{"post":{"operationId":"batchCreateDojoTryMeConfigs","summary":"Batch-mint Try-Me Configs and email each invitee an invitation.","description":"Mints one single-use Try-Me Config per invite (each its OWN server-generated `tryme_…` token) and sends each invitee a formatted invitation email (Resend, no-reply@mnemom) carrying that invite's route-composed `share_line`. Caps at 50 invites per batch; a per-invite mint failure is recorded in `results` and skipped (it never aborts the batch). Email delivery is best-effort (logged to `email_log`); the response reflects MINT status. Compute keys are bound server-side and NOT returned (MNE-828). Admin-only. MNE-1320.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["scenarioId","invites"],"properties":{"scenarioId":{"type":"string","description":"dojo_scenarios.id shared by every config minted in this batch."},"model":{"type":"object","description":"Frontier model; defaults to {provider:'anthropic', name:'claude'}.","properties":{"provider":{"type":"string","enum":["anthropic","openai","google"]},"name":{"type":"string"}}},"expiresAt":{"type":"string","format":"date-time","nullable":true},"usageLimit":{"type":"integer","minimum":1,"default":1},"logoUrl":{"type":"string","format":"uri","maxLength":2048,"nullable":true,"description":"MNE-1322: optional brand logo (https URL) applied to every invite in the batch; each minted agent carries it as its avatar."},"invites":{"type":"array","minItems":1,"maxItems":50,"description":"One entry per person to invite (1–50).","items":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"name":{"type":"string","maxLength":120,"description":"Optional display name used in the email greeting."},"routes":{"type":"object","description":"Which route(s) the invite's share line composes; defaults to both.","properties":{"npx":{"type":"boolean","default":true},"mcp":{"type":"boolean","default":true}}}}}}}}}}},"responses":{"201":{"description":"Batch processed. Each invite reports its mint status in `results`; sent emails are logged to email_log. Compute keys are NOT returned (MNE-828).","content":{"application/json":{"schema":{"type":"object","required":["requested","sent","failed","results"],"properties":{"requested":{"type":"integer"},"sent":{"type":"integer"},"failed":{"type":"integer"},"results":{"type":"array","items":{"type":"object","required":["email","status"],"properties":{"email":{"type":"string","format":"email"},"name":{"type":"string","nullable":true},"status":{"type":"string","enum":["sent","failed"]},"config_id":{"type":"string"},"share_line":{"type":"string"},"error":{"type":"string"}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/dojo/try-me-configs/{id}/expire":{"post":{"operationId":"expireDojoTryMeConfig","summary":"Burn/expire a Try-Me Config, freeing its token.","description":"Sets `uses_remaining` to 0 and stamps `expires_at`, immediately disabling the token and freeing it for re-mint. Idempotent. Admin-only. MNE-517 §3 / MNE-522.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The expired Try-Me Config.","content":{"application/json":{"schema":{"type":"object","required":["config"],"properties":{"config":{"type":"object","required":["id","token","scenario_id","model_provider","model_name","usage_limit","uses_remaining","created_by","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid"},"token":{"type":"string","description":"The single-use resolve credential. MNE-828: server-generated, high-entropy, prefixed `tryme_…` (no longer a user-chosen slug). Existing low-entropy tokens keep resolving (back-compat)."},"label":{"type":["string","null"],"description":"MNE-828: optional operator label (free text) for the operator's own list. NOT a credential and never resolved against."},"scenario_id":{"type":"string"},"model_provider":{"type":"string","enum":["anthropic","openai","google"]},"model_name":{"type":"string"},"compute_key_ref":{"type":["string","null"],"description":"mnemom_api_keys.key_id of the bound compute key."},"briefing_manifest_ref":{"type":["string","null"]},"logo_url":{"type":["string","null"],"format":"uri","description":"MNE-1322: optional brand logo (https URL) attached to the invite; the agent minted from it carries this as its avatar."},"usage_limit":{"type":"integer","minimum":1},"uses_remaining":{"type":"integer","minimum":0,"description":"Burns to 0 on first use."},"used_at":{"type":["string","null"],"format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time"},"self_serve_resettable":{"type":"boolean","description":"When true, the anon self-serve reset (POST /dojo/try-me/reset) may re-arm this token. Default false (opt-in)."},"reset_count":{"type":"integer","minimum":0,"description":"Monotonic self-serve reset count, capped in-handler to bound farmed births."},"created_by":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/dojo/try-me-configs/{id}/invite":{"post":{"operationId":"resendDojoTryMeInvite","summary":"Re-send an invitation email for an already-minted Try-Me Config.","description":"Rebuilds the invite's route-composed `share_line` from the EXISTING token (no re-mint, no new row) and emails it (Resend, no-reply@mnemom) to the recipient. Powers the Invites table 'Re-invite' action — resending burns nothing and the same token keeps working (pair with `/reset` first if it's already spent). Email delivery is best-effort (logged to `email_log`); the response reflects send dispatch. Admin-only. MNE-1320.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"name":{"type":"string","maxLength":120,"description":"Optional display name used in the email greeting."},"routes":{"type":"object","description":"Which route(s) the invite's share line composes; defaults to both.","properties":{"npx":{"type":"boolean","default":true},"mcp":{"type":"boolean","default":true}}}}}}}},"responses":{"200":{"description":"The invitation email was dispatched (logged to email_log).","content":{"application/json":{"schema":{"type":"object","required":["sent","email","share_line"],"properties":{"sent":{"type":"boolean"},"email":{"type":"string","format":"email"},"share_line":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/dojo/try-me-configs/{id}/reset":{"post":{"operationId":"resetDojoTryMeConfig","summary":"Re-arm a Try-Me Config, making its token resolvable again.","description":"The inverse of expire: re-arms `uses_remaining` to `usage_limit` and clears the burn state (`used_at`, `expires_at`, `briefing_manifest_ref`) so the next resolve mints a fresh manifest. Operator path — re-arms ANY config by id (e.g. the `smoke-test` demo token), independent of the self-serve opt-in gate. Idempotent. Admin-only. MNE-800.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The re-armed Try-Me Config.","content":{"application/json":{"schema":{"type":"object","required":["config"],"properties":{"config":{"type":"object","required":["id","token","scenario_id","model_provider","model_name","usage_limit","uses_remaining","created_by","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid"},"token":{"type":"string","description":"The single-use resolve credential. MNE-828: server-generated, high-entropy, prefixed `tryme_…` (no longer a user-chosen slug). Existing low-entropy tokens keep resolving (back-compat)."},"label":{"type":["string","null"],"description":"MNE-828: optional operator label (free text) for the operator's own list. NOT a credential and never resolved against."},"scenario_id":{"type":"string"},"model_provider":{"type":"string","enum":["anthropic","openai","google"]},"model_name":{"type":"string"},"compute_key_ref":{"type":["string","null"],"description":"mnemom_api_keys.key_id of the bound compute key."},"briefing_manifest_ref":{"type":["string","null"]},"logo_url":{"type":["string","null"],"format":"uri","description":"MNE-1322: optional brand logo (https URL) attached to the invite; the agent minted from it carries this as its avatar."},"usage_limit":{"type":"integer","minimum":1},"uses_remaining":{"type":"integer","minimum":0,"description":"Burns to 0 on first use."},"used_at":{"type":["string","null"],"format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time"},"self_serve_resettable":{"type":"boolean","description":"When true, the anon self-serve reset (POST /dojo/try-me/reset) may re-arm this token. Default false (opt-in)."},"reset_count":{"type":"integer","minimum":0,"description":"Monotonic self-serve reset count, capped in-handler to bound farmed births."},"created_by":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/dojo/try-me/bind-agent":{"post":{"operationId":"bindTryMeAgent","summary":"Record the born agent on its Try-Me Config (authed, owner-only).","description":"Links the born agent's id to its TryMeConfig so Begin Sim can later resolve the dojo provider key by agent_id alone (the dashboard never handles the key). A SEPARATE, dojo-specific step the agent performs AFTER `mnemom login` — NOT part of the canonical claim flow (that page is untouched). AUTHED + owner-only: the caller must authenticate (Bearer/API key — the agent uses its `mnemom login` session) AND be a member of the agent's governing org (ADR-062 — the same gate as `put_alignment_by_agent`/DECLARE). `config_id` (baked into the manifest's `bind` block + the claim link's `&dojo_config`) is the unambiguous selector vs the burned token. Idempotent. MNE-517 §1 / MNE-524.","tags":["Dojo"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["config_id","agent_id"],"properties":{"config_id":{"type":"string","format":"uuid","description":"The TryMeConfig to bind to — the unambiguous selector baked into the manifest's `bind` block and the claim link's `&dojo_config`. Begin Sim resolves the dojo provider key from this config."},"agent_id":{"type":"string","description":"The born agent's id (`mnm-…`) to link to the config. Owner-only: you must be a member of the agent's governing org (ADR-062), the same gate as publishing its alignment card."}}}}}},"responses":{"200":{"description":"Bound. A 200 MEANS the agent is now recorded on the config — the endpoint no longer answers `200 {bound:false}`; a failed linkage is 404 `config_not_found` / 403 `config_linkage_forbidden` / 500 `config_bind_failed`.","content":{"application/json":{"schema":{"type":"object","required":["bound"],"properties":{"bound":{"type":"boolean","description":"Always `true` on a 200. Kept for wire compatibility."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/dojo/try-me/reset":{"get":{"operationId":"resetTryMeToken","summary":"Self-serve re-arm of a stuck (burned) demo token.","description":"UNAUTHED — the token IS the credential, exactly like resolve. Re-arms a BURNED, self-serve-resettable demo token so the next resolve mints a fresh manifest, WITHOUT an operator (a stuck demo self-heals). Bounded against abuse: the config must be opt-in `self_serve_resettable`, the reset count is hard-capped, and a token is re-armable only while already burned (never multiplies a live token) — all enforced atomically. The 409 is uniform across every not-resettable reason (unknown / not opt-in / still live / over cap) so it is not an enumeration or state oracle. POST (body `{token}`) is equivalent. MNE-800.","tags":["Dojo"],"security":[],"parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string"},"description":"The demo token to re-arm."}],"responses":{"200":{"description":"The token was re-armed; re-resolve to get a fresh manifest.","content":{"application/json":{"schema":{"type":"object","required":["reset"],"properties":{"reset":{"type":"boolean","enum":[true]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"409":{"description":"Not resettable (uniform: unknown / not opt-in / still live / over cap).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"post":{"operationId":"resetTryMeTokenPost","summary":"Self-serve re-arm of a stuck demo token (POST form).","description":"POST equivalent of `GET /dojo/try-me/reset` — token supplied in the JSON body. Same semantics and responses. MNE-800.","tags":["Dojo"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token"],"properties":{"token":{"type":"string"}}}}}},"responses":{"200":{"description":"The token was re-armed; re-resolve to get a fresh manifest.","content":{"application/json":{"schema":{"type":"object","required":["reset"],"properties":{"reset":{"type":"boolean","enum":[true]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"409":{"description":"Not resettable (uniform: unknown / not opt-in / still live / over cap).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/dojo/try-me/resolve":{"get":{"operationId":"resolveTryMeBriefing","summary":"Resolve a single-use Try-Me token to its onboarding briefing manifest.","description":"UNAUTHED — the token IS the credential. Returns the briefing manifest, a declarative state machine an agent executes deterministically: it leads with a machine-readable `directive` (fetch the RAW JSON, do not summarize), declares the flow as explicit states (orient → resolve → birth → claim → spar → receipt), and declares BOTH owner-tier auth doors (`auth_doors`: an RFC 6750 MCP step-up challenge and an RFC 8628 device authorization grant) so the agent negotiates by host capability. The agent is born through the gateway with a per-session BIRTH TOKEN (`mnbt_…`, MNE-799 server-mediated birth) and a CONCRETE model id; the gateway resolves the birth token server-side to the real key and mints a server-side `mnm-…` agent_id, and the agent's identity is token-derived (`first16hex(SHA256(birth_token))`), NOT name-derived — no shared provider key is ever handed to the agent (the name is only a display label). The human takes ownership via the canonical /claim URL (the claim page is generic and untouched), then — as the human, via a `mnemom login` CLI session — the agent records itself with the Dojo (a SEPARATE authed, owner-only bind) and DECLARES ITS OWN GOOD alignment + protection cards (`mnemom card/protection publish`, nudge). Single-use: preconditions (live token, provider key configured, scenario present, birth token minted) are checked BEFORE the atomic burn, so a setup slip returns a clean error WITHOUT consuming the token; the burn is the last step. Idempotent within a reuse window (MNE-800): a re-resolve of a recently-burned token replays the EXACT manifest (same birth token) instead of 410. A second resolve outside the window returns 404/410. POST (body `{token}`) is equivalent, and the MCP `get_started(token)` tool returns the identical manifest over MCP. MNE-517 / MNE-799 / MNE-798.","tags":["Dojo"],"security":[],"parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string"},"description":"The single-use Try-Me token (e.g. `wndrco`)."}],"responses":{"200":{"description":"The briefing manifest for the burned token.","content":{"application/json":{"schema":{"type":"object","required":["directive","version","token","mission","model","gateway","declare","bind","handoff","human_beats","human_beats_note","steps","state_machine","auth_doors","instructions_markdown"],"properties":{"directive":{"type":"string","description":"MNE-798 — the FIRST manifest field: the machine-readable contract (fetch the RAW JSON, do not summarize, agent-directive language — never 'visit'). Hoisted to the top so a summarizing reader hits it before stripping the structured fields."},"version":{"type":"string"},"token":{"type":"string"},"human_beats":{"type":"array","description":"MNE-804 — the claim-first arc as the human FEELS it: exactly three one-click beats (name → authorize → Begin Sim). Everything else is a silent machine step under the grant from beat 2. The human twin of `steps`/`state_machine` (additive — those are untouched). Beat 2 (authorize) is host-native OAuth consent or a single one-click device-grant deep link (`verification_uri_complete`), NEVER a pasted URL, and carries the explicit 'waiting for signup' state (no premature timeout).","items":{"type":"object","required":["id","n","title","prompt","one_click"],"properties":{"id":{"type":"string","enum":["name","authorize","begin_sim"]},"n":{"type":"integer"},"title":{"type":"string"},"prompt":{"type":"string"},"one_click":{"type":"boolean"}}}},"human_beats_note":{"type":"string","description":"MNE-804 — framing for `human_beats`: everything outside the three beats runs silently/automatically under the scoped grant."},"mission":{"type":"object","required":["scenario_id","name","role_system_prompt","failure_conditions"],"properties":{"scenario_id":{"type":"string"},"name":{"type":"string"},"role_system_prompt":{"type":"string"},"failure_conditions":{"type":"object","additionalProperties":true}}},"model":{"type":"object","required":["provider","name"],"properties":{"provider":{"type":"string"},"name":{"type":"string"}}},"gateway":{"type":"object","description":"Birth credential — the agent presents this on `key_header` to be born + carry every gateway/model call. The ONLY credential handed to the agent. Under MNE-799 server-mediated birth this is a per-session BIRTH TOKEN (`birth_token`, `mnbt_…`) the gateway resolves server-side to the real key; identity is token-derived (`first16hex(SHA256(birth_token))`) and the agent_id is a server-minted `mnm-…` — NOT name-derived, and no shared provider key reaches the agent.","required":["endpoint","provider","model","key_header","agent_header"],"properties":{"endpoint":{"type":"string","format":"uri"},"provider":{"type":"string","enum":["anthropic","openai","google"]},"model":{"type":"string","description":"Concrete model id to send at birth (bare aliases 404 upstream)."},"key_header":{"type":"string","description":"Provider-native header for the key (x-api-key / Authorization / x-goog-api-key)."},"provider_key":{"type":"string","description":"Legacy flow only — the Mnemom-provided dojo provider key as the agent's identity + model credential. Present ONLY when no `birth_token` is issued; superseded by `birth_token` under MNE-799 server-mediated birth (which never hands a shared provider key to the agent)."},"birth_token":{"type":"string","description":"MNE-799 server-mediated birth — the per-session BIRTH TOKEN (`mnbt_…`) the agent presents on `key_header`; the gateway resolves it server-side to the real key and mints a token-derived `mnm-…` agent_id. Present in token mode (the default) INSTEAD OF `provider_key`."},"agent_header":{"type":"string","description":"Header carrying the agent's birth NAME (x-mnemom-agent) — the other half of agent_id."}}},"declare":{"type":"object","required":["alignment_card","protection_card","protection_mode"],"properties":{"alignment_card":{"type":"object","additionalProperties":true},"protection_card":{"type":"object","additionalProperties":true},"protection_mode":{"type":"string","enum":["nudge","enforce"]}}},"bind":{"type":"object","description":"Authed dojo bind (post-`mnemom login`, owner-only) — the agent records its agent_id against this briefing so Begin Sim can resolve the dojo key by agent_id and spar it.","required":["endpoint","config_id"],"properties":{"endpoint":{"type":"string","format":"uri"},"config_id":{"type":"string"}}},"handoff":{"type":"object","description":"Human-handoff + CLI surfaces: the human takes ownership via the canonical /claim page, then the agent declares as the human via a `mnemom login` CLI session.","required":["name_question","name_options","signup_url","claim_url_template","claim_hash_recipe","dojo_url"],"properties":{"name_question":{"type":"string"},"name_options":{"type":"array","items":{"type":"string"}},"signup_url":{"type":"string","format":"uri"},"claim_url_template":{"type":"string"},"grant_url_template":{"type":"string","description":"First-party protection-grant page template (`…/authorize-protection?agent_id={agent_id}`) — the human approves the one-time protection-card write grant here (the `protection_grant` auth door surface)."},"claim_hash_recipe":{"type":"string"},"cli_install":{"type":"string","description":"Legacy/optional — the `mnemom` CLI install one-liner. No longer emitted by the narrated one-click flow; retained as an optional field for older consumers."},"dojo_url":{"type":"string","format":"uri"}}},"steps":{"type":"array","items":{"type":"object","required":["n","title","body"],"properties":{"n":{"type":"integer"},"title":{"type":"string"},"body":{"type":"string"},"human_handoff":{"type":"boolean"}}}},"state_machine":{"type":"object","description":"MNE-798 — the declarative flow as explicit states + transitions (the machine twin of `steps`), so an agent executes it deterministically across substrates. Each state carries the concrete next call to make and the signal that advances it.","required":["initial","states"],"properties":{"initial":{"type":"string","enum":["orient","resolve","birth","claim","spar","receipt"]},"states":{"type":"array","items":{"type":"object","required":["id","description","auth","next_action","success_signal","on_success"],"properties":{"id":{"type":"string","enum":["orient","resolve","birth","claim","spar","receipt"]},"description":{"type":"string"},"auth":{"type":"object","description":"MNE-798 — the state's authorization tier: `anon` (the try-me token IS the credential — token-mediated birth) or `owner` (acts in the human's org; the agent must obtain an owner session through one of the listed `doors`, a subset of `auth_doors`). Tells the agent WHEN to invoke an auth door.","required":["tier"],"properties":{"tier":{"type":"string","enum":["anon","owner"]},"doors":{"type":"array","items":{"type":"string","enum":["mcp_step_up","protection_grant","device_grant"]},"description":"For an `owner` state: which auth_doors ids unlock it. Empty for `anon`."}},"additionalProperties":false},"next_action":{"type":"object","description":"The single concrete, machine-executable action this state advances on — a raw HTTP call (`kind:http`) or an MCP tool invocation (`kind:mcp`).","required":["kind"],"properties":{"kind":{"type":"string","enum":["http","mcp"]},"method":{"type":"string","enum":["GET","POST"]},"url":{"type":"string"},"headers":{"type":"object","additionalProperties":{"type":"string"}},"body_hint":{"type":"string"},"tool":{"type":"string"},"args_hint":{"type":"string"}},"additionalProperties":false},"success_signal":{"type":"string"},"on_success":{"type":["string","null"],"enum":["orient","resolve","birth","claim","spar","receipt",null],"description":"The successor state id, or null when terminal."},"human_handoff":{"type":"boolean"}},"additionalProperties":false}}}},"auth_doors":{"type":"object","description":"MNE-798 — the owner-tier authorization affordances, declared so the agent negotiates by host capability: `mcp_step_up` (RFC 6750 insufficient_scope challenge — mid-session step-up), `protection_grant` (first-party one-time browser grant — the human approves the protection-card write), and `device_grant` (RFC 8628 device authorization grant — the headless fallback). The agent picks the one its host supports.","required":["negotiation_hint","doors"],"properties":{"negotiation_hint":{"type":"string"},"doors":{"type":"array","items":{"type":"object","required":["id","protocol","description","use_when"],"properties":{"id":{"type":"string","enum":["mcp_step_up","protection_grant","device_grant"]},"protocol":{"type":"string","enum":["RFC 6750","first-party one-time grant","RFC 8628"]},"description":{"type":"string"},"use_when":{"type":"string"},"challenge":{"type":"object","description":"mcp_step_up only — the 403 challenge the api emits at owner-tier endpoints.","required":["status","www_authenticate","resource_metadata"],"properties":{"status":{"type":"integer","enum":[403]},"www_authenticate":{"type":"string"},"resource_metadata":{"type":"string","format":"uri"}}},"grant_url_template":{"type":"string","description":"protection_grant only — the first-party grant page template (`…/authorize-protection?agent_id={agent_id}`) the human opens to approve the one-time protection-card write."},"insufficient_scope_status":{"type":"integer","description":"protection_grant only — the status the protection-card write returns until the grant lands (403)."},"grant_type":{"type":"string"},"device_authorization_endpoint":{"type":"string","format":"uri"},"token_endpoint":{"type":"string","format":"uri"},"registration_endpoint":{"type":"string","format":"uri"},"scopes_hint":{"type":"string","description":"device_grant only — the OAuth scopes to request for the card writes."},"verification_uri":{"type":"string","format":"uri"},"poll_interval_seconds":{"type":"integer"}},"additionalProperties":false}}}},"instructions_markdown":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"410":{"description":"The token has already been used (single-use, burned) or has expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"post":{"operationId":"resolveTryMeBriefingPost","summary":"Resolve a single-use Try-Me token to its briefing manifest (POST form).","description":"POST equivalent of `GET /dojo/try-me/resolve` — token supplied in the JSON body. Same burn semantics and responses. MNE-517 §1/§2 / MNE-523.","tags":["Dojo"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token"],"properties":{"token":{"type":"string"}}}}}},"responses":{"200":{"description":"The briefing manifest for the burned token.","content":{"application/json":{"schema":{"type":"object","required":["directive","version","token","mission","model","gateway","declare","bind","handoff","human_beats","human_beats_note","steps","state_machine","auth_doors","instructions_markdown"],"properties":{"directive":{"type":"string","description":"MNE-798 — the FIRST manifest field: the machine-readable contract (fetch the RAW JSON, do not summarize, agent-directive language — never 'visit'). Hoisted to the top so a summarizing reader hits it before stripping the structured fields."},"version":{"type":"string"},"token":{"type":"string"},"human_beats":{"type":"array","description":"MNE-804 — the claim-first arc as the human FEELS it: exactly three one-click beats (name → authorize → Begin Sim). Everything else is a silent machine step under the grant from beat 2. The human twin of `steps`/`state_machine` (additive — those are untouched). Beat 2 (authorize) is host-native OAuth consent or a single one-click device-grant deep link (`verification_uri_complete`), NEVER a pasted URL, and carries the explicit 'waiting for signup' state (no premature timeout).","items":{"type":"object","required":["id","n","title","prompt","one_click"],"properties":{"id":{"type":"string","enum":["name","authorize","begin_sim"]},"n":{"type":"integer"},"title":{"type":"string"},"prompt":{"type":"string"},"one_click":{"type":"boolean"}}}},"human_beats_note":{"type":"string","description":"MNE-804 — framing for `human_beats`: everything outside the three beats runs silently/automatically under the scoped grant."},"mission":{"type":"object","required":["scenario_id","name","role_system_prompt","failure_conditions"],"properties":{"scenario_id":{"type":"string"},"name":{"type":"string"},"role_system_prompt":{"type":"string"},"failure_conditions":{"type":"object","additionalProperties":true}}},"model":{"type":"object","required":["provider","name"],"properties":{"provider":{"type":"string"},"name":{"type":"string"}}},"gateway":{"type":"object","description":"Birth credential — the agent presents this on `key_header` to be born + carry every gateway/model call. The ONLY credential handed to the agent. Under MNE-799 server-mediated birth this is a per-session BIRTH TOKEN (`birth_token`, `mnbt_…`) the gateway resolves server-side to the real key; identity is token-derived (`first16hex(SHA256(birth_token))`) and the agent_id is a server-minted `mnm-…` — NOT name-derived, and no shared provider key reaches the agent.","required":["endpoint","provider","model","key_header","agent_header"],"properties":{"endpoint":{"type":"string","format":"uri"},"provider":{"type":"string","enum":["anthropic","openai","google"]},"model":{"type":"string","description":"Concrete model id to send at birth (bare aliases 404 upstream)."},"key_header":{"type":"string","description":"Provider-native header for the key (x-api-key / Authorization / x-goog-api-key)."},"provider_key":{"type":"string","description":"Legacy flow only — the Mnemom-provided dojo provider key as the agent's identity + model credential. Present ONLY when no `birth_token` is issued; superseded by `birth_token` under MNE-799 server-mediated birth (which never hands a shared provider key to the agent)."},"birth_token":{"type":"string","description":"MNE-799 server-mediated birth — the per-session BIRTH TOKEN (`mnbt_…`) the agent presents on `key_header`; the gateway resolves it server-side to the real key and mints a token-derived `mnm-…` agent_id. Present in token mode (the default) INSTEAD OF `provider_key`."},"agent_header":{"type":"string","description":"Header carrying the agent's birth NAME (x-mnemom-agent) — the other half of agent_id."}}},"declare":{"type":"object","required":["alignment_card","protection_card","protection_mode"],"properties":{"alignment_card":{"type":"object","additionalProperties":true},"protection_card":{"type":"object","additionalProperties":true},"protection_mode":{"type":"string","enum":["nudge","enforce"]}}},"bind":{"type":"object","description":"Authed dojo bind (post-`mnemom login`, owner-only) — the agent records its agent_id against this briefing so Begin Sim can resolve the dojo key by agent_id and spar it.","required":["endpoint","config_id"],"properties":{"endpoint":{"type":"string","format":"uri"},"config_id":{"type":"string"}}},"handoff":{"type":"object","description":"Human-handoff + CLI surfaces: the human takes ownership via the canonical /claim page, then the agent declares as the human via a `mnemom login` CLI session.","required":["name_question","name_options","signup_url","claim_url_template","claim_hash_recipe","dojo_url"],"properties":{"name_question":{"type":"string"},"name_options":{"type":"array","items":{"type":"string"}},"signup_url":{"type":"string","format":"uri"},"claim_url_template":{"type":"string"},"grant_url_template":{"type":"string","description":"First-party protection-grant page template (`…/authorize-protection?agent_id={agent_id}`) — the human approves the one-time protection-card write grant here (the `protection_grant` auth door surface)."},"claim_hash_recipe":{"type":"string"},"cli_install":{"type":"string","description":"Legacy/optional — the `mnemom` CLI install one-liner. No longer emitted by the narrated one-click flow; retained as an optional field for older consumers."},"dojo_url":{"type":"string","format":"uri"}}},"steps":{"type":"array","items":{"type":"object","required":["n","title","body"],"properties":{"n":{"type":"integer"},"title":{"type":"string"},"body":{"type":"string"},"human_handoff":{"type":"boolean"}}}},"state_machine":{"type":"object","description":"MNE-798 — the declarative flow as explicit states + transitions (the machine twin of `steps`), so an agent executes it deterministically across substrates. Each state carries the concrete next call to make and the signal that advances it.","required":["initial","states"],"properties":{"initial":{"type":"string","enum":["orient","resolve","birth","claim","spar","receipt"]},"states":{"type":"array","items":{"type":"object","required":["id","description","auth","next_action","success_signal","on_success"],"properties":{"id":{"type":"string","enum":["orient","resolve","birth","claim","spar","receipt"]},"description":{"type":"string"},"auth":{"type":"object","description":"MNE-798 — the state's authorization tier: `anon` (the try-me token IS the credential — token-mediated birth) or `owner` (acts in the human's org; the agent must obtain an owner session through one of the listed `doors`, a subset of `auth_doors`). Tells the agent WHEN to invoke an auth door.","required":["tier"],"properties":{"tier":{"type":"string","enum":["anon","owner"]},"doors":{"type":"array","items":{"type":"string","enum":["mcp_step_up","protection_grant","device_grant"]},"description":"For an `owner` state: which auth_doors ids unlock it. Empty for `anon`."}},"additionalProperties":false},"next_action":{"type":"object","description":"The single concrete, machine-executable action this state advances on — a raw HTTP call (`kind:http`) or an MCP tool invocation (`kind:mcp`).","required":["kind"],"properties":{"kind":{"type":"string","enum":["http","mcp"]},"method":{"type":"string","enum":["GET","POST"]},"url":{"type":"string"},"headers":{"type":"object","additionalProperties":{"type":"string"}},"body_hint":{"type":"string"},"tool":{"type":"string"},"args_hint":{"type":"string"}},"additionalProperties":false},"success_signal":{"type":"string"},"on_success":{"type":["string","null"],"enum":["orient","resolve","birth","claim","spar","receipt",null],"description":"The successor state id, or null when terminal."},"human_handoff":{"type":"boolean"}},"additionalProperties":false}}}},"auth_doors":{"type":"object","description":"MNE-798 — the owner-tier authorization affordances, declared so the agent negotiates by host capability: `mcp_step_up` (RFC 6750 insufficient_scope challenge — mid-session step-up), `protection_grant` (first-party one-time browser grant — the human approves the protection-card write), and `device_grant` (RFC 8628 device authorization grant — the headless fallback). The agent picks the one its host supports.","required":["negotiation_hint","doors"],"properties":{"negotiation_hint":{"type":"string"},"doors":{"type":"array","items":{"type":"object","required":["id","protocol","description","use_when"],"properties":{"id":{"type":"string","enum":["mcp_step_up","protection_grant","device_grant"]},"protocol":{"type":"string","enum":["RFC 6750","first-party one-time grant","RFC 8628"]},"description":{"type":"string"},"use_when":{"type":"string"},"challenge":{"type":"object","description":"mcp_step_up only — the 403 challenge the api emits at owner-tier endpoints.","required":["status","www_authenticate","resource_metadata"],"properties":{"status":{"type":"integer","enum":[403]},"www_authenticate":{"type":"string"},"resource_metadata":{"type":"string","format":"uri"}}},"grant_url_template":{"type":"string","description":"protection_grant only — the first-party grant page template (`…/authorize-protection?agent_id={agent_id}`) the human opens to approve the one-time protection-card write."},"insufficient_scope_status":{"type":"integer","description":"protection_grant only — the status the protection-card write returns until the grant lands (403)."},"grant_type":{"type":"string"},"device_authorization_endpoint":{"type":"string","format":"uri"},"token_endpoint":{"type":"string","format":"uri"},"registration_endpoint":{"type":"string","format":"uri"},"scopes_hint":{"type":"string","description":"device_grant only — the OAuth scopes to request for the card writes."},"verification_uri":{"type":"string","format":"uri"},"poll_interval_seconds":{"type":"integer"}},"additionalProperties":false}}}},"instructions_markdown":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"410":{"description":"The token has already been used (single-use, burned) or has expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/domains":{"post":{"operationId":"createDomainClaim","summary":"Create a domain ownership claim","description":"Starts a claim on a registrable apex domain you own and returns the DNS TXT record to place (`mnemom-verification=<token>`). Idempotent per (owner, domain): re-POSTing the same domain returns the same pending token. Subdomains, IP literals and non-apex hosts are rejected. Rate-limited per user and per IP.","tags":["Domains"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string","description":"Registrable apex (e.g. `example.com`, `example.co.uk`).","example":"example.com"}}}}}},"responses":{"200":{"description":"Claim created or idempotently re-fetched; TXT record returned.","content":{"application/json":{"schema":{"type":"object","required":["domain","status","verification"],"properties":{"domain":{"type":"string","example":"example.com"},"status":{"type":"string","enum":["pending","verified"]},"verified_at":{"type":"string","format":"date-time","nullable":true},"honor_roll":{"type":"boolean"},"response_note":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"},"verification":{"type":"object","description":"Everything needed to place the DNS TXT record at the domain apex.","required":["method","type","host","record"],"properties":{"method":{"type":"string","enum":["dns-txt"]},"type":{"type":"string","enum":["TXT"]},"host":{"type":"string","description":"Apex the record goes on."},"name":{"type":"string","description":"DNS record name (apex = `@`)."},"record":{"type":"string","description":"The exact TXT value: `mnemom-verification=<token>`."},"value":{"type":"string","description":"Alias of `record`."},"instructions":{"type":"string"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"get":{"operationId":"listDomainClaims","summary":"List my domain claims","description":"Returns the caller's domain claims with status, verification time, Honor Roll opt-in, public response note, and the latest isittrustready.ai scan `grade` (fetched and cached server-side; `null` when the domain has not been scanned or the scanner is unreachable).","tags":["Domains"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"The caller's claims.","content":{"application/json":{"schema":{"type":"object","required":["domains"],"properties":{"domains":{"type":"array","items":{"type":"object","required":["domain","status","verified","honor_roll"],"properties":{"domain":{"type":"string"},"status":{"type":"string","enum":["pending","verified"]},"verified":{"type":"boolean"},"verified_at":{"type":"string","format":"date-time","nullable":true},"honor_roll":{"type":"boolean"},"response_note":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"},"grade":{"type":"string","nullable":true,"description":"Latest iitr scan grade."}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/domains/{domain}/honor-roll":{"put":{"operationId":"setDomainHonorRoll","summary":"Opt a verified domain in/out of the Honor Roll","description":"Sets explicit, revocable Honor Roll consent for a verified domain. Verified claims only (409 otherwise).","tags":["Domains"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["optIn"],"properties":{"optIn":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated Honor Roll state.","content":{"application/json":{"schema":{"type":"object","required":["domain","honor_roll"],"properties":{"domain":{"type":"string"},"honor_roll":{"type":"boolean"},"verified_at":{"type":"string","format":"date-time","nullable":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/domains/{domain}/public-status":{"get":{"operationId":"getPublicDomainStatus","summary":"Public claim status (no auth, no PII)","description":"Credential-free, cacheable projection consumed by the isittrustready.ai scanner. Always returns 200; an unknown or unverified domain yields `claimed:false`. Contains ZERO PII — only `domain`, `claimed`, `honor_roll`, and the owner-published `response_note`. `Cache-Control: public, max-age=300`.","tags":["Domains"],"security":[],"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Public claim status (always 200).","content":{"application/json":{"schema":{"type":"object","required":["claimed"],"properties":{"domain":{"type":"string","nullable":true},"claimed":{"type":"boolean"},"honor_roll":{"type":"boolean"},"response_note":{"type":"string","nullable":true}}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/domains/{domain}/response-note":{"put":{"operationId":"setDomainResponseNote","summary":"Set a verified domain's public owner response","description":"Publishes a plain-text owner response (≤500 chars; control and bidi/zero-width characters are stripped server-side) rendered on the public scan report. Verified claims only (409 otherwise). An empty note clears it.","tags":["Domains"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["text"],"properties":{"text":{"type":"string","maxLength":500,"nullable":true}}}}}},"responses":{"200":{"description":"Updated response note.","content":{"application/json":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string"},"response_note":{"type":"string","nullable":true},"verified_at":{"type":"string","format":"date-time","nullable":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/domains/{domain}/verify":{"post":{"operationId":"verifyDomainClaim","summary":"Verify a domain claim via DNS TXT","description":"Looks up the apex TXT records over a fixed DoH resolver (Cloudflare 1.1.1.1) for `mnemom-verification=<token>`. Found → the claim is marked verified. Not found → `{claimed:false, reason:\"txt-not-found\"}` (HTTP 200; retry after DNS propagation). A successful verify by a different owner transfers control (anti-squat). Rate-limited per user and per IP.","tags":["Domains"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"},"description":"The registrable apex being verified."}],"responses":{"200":{"description":"Verification result (verified, or a friendly retryable not-found).","content":{"application/json":{"schema":{"type":"object","required":["claimed"],"properties":{"claimed":{"type":"boolean"},"verified_at":{"type":"string","format":"date-time","nullable":true},"reason":{"type":"string","enum":["txt-not-found"],"nullable":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/drift/{agent_id}":{"get":{"operationId":"getAapDrift","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"summary":"Get AAP drift alerts for agent","tags":["Drift"],"parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Drift detection results","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"analyzed_traces":{"type":"integer"},"drift":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/enterprise/contact":{"post":{"operationId":"enterpriseContact","summary":"Submit enterprise contact form","tags":["Billing"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","email","company"],"properties":{"name":{"type":"string"},"email":{"type":"string","format":"email"},"company":{"type":"string"},"role":{"type":"string"},"company_size":{"type":"string"},"message":{"type":"string"}}}}}},"responses":{"200":{"description":"Inquiry submitted","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/feedback":{"post":{"operationId":"submitFeedback","summary":"Submit in-product feedback","description":"Ingest a single piece of in-product feedback (compliment / problem / suggestion) from an authenticated user (web app) or agent (MCP/gateway). Reporter-supplied content is redacted (email / API-key / JWT / phone / long-hex shapes replaced with `[redacted:*]`) BEFORE storage, and the sensitive context fields (`ai_prompts`, `diagnostics`) are dropped unless the matching consent flag is set. Idempotent: a replayed request carrying the same `Idempotency-Key` returns the same `feedback_id` and creates no duplicate row. Inherits the standard per-IP REST rate limit.","tags":["Feedback"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Client-generated key (e.g. a UUID). Replaying the same key within 24h returns the original response unchanged.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["category","title","body"],"properties":{"category":{"type":"string","enum":["compliment","problem","suggestion"],"description":"Reporter-selected intent."},"title":{"type":"string","minLength":1,"maxLength":500,"description":"Short title (redacted before storage)."},"body":{"type":"string","minLength":1,"maxLength":20000,"description":"Feedback body (redacted before storage)."},"consent_prompts":{"type":"boolean","default":false,"description":"When true, `context_bundle.ai_prompts` is stored (redacted); otherwise it is dropped."},"consent_diagnostics":{"type":"boolean","default":false,"description":"When true, `context_bundle.diagnostics` is stored (redacted); otherwise it is dropped."},"consent_contact":{"type":"boolean","default":false,"description":"When true, the reporter opts in to a resolution-email notification."},"context_bundle":{"type":"object","description":"Optional diagnostic context. `route_url` and `breadcrumbs` are always redacted-and-stored; `ai_prompts` / `diagnostics` are consent-gated.","properties":{"route_url":{"type":"string","description":"App route the reporter was on."},"app_version":{"type":"string","description":"Client app version."},"component":{"type":"string","description":"Inferred UI component/area."},"breadcrumbs":{"type":"array","description":"Recent UI actions (roles/test-ids only, never raw input).","items":{}},"ai_prompts":{"description":"AI-prompt excerpts (stored only with consent_prompts)."},"diagnostics":{"type":"object","description":"Client diagnostics (stored only with consent_diagnostics).","additionalProperties":true}}},"attachment_ids":{"type":"array","description":"IDs of previously-presigned pending attachments to bind to this submission.","items":{"type":"string","format":"uuid"}},"company_website":{"type":"string","description":"Honeypot — must be empty. Any non-empty value silently accepts and persists nothing."}}}}}},"responses":{"201":{"description":"Feedback accepted and stored (redacted).","content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"feedback_id":{"type":"string","format":"uuid","description":"The stored submission id (absent on a honeypot-silent accept)."},"status":{"type":"string","const":"received","description":"Client-facing acknowledgement status."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/feedback/attachments/presign":{"post":{"operationId":"presignFeedbackAttachment","summary":"Get a presigned upload URL for a feedback attachment (MNE-1659)","description":"Issues a presigned R2 PUT URL for a screenshot/screen-recording attachment and records a `pending` feedback_attachments row for it — the client uploads the bytes DIRECTLY to R2 with this URL (the worker never proxies them), then passes the returned `attachment_id` in `POST /feedback`'s `attachment_ids` array to bind it to the real submission. No owner column exists on feedback_attachments yet, so ownership is stamped into the R2 object key namespace instead of a DB column. A row that is never bound (upload abandoned, or the follow-up POST /feedback never happens) is reclaimed by a sweep cron past a 1h grace window. Returns 503 if R2 presign credentials aren't provisioned for this env.","tags":["Feedback"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["content_type","size_bytes"],"properties":{"content_type":{"type":"string","enum":["image/png","image/jpeg","image/webp","video/webm","video/mp4"],"description":"MIME type of the attachment. Must match migration 397's feedback_attachments_content_type_ck exactly."},"size_bytes":{"type":"integer","minimum":1,"maximum":26214400,"description":"Declared size in bytes; 25MB cap. Advisory only — R2 does not enforce this against the actual PUT."}}}}}},"responses":{"201":{"description":"Presigned upload URL issued.","content":{"application/json":{"schema":{"type":"object","required":["attachment_id","upload_url","method","headers","expires_in"],"properties":{"attachment_id":{"type":"string","format":"uuid","description":"Pass this in POST /feedback's attachment_ids to bind it."},"upload_url":{"type":"string","format":"uri","description":"Presigned R2 PUT URL. PUT the raw bytes here directly."},"method":{"type":"string","const":"PUT"},"headers":{"type":"object","description":"Headers the client must send with the PUT (Content-Type).","additionalProperties":{"type":"string"}},"expires_in":{"type":"integer","description":"Seconds until the presigned URL expires."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"description":"Attachment upload not configured for this environment."}}}},"/feedback/mine":{"get":{"operationId":"getMyFeedback","summary":"List my feedback submissions","description":"Lists the CALLING reporter's own feedback submissions (newest first), each with its current status, latest triage decision + scores, dedup-cluster membership, linked fleet work item, and resolution/acknowledgement state. Scoped to the authenticated principal server-side (`reporter_user_id`) — there is no way to list another reporter's submissions through this endpoint. Paginated: `cursor` is an opaque offset token, not a timestamp.","tags":["Feedback"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"description":"Maximum rows to return (default 50, max 200)."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque pagination token (an offset) from a prior response's `next_cursor`. Omit for the first page."}],"responses":{"200":{"description":"Paginated list of the caller's own feedback submissions.","content":{"application/json":{"schema":{"type":"object","required":["items","next_cursor","has_more"],"properties":{"items":{"type":"array","items":{"type":"object","required":["id","category","status","title","body","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid"},"category":{"type":"string","enum":["compliment","problem","suggestion"],"description":"Reporter-selected intent, as submitted."},"status":{"type":"string","enum":["received","triage_pending","triaged","needs_review","manual","routed","in_progress","resolved","wont_fix","duplicate"],"description":"Lifecycle status of the submission."},"title":{"type":"string","description":"Reporter-provided title (post-redaction)."},"body":{"type":"string","description":"Reporter-provided body (post-redaction)."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"triage_decision":{"type":["string","null"],"enum":["auto_fix","needs_review","manual","compliment_digest","suggestion_backlog",null],"description":"Most recent triage-brain decision, if any triage pass has run."},"triage_confidence":{"type":["number","null"],"description":"0..1 explainable confidence score from the most recent triage pass."},"triage_risk":{"type":["number","null"],"description":"0..1 explainable risk score from the most recent triage pass."},"cluster_id":{"type":["string","null"],"format":"uuid","description":"Dedup cluster this submission was attached to, if any (see status=duplicate)."},"cluster_member_count":{"type":["integer","null"],"description":"'N reporters affected' count for cluster_id, when present."},"work_item_repo":{"type":["string","null"],"description":"Repo the fleet work item was opened against, if one was created."},"work_item_url":{"type":["string","null"],"format":"uri","description":"URL of the Linear issue opened for this submission, if any."},"work_item_linear_status":{"type":["string","null"],"enum":["open","in_progress","done","released","canceled",null],"description":"Current status of the linked Linear issue, if any."},"work_item_dispatched_at":{"type":["string","null"],"format":"date-time","description":"When the fleet work item was created, if any."},"resolved_at":{"type":["string","null"],"format":"date-time","description":"When this submission was resolved, if it has been."},"resolution_source":{"type":["string","null"],"enum":["linear_webhook","manual",null],"description":"How the resolution was recorded, if resolved."},"acknowledged_at":{"type":["string","null"],"format":"date-time","description":"When the reporter acknowledged the resolution banner, if they have."}}}},"next_cursor":{"type":["string","null"],"description":"Opaque offset token; pass as `cursor` on the next request. `null` when there are no further pages."},"has_more":{"type":"boolean","description":"Whether additional pages exist."}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/feedback/mine/unacknowledged":{"get":{"operationId":"getMyFeedbackUnacknowledged","summary":"List my resolved-but-unacknowledged feedback (MNE-1681)","description":"Returns the CALLING reporter's own resolved feedback submissions that have no acknowledgement yet — the 'pending banner' set the client renders as resolution banners. Scoped server-side to the authenticated principal (`reporter_user_id`/`reporter_agent_id`), same as `/feedback/mine`. Not paginated: the pending set is expected to be small (internal fetch capped at 200 rows). Emits `mnemom.feedback.resolved` / `mnemom.feedback.ack_delivered` telemetry spans when the set is non-empty.","tags":["Feedback"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"The caller's resolved-but-unacknowledged feedback submissions.","content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"type":"object","required":["id","category","status","title","body","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid"},"category":{"type":"string","enum":["compliment","problem","suggestion"],"description":"Reporter-selected intent, as submitted."},"status":{"type":"string","enum":["received","triage_pending","triaged","needs_review","manual","routed","in_progress","resolved","wont_fix","duplicate"],"description":"Lifecycle status of the submission."},"title":{"type":"string","description":"Reporter-provided title (post-redaction)."},"body":{"type":"string","description":"Reporter-provided body (post-redaction)."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"triage_decision":{"type":["string","null"],"enum":["auto_fix","needs_review","manual","compliment_digest","suggestion_backlog",null],"description":"Most recent triage-brain decision, if any triage pass has run."},"triage_confidence":{"type":["number","null"],"description":"0..1 explainable confidence score from the most recent triage pass."},"triage_risk":{"type":["number","null"],"description":"0..1 explainable risk score from the most recent triage pass."},"cluster_id":{"type":["string","null"],"format":"uuid","description":"Dedup cluster this submission was attached to, if any (see status=duplicate)."},"cluster_member_count":{"type":["integer","null"],"description":"'N reporters affected' count for cluster_id, when present."},"work_item_repo":{"type":["string","null"],"description":"Repo the fleet work item was opened against, if one was created."},"work_item_url":{"type":["string","null"],"format":"uri","description":"URL of the Linear issue opened for this submission, if any."},"work_item_linear_status":{"type":["string","null"],"enum":["open","in_progress","done","released","canceled",null],"description":"Current status of the linked Linear issue, if any."},"work_item_dispatched_at":{"type":["string","null"],"format":"date-time","description":"When the fleet work item was created, if any."},"resolved_at":{"type":["string","null"],"format":"date-time","description":"When this submission was resolved, if it has been."},"resolution_source":{"type":["string","null"],"enum":["linear_webhook","manual",null],"description":"How the resolution was recorded, if resolved."},"acknowledged_at":{"type":["string","null"],"format":"date-time","description":"When the reporter acknowledged the resolution banner, if they have."}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/feedback/webhook/linear":{"post":{"operationId":"handleLinearFeedbackWebhook","summary":"Linear issue-state webhook (feedback resolution)","description":"Receives Issue state-change events from Linear (MNE-1680). When a linked issue (matched via the `Feedback-ID:` marker MNE-1679 embeds in the issue body, resolved through `feedback_work_items.linear_issue_id`) moves to a completed state (Done / Released), writes a `feedback_resolutions` row and flips the submission — and any cluster-dupe submissions — to resolved. Non-issue events, non-completed states, and issues with no linked work item are acknowledged as no-ops (200). Authenticated by the `linear-signature` header, an HMAC-SHA-256 digest of the raw request body keyed on `LINEAR_WEBHOOK_SIGNING_SECRET`, timing-safe-compared. FAILS CLOSED: if that secret is not configured, every request is rejected — this endpoint never silently skips signature validation. Handler: `handleLinearWebhook` in `src/feedback/linear-webhook.ts`; `runLinearReconciler` is the scheduled backstop for dropped deliveries.","tags":["Feedback"],"security":[],"parameters":[{"in":"header","name":"linear-signature","required":true,"schema":{"type":"string"},"description":"HMAC-SHA-256 hex digest of the raw request body, keyed on `LINEAR_WEBHOOK_SIGNING_SECRET`, timing-safe-compared."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Linear's Issue webhook payload. Only `type: \"Issue\"` with `action: \"update\"|\"create\"` is processed; other events are acknowledged as no-ops.","additionalProperties":true,"properties":{"type":{"type":"string","description":"Linear event type, e.g. \"Issue\"."},"action":{"type":"string","description":"e.g. \"update\", \"create\"."},"data":{"type":"object","additionalProperties":true,"description":"The Issue resource: id (Linear UUID), identifier (e.g. \"MNE-1234\"), state.name/state.type, description, mergeCommitHash, releaseLabel."}}}}}},"responses":{"200":{"description":"Acknowledged — either a real resolution was recorded (`resolved: true/false` reflecting whether this was already resolved) or the event was a no-op (`skipped: <reason>`).","content":{"application/json":{"schema":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean"},"skipped":{"type":"string","description":"Set when no action was taken: \"not_an_issue_event\" | \"not_a_resolution_state\" | \"no_linked_work_item\"."},"resolved":{"type":"boolean"},"submission_id":{"type":"string","format":"uuid"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/feedback/{id}":{"get":{"operationId":"getMyFeedbackById","summary":"Get one of my feedback submissions","description":"Fetches a single feedback submission by id, SCOPED TO THE CALLING REPORTER. Returns 404 — never 403 — for a submission that doesn't exist AND for a submission that exists but belongs to a different reporter, so the response never reveals whether a given id exists at all.","tags":["Feedback"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The feedback submission's id."}],"responses":{"200":{"description":"The caller's own feedback submission.","content":{"application/json":{"schema":{"type":"object","required":["id","category","status","title","body","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid"},"category":{"type":"string","enum":["compliment","problem","suggestion"],"description":"Reporter-selected intent, as submitted."},"status":{"type":"string","enum":["received","triage_pending","triaged","needs_review","manual","routed","in_progress","resolved","wont_fix","duplicate"],"description":"Lifecycle status of the submission."},"title":{"type":"string","description":"Reporter-provided title (post-redaction)."},"body":{"type":"string","description":"Reporter-provided body (post-redaction)."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"triage_decision":{"type":["string","null"],"enum":["auto_fix","needs_review","manual","compliment_digest","suggestion_backlog",null],"description":"Most recent triage-brain decision, if any triage pass has run."},"triage_confidence":{"type":["number","null"],"description":"0..1 explainable confidence score from the most recent triage pass."},"triage_risk":{"type":["number","null"],"description":"0..1 explainable risk score from the most recent triage pass."},"cluster_id":{"type":["string","null"],"format":"uuid","description":"Dedup cluster this submission was attached to, if any (see status=duplicate)."},"cluster_member_count":{"type":["integer","null"],"description":"'N reporters affected' count for cluster_id, when present."},"work_item_repo":{"type":["string","null"],"description":"Repo the fleet work item was opened against, if one was created."},"work_item_url":{"type":["string","null"],"format":"uri","description":"URL of the Linear issue opened for this submission, if any."},"work_item_linear_status":{"type":["string","null"],"enum":["open","in_progress","done","released","canceled",null],"description":"Current status of the linked Linear issue, if any."},"work_item_dispatched_at":{"type":["string","null"],"format":"date-time","description":"When the fleet work item was created, if any."},"resolved_at":{"type":["string","null"],"format":"date-time","description":"When this submission was resolved, if it has been."},"resolution_source":{"type":["string","null"],"enum":["linear_webhook","manual",null],"description":"How the resolution was recorded, if resolved."},"acknowledged_at":{"type":["string","null"],"format":"date-time","description":"When the reporter acknowledged the resolution banner, if they have."}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/feedback/{id}/ack":{"post":{"operationId":"acknowledgeFeedback","summary":"Acknowledge one of the caller's own feedback submissions","description":"Writes a reporter acknowledgement for a submission the caller owns. Ownership is verified authoritatively in the API query before the write; a submission the caller does not own (or that does not exist) returns 404 without disclosing its existence. Idempotent on the submission id — a repeat ack creates no duplicate row and does not error (returns 200 either way). Inherits the standard per-IP REST rate limit.","tags":["Feedback"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The submission id to acknowledge."}],"responses":{"200":{"description":"Acknowledgement recorded (or already present — idempotent).","content":{"application/json":{"schema":{"type":"object","required":["submission_id","status"],"properties":{"submission_id":{"type":"string","format":"uuid"},"status":{"type":"string","const":"acknowledged","description":"Acknowledgement status."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/governance/signals":{"get":{"operationId":"listPlatformGovernanceSignals","summary":"List governance signals across the entire platform","description":"Cross-org listing for Mnemom platform admins. Optional `org_id` query narrows to one tenant. Other filters mirror the org-scope endpoint. Mnemom staff only (`app_metadata.is_admin = true`).","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"org_id","in":"query","required":false,"schema":{"type":"string"},"description":"Optional: narrow to a single org."},{"name":"source","in":"query","required":false,"schema":{"$ref":"#/components/schemas/GovernanceSignalSource"},"description":"Filter by source detector."},{"name":"severity","in":"query","required":false,"schema":{"$ref":"#/components/schemas/GovernanceSignalSeverity"},"description":"Filter by severity."},{"name":"status","in":"query","required":false,"schema":{"$ref":"#/components/schemas/GovernanceSignalStatus"},"description":"Filter by workflow status."},{"name":"pattern_type","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by pattern_type within the source's taxonomy."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"default":100}}],"responses":{"200":{"description":"Platform-scope governance signals listing.","content":{"application/json":{"schema":{"type":"object","required":["scope","signals"],"properties":{"scope":{"type":"string","enum":["platform"]},"signals":{"type":"array","items":{"$ref":"#/components/schemas/GovernanceSignal"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/governance/signals/{signal_id}":{"get":{"operationId":"getGovernanceSignal","summary":"Get a single governance signal by ID","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"signal_id","in":"path","required":true,"schema":{"type":"string","pattern":"^gs-[0-9a-f]{12}$"},"description":"Governance signal ID (gs-{12-hex})."}],"responses":{"200":{"description":"Governance signal.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GovernanceSignal"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/governance/signals/{signal_id}/acknowledge":{"post":{"operationId":"acknowledgeGovernanceSignal","summary":"Acknowledge a governance signal","description":"Records the actor + timestamp on the signal row. Captures `acknowledged_actor_role` per ADR-046 audit-actor model. Authorized: org_admin, org_owner, or team_admin grant for the signal's team.","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"signal_id","in":"path","required":true,"schema":{"type":"string","pattern":"^gs-[0-9a-f]{12}$"},"description":"Governance signal ID (gs-{12-hex})."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"action_taken":{"type":"string","description":"Optional note about what action is being taken."}}}}}},"responses":{"200":{"description":"Governance signal.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GovernanceSignal"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/governance/signals/{signal_id}/dismiss":{"post":{"operationId":"dismissGovernanceSignal","summary":"Dismiss a governance signal as not actionable","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"signal_id","in":"path","required":true,"schema":{"type":"string","pattern":"^gs-[0-9a-f]{12}$"},"description":"Governance signal ID (gs-{12-hex})."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"reason":{"type":"string","description":"Optional free-text note explaining why the signal is not actionable."}}}}}},"responses":{"200":{"description":"Governance signal.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GovernanceSignal"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/governance/signals/{signal_id}/resolve":{"post":{"operationId":"resolveGovernanceSignal","summary":"Resolve a governance signal","description":"Closes the signal with a `resolution_status` and optional `action_taken` note. Authorized: org_admin, org_owner, or team_admin.","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"signal_id","in":"path","required":true,"schema":{"type":"string","pattern":"^gs-[0-9a-f]{12}$"},"description":"Governance signal ID (gs-{12-hex})."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["resolution_status"],"properties":{"resolution_status":{"$ref":"#/components/schemas/GovernanceResolutionStatus","description":"Why the signal is being closed: action_taken, wont_fix, duplicate, false_positive, or self_resolved."},"action_taken":{"type":"string","description":"Optional free-text note describing the action taken to resolve the signal."}}}}}},"responses":{"200":{"description":"Governance signal.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GovernanceSignal"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/integrity/{agent_id}":{"get":{"operationId":"getIntegrityScore","security":[{},{"ApiKeyAuth":[]},{"BearerAuth":[]},{"CookieAuth":[]}],"summary":"Compute AAP integrity score","tags":["Integrity"],"parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"},"description":"Agent identifier whose AAP integrity score to compute (e.g. smolt-abc123)."}],"responses":{"200":{"description":"Integrity score","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrityScore"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/keys":{"get":{"operationId":"getSigningKeys","summary":"List signing keys","description":"List all active Ed25519 signing public keys. Public endpoint, no authentication required. These keys are used to verify IntegrityCertificate signatures.","tags":["Verification"],"security":[{}],"responses":{"200":{"description":"List of active signing keys","content":{"application/json":{"schema":{"type":"object","properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/SigningKeyInfo"}}}}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/license/validate":{"post":{"operationId":"validateLicense","summary":"Validate a license key (public)","tags":["Licensing"],"security":[{}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["license","instance_id"],"properties":{"license":{"type":"string","description":"License JWT token"},"instance_id":{"type":"string","description":"Unique instance identifier"},"instance_metadata":{"type":"object","additionalProperties":false,"description":"Optional: instance metadata (hostname, region, version only). No PII, API keys, or secrets allowed. Unknown fields are rejected.","properties":{"hostname":{"type":"string","maxLength":255,"description":"Instance hostname (e.g. server-prod-01)"},"region":{"type":"string","pattern":"^[a-z0-9-]+$","maxLength":64,"description":"Deployment region (e.g. us-1, eu-west, ap-southeast)"},"version":{"type":"string","pattern":"^[0-9]+\\.[0-9]+\\.[0-9]+$","description":"Instance software version (e.g. 1.2.3)"}}}}}}}},"responses":{"200":{"description":"License valid","content":{"application/json":{"schema":{"type":"object","properties":{"valid":{"type":"boolean"},"license_id":{"type":"string"},"plan_id":{"type":"string"},"feature_flags":{"type":"object","additionalProperties":{"type":"boolean"}},"limits":{"type":"object"},"expires_at":{"type":"string","format":"date-time"},"next_check_seconds":{"type":"integer"},"warning":{"type":["string","null"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"410":{"description":"License expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/mcp-servers":{"post":{"operationId":"createMcpServerClaim","summary":"Create an MCP-server ownership claim","description":"Starts a claim on an MCP server you operate (identified by its endpoint URL, e.g. `https://api.example.com/mcp`) and returns the DNS TXT record to place on the server's origin domain apex (`mnemom-verification=<token>`). Idempotent per (owner, server_id): re-POSTing the same server returns the same pending token. IP-literal hosts and non-http(s) URLs are rejected. Rate-limited per user and per IP.","tags":["MCP Servers"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["server_id"],"properties":{"server_id":{"type":"string","description":"The MCP server endpoint URL (e.g. `https://api.example.com/mcp`).","example":"https://api.example.com/mcp"}}}}}},"responses":{"200":{"description":"Claim created or idempotently re-fetched; TXT record returned.","content":{"application/json":{"schema":{"type":"object","required":["server_id","origin_domain","status","verification"],"properties":{"server_id":{"type":"string","example":"https://api.example.com/mcp"},"origin_domain":{"type":"string","example":"example.com"},"status":{"type":"string","enum":["pending","verified"]},"verified_at":{"type":"string","format":"date-time","nullable":true},"honor_roll":{"type":"boolean"},"response_note":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"},"verification":{"type":"object","description":"Everything needed to place the DNS TXT record at the origin domain apex (the domain that serves the MCP server).","required":["method","type","host","record"],"properties":{"method":{"type":"string","enum":["dns-txt"]},"type":{"type":"string","enum":["TXT"]},"host":{"type":"string","description":"Origin domain apex the record goes on."},"name":{"type":"string","description":"DNS record name (apex = `@`)."},"record":{"type":"string","description":"The exact TXT value: `mnemom-verification=<token>`."},"value":{"type":"string","description":"Alias of `record`."},"instructions":{"type":"string"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"get":{"operationId":"listMcpServerClaims","summary":"List my MCP-server claims","description":"Returns the caller's MCP-server claims with status, origin domain, verification time, Honor Roll opt-in, and public response note.","tags":["MCP Servers"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"The caller's claims.","content":{"application/json":{"schema":{"type":"object","required":["mcp_servers"],"properties":{"mcp_servers":{"type":"array","items":{"type":"object","required":["server_id","origin_domain","status","verified","honor_roll"],"properties":{"server_id":{"type":"string"},"origin_domain":{"type":"string"},"status":{"type":"string","enum":["pending","verified"]},"verified":{"type":"boolean"},"verified_at":{"type":"string","format":"date-time","nullable":true},"honor_roll":{"type":"boolean"},"response_note":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/mcp-servers/{id}/honor-roll":{"put":{"operationId":"setMcpServerHonorRoll","summary":"Opt a verified MCP server in/out of the Honor Roll","description":"Sets explicit, revocable Honor Roll consent for a verified MCP server. Verified claims only (409 otherwise). The `{id}` path parameter is the URL-encoded server endpoint URL.","tags":["MCP Servers"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["optIn"],"properties":{"optIn":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated Honor Roll state.","content":{"application/json":{"schema":{"type":"object","required":["server_id","honor_roll"],"properties":{"server_id":{"type":"string"},"honor_roll":{"type":"boolean"},"verified_at":{"type":"string","format":"date-time","nullable":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/mcp-servers/{id}/public-status":{"get":{"operationId":"getPublicMcpServerStatus","summary":"Public MCP-server claim status (no auth, no PII)","description":"Credential-free, cacheable projection consumed by the isittrustready.ai MCP-readiness rubric. Always returns 200; an unknown or unverified server yields `claimed:false`. Contains ZERO PII — only `server_id`, `claimed`, `honor_roll`, and the owner-published `response_note`. `Cache-Control: public, max-age=300`; `X-Robots-Tag: noindex`. The `{id}` path parameter is the URL-encoded server endpoint URL.","tags":["MCP Servers"],"security":[],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Public claim status (always 200).","content":{"application/json":{"schema":{"type":"object","required":["claimed"],"properties":{"server_id":{"type":"string","nullable":true},"claimed":{"type":"boolean"},"honor_roll":{"type":"boolean"},"response_note":{"type":"string","nullable":true}}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/mcp-servers/{id}/response-note":{"put":{"operationId":"setMcpServerResponseNote","summary":"Set a verified MCP server's public owner response","description":"Publishes a plain-text owner response (≤500 chars; control and bidi/zero-width characters are stripped server-side) rendered on the public MCP-readiness report. Verified claims only (409 otherwise). An empty note clears it. The `{id}` path parameter is the URL-encoded server endpoint URL.","tags":["MCP Servers"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["text"],"properties":{"text":{"type":"string","maxLength":500,"nullable":true}}}}}},"responses":{"200":{"description":"Updated response note.","content":{"application/json":{"schema":{"type":"object","required":["server_id"],"properties":{"server_id":{"type":"string"},"response_note":{"type":"string","nullable":true},"verified_at":{"type":"string","format":"date-time","nullable":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/mcp-servers/{id}/verify":{"post":{"operationId":"verifyMcpServerClaim","summary":"Verify an MCP-server claim via DNS TXT","description":"Looks up the origin domain apex TXT records over a fixed DoH resolver (Cloudflare 1.1.1.1) for `mnemom-verification=<token>`. Found → the claim is marked verified. Not found → `{claimed:false, reason:\"txt-not-found\"}` (HTTP 200; retry after DNS propagation). A successful verify by a different owner transfers control (anti-squat). The `{id}` path parameter is the URL-encoded server endpoint URL. Rate-limited per user and per IP.","tags":["MCP Servers"],"security":[{"CookieAuth":[]},{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The URL-encoded MCP server endpoint URL being verified."}],"responses":{"200":{"description":"Verification result (verified, or a friendly retryable not-found).","content":{"application/json":{"schema":{"type":"object","required":["claimed"],"properties":{"claimed":{"type":"boolean"},"verified_at":{"type":"string","format":"date-time","nullable":true},"reason":{"type":"string","enum":["txt-not-found"],"nullable":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/me/context":{"get":{"operationId":"getMyContext","summary":"Get the authenticated user's effective org-context envelope","description":"Returns the active org context, the full membership list, and any user preferences that affect the dashboard. Per ADR-044 Piece 1 / migration 164. The dashboard's authoritative endpoint for \"who am I, which org am I in, what are my memberships.\" `active` falls back to the most-recently-accepted multi-user org, then the personal org; `null` only if the user has zero memberships.","tags":["Auth"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"responses":{"200":{"description":"User context envelope.","content":{"application/json":{"schema":{"type":"object","required":["active","memberships","preferences"],"properties":{"active":{"oneOf":[{"type":"object","required":["org_id","name","slug","is_personal","is_owner","role"],"properties":{"org_id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"avatar_url":{"type":["string","null"]},"is_personal":{"type":"boolean"},"is_owner":{"type":"boolean"},"role":{"type":"string"},"company_name":{"type":["string","null"]},"release_ring":{"type":"string","enum":["internal","early_adopter","ga"],"description":"The active org's release ring (MNE-889), resolved from plan.feature_flags.release_ring. Defaults to 'ga' (general availability) — the caller-side input to the KV release switchboard that gates feature exposure without a redeploy."}}},{"type":"null"}]},"memberships":{"type":"array","items":{"type":"object","required":["org_id","name","slug","is_personal","is_owner","role"],"properties":{"org_id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"avatar_url":{"type":["string","null"]},"is_personal":{"type":"boolean"},"is_owner":{"type":"boolean"},"role":{"type":"string"},"accepted_at":{"type":["string","null"],"format":"date-time"},"company_name":{"type":["string","null"]}}}},"preferences":{"type":"object","additionalProperties":true,"description":"User preferences blob (e.g., active_org_id, onboarding_completed_at)."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"setMyActiveOrg","summary":"Set the authenticated user's active org","description":"Switches the user's active org via `set_user_active_org` RPC; the `active_org_id` is persisted to `user_preferences.preferences`. Body is `{ org_id: string }`. Returns the same envelope shape as `GET /me/context`. Returns 403 with `code: 'not_a_member'` if the user is not a member of the target org. Per ADR-044 Piece 1 / migration 164.","tags":["Auth"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["org_id"],"properties":{"org_id":{"type":"string","description":"Org ID to switch the active context to. The user must be a member."}}}}}},"responses":{"200":{"description":"Active org switched. Response envelope matches GET /me/context."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/me/logs/query":{"post":{"operationId":"queryMyLogs","summary":"Query your own org's diagnostic log lines (self-serve)","description":"MNE-382 (O8 supportability). Returns a STRUCTURED, ALLOWLISTED PROJECTION of the authenticated caller's OWN org's diagnostic log lines from the Tier-3 Loki mirror — operational metadata only (timestamp, level, event type, request_id, agent_id, status, duration_ms, http method, route template). The raw log body and any free-text `error` / `stack` / `message` / prompt / request-body content are never returned (GDPR data minimization). The org is resolved SERVER-SIDE from the authenticated identity and force-injected as the query scope; a caller can never name the org or supply a raw query (`org_id` / `query` / `selector` in the body → 400). Restricted to owner/admin/auditor. Fails closed: no resolvable org → 403; Loki creds unconfigured → 503.","tags":["Auth"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","description":"All fields optional. The query is always scoped to your org server-side; `org_id` / `query` / `selector` / `stream` are rejected (400).","properties":{"level":{"type":"string","enum":["debug","info","warn","error"],"description":"Filter to a single severity level."},"request_id":{"type":"string","description":"Filter to a single request_id."},"agent_id":{"type":"string","description":"Filter to a single agent_id."},"contains":{"type":"string","description":"Bounded substring line-filter term (max 128 chars)."},"start":{"description":"Window start (ISO-8601 or epoch-ms). Clamped to at most 7 days before `end`.","oneOf":[{"type":"string"},{"type":"number"}]},"end":{"description":"Window end (ISO-8601 or epoch-ms). Clamped to now.","oneOf":[{"type":"string"},{"type":"number"}]},"limit":{"type":"integer","minimum":1,"maximum":500,"description":"Max entries to return (default 100, capped at 500)."}}}}}},"responses":{"200":{"description":"Allowlisted operational-metadata projection of the org's matching log lines.","content":{"application/json":{"schema":{"type":"object","required":["org_id","query","count","entries"],"properties":{"org_id":{"type":"string","description":"The server-resolved org the query was scoped to."},"query":{"type":"string","description":"The server-built LogQL query."},"count":{"type":"integer"},"entries":{"type":"array","items":{"type":"object","required":["ts"],"properties":{"ts":{"type":"string","description":"Loki nanosecond timestamp."},"timestamp":{"type":"string"},"level":{"type":"string"},"event":{"type":"string","description":"Structured event TYPE token."},"request_id":{"type":"string"},"agent_id":{"type":"string"},"status":{"type":"integer"},"duration_ms":{"type":"number"},"method":{"type":"string"},"route":{"type":"string","description":"Route template (never a raw path)."}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"description":"The log backend query failed or was unreachable."},"503":{"description":"Self-serve log query is not available in this environment."}}}},"/mu/budgets":{"get":{"x-proxied-url":"MU_PUBLIC_URL","operationId":"getMuBudgets","summary":"Read the caller's org mu-engine budgets","description":"Returns the mu budgets configured for the authenticated caller's organization, optionally with month-to-date spend (`status=true`, which answers `{statuses:[{budget, spentMmu, pctOfSoft, crossedThresholds}]}` — the input a burn-down meter needs). Same org-context + RBAC resolution as `GET /billing/mu` (any org member may read). api forwards to the mnemom-mu upstream `GET /v1/budgets?account={accountId}` with the server-resolved account id; a client-supplied `account` parameter is overwritten, never trusted.","tags":["Mu"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"org_id","in":"query","required":false,"description":"Target org id. Defaults to the caller's primary org. A non-member is denied 403.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"When `true`, return budget STATUS (month-to-date spend + percent of soft cap + crossed alert thresholds) instead of the bare budget rows.","schema":{"type":"string","enum":["true"]}}],"responses":{"200":{"description":"mu budgets for the org (mnemom-mu response, verbatim).","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/mu/customer-sessions":{"post":{"x-proxied-url":"MU_PUBLIC_URL","operationId":"createMuCustomerSession","summary":"Mint a Stripe Customer Session for the caller's org (saved-method redisplay)","description":"Mints a short-lived Stripe Customer Session client secret for the authenticated caller's organization. Passed into `stripe.elements()` as `customerSessionClientSecret`, it lets the Payment Element redisplay the org's saved payment methods and offer the save-for-future checkbox — the modern returning-buyer flow. Creates a Stripe object only: no charge, no ledger movement. Owner/admin only, same org resolution as the purchase route. Takes NO request body — any body sent is ignored; api authors the upstream request entirely from the server-resolved `billing_account_id`. The secret expires roughly 30 minutes after minting, so request a fresh one per Payment Element mount. Response is mnemom-billing's verbatim `{stripeCustomerId, customerSessionClientSecret}` on 201.","tags":["Mu"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"org_id","in":"query","required":false,"description":"Target org id. Defaults to the caller's primary org. A non-member is denied 403.","schema":{"type":"string"}}],"responses":{"201":{"description":"Customer Session created (mnemom-billing response, verbatim): `{stripeCustomerId, customerSessionClientSecret}`.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/mu/purchase-intents":{"post":{"x-proxied-url":"MU_PUBLIC_URL","operationId":"createMuPurchaseIntent","summary":"Create a Stripe PaymentIntent to buy mu by dollar amount at the peg","description":"Creates a Stripe PaymentIntent for the authenticated caller's organization to buy mu at the fixed peg (1 mu = 1¢, face-only retail — MNE-3255). Owner/admin only (`org_id` query targets a specific org; a non-member or under-privileged caller is denied 403). api resolves the org's `billing_account_id` server-side and authors the upstream body itself — a client-supplied account reference is never forwarded. `amountUsdCents` must be a JSON integer; the min/max purchase bounds are enforced by mnemom-billing (its 400 passes back verbatim). `idempotencyKey` is REQUIRED — billing scopes the Stripe idempotency key to it so a retry of the same purchase cannot double-charge. Response is mnemom-billing's verbatim `{paymentIntentId, clientSecret, expectedMmu}` on 201; `expectedMmu` is a display prediction, never mint authority — the ledger credits only when `payment_intent.succeeded` arrives on the webhook.","tags":["Mu"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"org_id","in":"query","required":false,"description":"Target org id. Defaults to the caller's primary org. A non-member is denied 403.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["amountUsdCents","idempotencyKey"],"properties":{"amountUsdCents":{"type":"integer","description":"Whole USD cents to charge. Bounds are enforced by mnemom-billing (MIN/MAX_PURCHASE_CENTS), not mirrored here."},"idempotencyKey":{"type":"string","minLength":1,"maxLength":128,"description":"Caller-chosen retry key. billing composes the Stripe idempotency key from it, so re-submitting with the same key cannot double-charge."}},"additionalProperties":false}}}},"responses":{"201":{"description":"PaymentIntent created (mnemom-billing response, verbatim): `{paymentIntentId, clientSecret, expectedMmu}`.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/mu/setup-intents":{"post":{"x-proxied-url":"MU_PUBLIC_URL","operationId":"createMuSetupIntent","summary":"Create a Stripe SetupIntent to capture a card for the caller's org","description":"Creates a Stripe SetupIntent (card capture, no charge) for the authenticated caller's organization — the deliberate second ask of Pricing Model v2 (MNE-3255): sign-up needs no card, and capturing one triggers the one-time intro grant when `setup_intent.succeeded` arrives on the webhook (never on this call). Owner/admin only, same org resolution as the purchase route. Takes NO request body — any body sent is ignored; api authors the upstream request entirely from the server-resolved `billing_account_id`. Response is mnemom-billing's verbatim `{stripeCustomerId, setupIntentId, clientSecret}` on 201.","tags":["Mu"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"org_id","in":"query","required":false,"description":"Target org id. Defaults to the caller's primary org. A non-member is denied 403.","schema":{"type":"string"}}],"responses":{"201":{"description":"SetupIntent created (mnemom-billing response, verbatim): `{stripeCustomerId, setupIntentId, clientSecret}`.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/mu/stripe/webhook":{"post":{"x-proxied-url":"MU_PUBLIC_URL","operationId":"muStripeWebhook","security":[],"summary":"Stripe webhook for mu top-up grants (signature-authenticated upstream)","description":"Stripe → api → mnemom-mu grant path (MNE-2516). Accepts Stripe webhook deliveries (e.g. `payment_intent.succeeded`) and forwards them BYTE-VERBATIM to the ledger's `/v1/stripe/webhook` consumer, which verifies the `stripe-signature` header against its webhook secret and fail-closes (401 bad signature, 503 unconfigured). api adds no authentication of its own — the payload, not the transport, is what is authenticated — and no ledger logic. Purchase grants land exactly-once with Stripe provenance; retail grant creation happens ONLY through this path.","tags":["Mu"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Ledger webhook consumer result, passed through verbatim.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"Ledger consumer rejected the signature. Body is mnemom-mu's VERBATIM error shape (e.g. `{\"error\":\"bad_signature\"}`), NOT an api error envelope.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"description":"Ledger consumer is unconfigured (no webhook secret). Body is mnemom-mu's VERBATIM error shape, NOT an api error envelope.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/network/threat-state":{"get":{"operationId":"getNetworkThreatState","summary":"Per-axis Protection Network threat state","description":"Returns the current aggregated `network_campaign_state` grouped by axis (substrate / vertical / pattern / source), plus per-state totals. Backs the customer-facing L4 thermometer page. Public-aggregate disclosure: any authenticated principal may read; rows carry no per-tenant identifiers (L0 fingerprints only).","tags":["Network"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"max_buckets","in":"query","required":false,"description":"Top-N most elevated buckets returned per axis. Clamped to [1, 50]; default 10.","schema":{"type":"integer","minimum":1,"maximum":50,"default":10}}],"responses":{"200":{"description":"Aggregated threat state snapshot.","content":{"application/json":{"schema":{"type":"object","required":["snapshot_at","totals","by_substrate","by_vertical","by_pattern","by_source"],"properties":{"snapshot_at":{"type":"string","format":"date-time","description":"RPC evaluation timestamp."},"totals":{"type":"object","required":["calm","elevated","high","under_attack","total"],"properties":{"calm":{"type":"integer"},"elevated":{"type":"integer"},"high":{"type":"integer"},"under_attack":{"type":"integer"},"total":{"type":"integer"}}},"by_substrate":{"type":"array","items":{"$ref":"#/components/schemas/NetworkThreatBucket"}},"by_vertical":{"type":"array","items":{"$ref":"#/components/schemas/NetworkThreatBucket"}},"by_pattern":{"type":"array","items":{"$ref":"#/components/schemas/NetworkThreatBucket"}},"by_source":{"type":"array","items":{"$ref":"#/components/schemas/NetworkThreatBucket"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"}}}},"/oauth/authorize":{"get":{"operationId":"oauthAuthorize","summary":"OAuth 2.1 authorization endpoint (renders the consent screen)","description":"Begins the authorization-code + PKCE flow. Identity is delegated to Supabase GoTrue via the Mnemom session cookie; an unauthenticated user is redirected to the hosted login and returns here. With a valid session, renders the server-side consent screen listing the requested scopes in product language. PKCE S256 is mandatory; redirect_uri must exactly match one registered for the client.","tags":["OAuth"],"security":[],"parameters":[{"name":"response_type","in":"query","required":true,"schema":{"type":"string","enum":["code"]}},{"name":"client_id","in":"query","required":true,"schema":{"type":"string"}},{"name":"redirect_uri","in":"query","required":true,"schema":{"type":"string","format":"uri"}},{"name":"scope","in":"query","required":true,"schema":{"type":"string","example":"mcp:read mcp:write"}},{"name":"state","in":"query","required":false,"schema":{"type":"string"}},{"name":"code_challenge","in":"query","required":true,"schema":{"type":"string"}},{"name":"code_challenge_method","in":"query","required":true,"schema":{"type":"string","enum":["S256"]}}],"responses":{"200":{"description":"Consent screen (HTML).","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"Redirect to the hosted login (unauthenticated) or back to the client's redirect_uri with an error per RFC 6749 §4.1.2.1."},"400":{"description":"Unknown client_id or unregistered redirect_uri — rendered as an HTML error page; never redirected (open-redirect guard).","content":{"text/html":{"schema":{"type":"string"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"post":{"operationId":"oauthAuthorizeDecision","summary":"Submit the OAuth consent decision (Allow / Deny)","description":"Processes the consent form. On Allow, mints a single-use, 60-second authorization code bound to the client, the exact redirect_uri, and the PKCE challenge, then redirects back to the client with code + state. On Deny, redirects with error=access_denied. CSRF-protected (SameSite=Lax cookie + signed token); the acting org is bound here and is immutable for tokens minted from the code.","tags":["OAuth"],"security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","required":["decision","client_id","redirect_uri","code_challenge","scope","org_id","csrf"],"properties":{"decision":{"type":"string","enum":["allow","deny"]},"client_id":{"type":"string"},"redirect_uri":{"type":"string","format":"uri"},"state":{"type":"string"},"code_challenge":{"type":"string"},"code_challenge_method":{"type":"string","enum":["S256"]},"response_type":{"type":"string","enum":["code"]},"scope":{"type":"string"},"org_id":{"type":"string"},"csrf":{"type":"string"}}}}}},"responses":{"302":{"description":"Redirect back to the client with code+state, or with an OAuth error."},"400":{"description":"Invalid client/redirect_uri/org selection (HTML).","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"Session expired during consent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Invalid or missing CSRF token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/oauth/device":{"get":{"operationId":"oauthDeviceVerifyPage","summary":"Device verification page (RFC 8628 user-facing approval)","description":"Server-rendered approval page a human opens (from verification_uri / verification_uri_complete) to authorize a device. Unauthenticated users are redirected to the hosted login and returned here. Leads with the user_code so the human confirms it matches their device before an explicit Approve (RFC 8628 §5.4). Same origin as the AS so the session cookie + CSRF apply.","tags":["OAuth"],"security":[],"parameters":[{"name":"user_code","in":"query","required":false,"schema":{"type":"string","example":"BCDF-GHJK"}}],"responses":{"200":{"description":"The approval page (HTML), or a terminal result page (invalid/expired code).","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"Redirect to the hosted login (unauthenticated), returning here after sign-in."},"400":{"description":"Missing or malformed user_code (HTML).","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"No live device code for that user_code (HTML).","content":{"text/html":{"schema":{"type":"string"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"post":{"operationId":"oauthDeviceApprove","summary":"Submit the device approval decision (Approve / Deny)","description":"Processes the device verification form. On Approve, binds the device code to the authenticated user and the chosen org (default: the user's personal org) — the claim-first ownership moment — so the polling client can then exchange it for tokens. On Deny, marks the code denied. CSRF-protected (signed token bound to user + client + user_code); session must still be valid.","tags":["OAuth"],"security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","required":["user_code","decision","csrf"],"properties":{"user_code":{"type":"string"},"decision":{"type":"string","enum":["allow","deny"]},"org_id":{"type":"string"},"csrf":{"type":"string"}}}}}},"responses":{"200":{"description":"Terminal result page — authorized, denied, or code-not-found (HTML).","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"Malformed submission or invalid organization (HTML).","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"Session expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Invalid or missing CSRF token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No live device code for that user_code (HTML).","content":{"text/html":{"schema":{"type":"string"}}}},"409":{"description":"The code expired or was already used before approval committed (HTML).","content":{"text/html":{"schema":{"type":"string"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/oauth/device_authorization":{"post":{"operationId":"oauthDeviceAuthorization","summary":"OAuth 2.0 Device Authorization Request (RFC 8628)","description":"Begins the device authorization grant for headless agents / CLIs that cannot perform an interactive redirect. Returns a device_code (the polled secret), a short human-typed user_code, and verification URIs. Public-client posture; the device_code itself is the proof-of-possession (PKCE is not required). The user approves at verification_uri; the client then polls /oauth/token with grant_type=urn:ietf:params:oauth:grant-type:device_code.","tags":["OAuth"],"security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","required":["client_id"],"properties":{"client_id":{"type":"string"},"scope":{"type":"string","example":"mcp:read mcp:write"}}}}}},"responses":{"200":{"description":"Device authorization response (RFC 8628 §3.2).","content":{"application/json":{"schema":{"type":"object","required":["device_code","user_code","verification_uri","verification_uri_complete","expires_in","interval"],"properties":{"device_code":{"type":"string"},"user_code":{"type":"string"},"verification_uri":{"type":"string","format":"uri"},"verification_uri_complete":{"type":"string","format":"uri"},"expires_in":{"type":"integer"},"interval":{"type":"integer"}}}}}},"400":{"description":"OAuth error (invalid_request / invalid_scope).","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"error_description":{"type":"string"}}}}}},"401":{"description":"Unknown client_id (invalid_client).","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"error_description":{"type":"string"}}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/oauth/grants":{"get":{"operationId":"oauthListGrants","summary":"List an org's active OAuth grants (connected apps / sessions)","description":"Lists the live OAuth grants (unrevoked, refresh-token-unexpired) issued against an org — the owner-facing 'Connected apps / active sessions' view. Returns only non-secret metadata: client, scopes (including per-agent resource scopes), issued/expiry times, and a best-effort last-used stamp — never any token material or hash. Caller must be an owner or admin of `org_id`. Optionally filter to grants connected to a specific agent with `agent_id`.","tags":["OAuth"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"org_id","in":"query","required":true,"schema":{"type":"string"}},{"name":"agent_id","in":"query","required":false,"schema":{"type":"string"},"description":"Keep only grants carrying a resource scope (MNE-796) for this agent."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"The org's live grants.","content":{"application/json":{"schema":{"type":"object","properties":{"grants":{"type":"array","items":{"type":"object","description":"A live OAuth grant (active session / connected app). Carries only non-secret metadata — never any token material or hash.","properties":{"grant_id":{"type":"string","description":"Opaque grant id; address it in POST /oauth/grants/revoke."},"client_id":{"type":"string"},"user_id":{"type":"string","description":"The consenting user."},"org_id":{"type":"string","description":"The org the grant acts within (immutable post-issuance)."},"scopes":{"type":"array","items":{"type":"string"}},"issued_at":{"type":"string","format":"date-time"},"access_expires_at":{"type":"string","format":"date-time"},"refresh_expires_at":{"type":"string","format":"date-time"},"last_used_at":{"type":["string","null"],"format":"date-time","description":"Best-effort last-seen stamp; null if not yet observed."}}}},"org_id":{"type":"string"},"limit":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/oauth/grants/audit":{"get":{"operationId":"oauthGrantsAudit","summary":"OAuth grant-lifecycle audit trail for an org","description":"Lists the governance audit entries for the OAuth grant lifecycle (consent granted, consent denied, owner revocation) scoped to the owner's org, so revocation and consent are accountable. Caller must be an owner or admin of `org_id`. Carries no token material.","tags":["OAuth"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"org_id","in":"query","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"OAuth-lifecycle audit entries, newest first.","content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object","properties":{"action":{"type":"string"},"actor_user_id":{"type":["string","null"]},"actor_role":{"type":["string","null"]},"target_type":{"type":["string","null"]},"target_id":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"metadata":{"type":["object","null"],"additionalProperties":true}}}},"org_id":{"type":"string"},"limit":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/oauth/grants/revoke":{"post":{"operationId":"oauthRevokeGrant","summary":"Owner-initiated revocation of an OAuth grant by id","description":"Revokes a grant the caller owns, by its opaque `grant_id`, within an org the caller owns/admins. Distinct from RFC 7009 POST /oauth/revoke (which lets a token HOLDER revoke its OWN token). Idempotent: revoking an already-revoked grant in the caller's org returns revoked:true with already_revoked:true. The revocation cascades to the grant's refresh token (a single grant row holds both the access and refresh token hashes), and is recorded on the org's audit trail (action=oauth.grant_revoked). A grant in another org — or unknown — returns 404 with no distinction (no cross-org existence oracle).","tags":["OAuth"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["grant_id","org_id"],"properties":{"grant_id":{"type":"string"},"org_id":{"type":"string"}}}}}},"responses":{"200":{"description":"The grant is revoked (idempotent).","content":{"application/json":{"schema":{"type":"object","properties":{"revoked":{"type":"boolean","enum":[true]},"grant_id":{"type":"string"},"already_revoked":{"type":"boolean","description":"true when the grant was already revoked before this call."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/oauth/introspect":{"post":{"operationId":"oauthIntrospect","summary":"OAuth 2.0 token introspection (RFC 7662)","description":"Returns the activeness + metadata of an access token per RFC 7662. The caller MUST authenticate: because Mnemom's OAuth clients are public (no client secret), there is no client-credentials path, so the caller authenticates as a USER (bearer / api-key / cookie). active:true with full metadata is returned ONLY when the token is live AND the authenticated caller owns/admins the token's org; otherwise the response is {active:false} with no other fields — the endpoint is never a token existence/validity oracle for tokens the caller does not control. Only opaque access tokens (mcp_at_) are introspectable; refresh tokens and unknown values report active:false.","tags":["OAuth"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"The access token to introspect."},"token_type_hint":{"type":"string","enum":["access_token"]}}}},"application/x-www-form-urlencoded":{"schema":{"type":"object","required":["token"],"properties":{"token":{"type":"string"},"token_type_hint":{"type":"string","enum":["access_token"]}}}}}},"responses":{"200":{"description":"RFC 7662 introspection response.","content":{"application/json":{"schema":{"type":"object","required":["active"],"properties":{"active":{"type":"boolean"},"scope":{"type":"string"},"client_id":{"type":"string"},"token_type":{"type":"string","enum":["Bearer"]},"exp":{"type":"integer","description":"Expiry, seconds since epoch."},"sub":{"type":"string","description":"The consenting user id."},"org_id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/oauth/register":{"post":{"operationId":"oauthRegisterClient","summary":"OAuth 2.0 Dynamic Client Registration (RFC 7591)","description":"Registers a public OAuth client for the MCP flow. No client secret is issued (PKCE-protected public clients only). redirect_uris must be HTTPS, or an RFC 8252 loopback (http://127.0.0.1[:port]/..., http://[::1][:port]/..., or http://localhost[:port]/...), and are exact-matched at /authorize. Registration is abuse-guarded with per-IP and global daily caps.","tags":["OAuth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["client_name"],"properties":{"client_name":{"type":"string","maxLength":200},"redirect_uris":{"type":"array","items":{"type":"string","format":"uri"},"minItems":1,"maxItems":5},"grant_types":{"type":"array","items":{"type":"string"},"description":"Requested grant types. A client requesting ONLY urn:ietf:params:oauth:grant-type:device_code (RFC 8628 device flow) may omit redirect_uris; any authorization_code client must supply at least one redirect_uri."},"token_endpoint_auth_method":{"type":"string","enum":["none"]},"response_types":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"201":{"description":"Client registered (RFC 7591 §3.2.1 client information response).","content":{"application/json":{"schema":{"type":"object","required":["client_id","redirect_uris"],"properties":{"client_id":{"type":"string"},"client_name":{"type":"string"},"redirect_uris":{"type":"array","items":{"type":"string"}},"token_endpoint_auth_method":{"type":"string","enum":["none"]},"grant_types":{"type":"array","items":{"type":"string"}},"response_types":{"type":"array","items":{"type":"string"}},"client_id_issued_at":{"type":"integer"}}}}}},"400":{"description":"Invalid client metadata or redirect_uri.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"error_description":{"type":"string"}}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/oauth/revoke":{"post":{"operationId":"oauthRevoke","summary":"OAuth token revocation (RFC 7009)","description":"Revokes the presented access or refresh token. Returns 200 even for an unknown token, per RFC 7009 §2.2.","tags":["OAuth"],"security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","required":["token"],"properties":{"token":{"type":"string"},"token_type_hint":{"type":"string","enum":["access_token","refresh_token"]}}}}}},"responses":{"200":{"description":"Token revoked (or already unknown)."},"400":{"description":"Missing token parameter.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"error_description":{"type":"string"}}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/oauth/token":{"post":{"operationId":"oauthToken","summary":"OAuth 2.1 token endpoint (code exchange + refresh)","description":"Exchanges an authorization code (+ PKCE code_verifier) for a short-lived opaque access token and a rotating refresh token, or rotates a refresh token. Authorization codes are single-use; refresh tokens are single-use (rotated on every exchange). Public-client posture: no client authentication (token_endpoint_auth_method=none).","tags":["OAuth"],"security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","required":["grant_type"],"properties":{"grant_type":{"type":"string","enum":["authorization_code","refresh_token","urn:ietf:params:oauth:grant-type:device_code"]},"code":{"type":"string"},"redirect_uri":{"type":"string","format":"uri"},"client_id":{"type":"string"},"code_verifier":{"type":"string"},"refresh_token":{"type":"string"},"device_code":{"type":"string"}}}}}},"responses":{"200":{"description":"Token response (RFC 6749 §5.1).","content":{"application/json":{"schema":{"type":"object","required":["access_token","token_type","expires_in"],"properties":{"access_token":{"type":"string"},"token_type":{"type":"string","enum":["Bearer"]},"expires_in":{"type":"integer"},"refresh_token":{"type":"string"},"scope":{"type":"string"}}}}}},"400":{"description":"OAuth error (invalid_request / invalid_grant / unsupported_grant_type / authorization_pending / slow_down / expired_token / access_denied).","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"error_description":{"type":"string"}}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/on-chain/history":{"get":{"operationId":"getOnChainHistory","summary":"Get on-chain history","description":"Retrieve the history of on-chain Merkle root anchoring events. Returns a paginated list of all anchors with their transaction details, included agents, and verification status.","tags":["On-Chain"],"security":[],"parameters":[{"name":"chain","in":"query","schema":{"type":"string","enum":["base-sepolia","base"]},"description":"Filter by blockchain network (matches on_chain_anchors.chain CHECK constraint)"},{"name":"agent_id","in":"query","schema":{"type":"string"},"description":"Filter anchors that include this agent"},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"},"description":"Start of time range"},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"},"description":"End of time range"},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"minimum":1,"maximum":100},"description":"Maximum number of records to return (handler default 50; values above 100 are clamped to 100)."},{"name":"offset","in":"query","schema":{"type":"integer","default":0,"minimum":0},"description":"Number of records to skip for pagination"}],"responses":{"200":{"description":"On-chain anchoring history: the page of anchor rows plus the effective `limit`/`offset` echoed back by the handler (handleGetAnchoringHistory in src/on-chain/handlers.ts).","content":{"application/json":{"schema":{"type":"object","required":["anchors"],"properties":{"anchors":{"type":"array","items":{"$ref":"#/components/schemas/OnChainAnchorResult"}},"limit":{"type":"integer","description":"Effective page size applied to this response."},"offset":{"type":"integer","description":"Effective offset applied to this response."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/on-chain/status/{agent_id}":{"get":{"operationId":"getOnChainStatus","summary":"Get on-chain status","description":"Get the current on-chain anchoring status for an agent. Returns the most recent anchor, pending publications, and overall on-chain coverage statistics.","tags":["On-Chain"],"security":[],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"On-chain status for the agent, as assembled by the get_on_chain_status RPC (migrations 057/058): the agent's latest score publication, the latest confirmed anchor, and the agent's current Merkle-tree summary. Each of the three nested objects is `null` when no matching row exists.","content":{"application/json":{"schema":{"type":"object","required":["agent_id"],"properties":{"agent_id":{"type":"string"},"latest_score_publication":{"description":"The agent's most recent row in score_publications, or `null` when the agent has never been published.","anyOf":[{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string"},"score":{"type":"integer"},"grade":{"type":"string"},"tx_hash":{"type":["string","null"]},"block_number":{"type":["integer","null"]},"chain":{"type":"string","enum":["base-sepolia","base"]},"status":{"type":"string","enum":["pending","confirmed","failed"]},"published_at":{"type":"string","format":"date-time"}}},{"type":"null"}]},"latest_anchor":{"description":"The most recent `confirmed` on-chain anchor, or `null` when none is confirmed yet. (The RPC filters to status='confirmed' and omits gas_used/created_at.)","anyOf":[{"$ref":"#/components/schemas/OnChainAnchorResult"},{"type":"null"}]},"merkle_tree":{"description":"Summary of the agent's current Merkle tree (from agent_merkle_trees), or `null` when the agent has no tree.","anyOf":[{"type":"object","additionalProperties":true,"properties":{"merkle_root":{"type":["string","null"]},"leaf_count":{"type":["integer","null"]},"tree_depth":{"type":["integer","null"]},"updated_at":{"type":["string","null"],"format":"date-time"}}},{"type":"null"}]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/on-chain/verify-proof/{agent_id}":{"get":{"operationId":"verifyOnChainProof","summary":"Verify on-chain proof","description":"Verify an agent's integrity or score proof against the on-chain Merkle root. Checks that the provided proof correctly links the agent's data to an anchored root, confirming the data has not been tampered with since anchoring.","tags":["On-Chain"],"security":[],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"anchor_id","in":"query","schema":{"type":"string"},"description":"Specific anchor ID to verify against. If omitted, verifies against the most recent anchor."},{"name":"score_type","in":"query","schema":{"type":"string","enum":["integrity","reputation","compliance"]},"description":"Type of score proof to verify"}],"responses":{"200":{"description":"Proof verification result. `verified` reflects whether the agent's current Merkle root is anchored on-chain with a `confirmed` anchor. When not verified, `reason` explains why (`no_merkle_tree`, `no_checkpoint`, `not_anchored`). When verified, the confirming `anchor` is included. (handleVerifyProof in src/on-chain/handlers.ts.)","content":{"application/json":{"schema":{"type":"object","required":["verified","agent_id"],"properties":{"verified":{"type":"boolean","description":"True when a confirmed on-chain anchor covers the agent's current Merkle root."},"agent_id":{"type":"string"},"reason":{"type":"string","enum":["no_merkle_tree","no_checkpoint","not_anchored"],"description":"Present only when `verified` is false. `no_merkle_tree`: the agent has no merkle tree row; `no_checkpoint`: the tree has no merkle_root yet; `not_anchored`: the root exists but has no confirmed anchor."},"merkle_root":{"type":"string","description":"The agent's current Merkle root. Present when a checkpoint exists (i.e. absent for the `no_merkle_tree`/`no_checkpoint` cases)."},"anchor":{"type":"object","description":"The confirming anchor. Present only when `verified` is true.","properties":{"tx_hash":{"type":["string","null"]},"block_number":{"type":["integer","null"]},"chain":{"type":"string","enum":["base-sepolia","base"]},"anchored_at":{"type":"string","format":"date-time"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs":{"post":{"operationId":"createOrg","summary":"Create organization","tags":["Organizations"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","slug"],"properties":{"name":{"type":"string","minLength":2,"maxLength":100},"slug":{"type":"string","minLength":3,"maxLength":48,"pattern":"^[a-z0-9][a-z0-9-]*[a-z0-9]$"}}}}}},"responses":{"201":{"description":"Organization created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Organization"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"get":{"operationId":"listMyOrgs","summary":"List organizations for authenticated user","tags":["Organizations"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Organizations list","content":{"application/json":{"schema":{"type":"object","properties":{"orgs":{"type":"array","items":{"$ref":"#/components/schemas/Organization"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/invitations/accept":{"post":{"operationId":"acceptInvitation","summary":"Accept an organization invitation","tags":["Organizations"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token"],"properties":{"token":{"type":"string"}}}}}},"responses":{"200":{"description":"Invitation accepted","content":{"application/json":{"schema":{"type":"object","properties":{"org_id":{"type":"string"},"org_name":{"type":"string"},"role":{"type":"string"},"personal_subscription_warning":{"type":["string","null"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}":{"get":{"operationId":"getOrg","summary":"Get organization details","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"description":"Organization details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Organization"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"updateOrg","summary":"Update organization","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"},"billing_email":{"type":"string"},"company_name":{"type":"string"}}}}}},"responses":{"200":{"description":"Organization updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Organization"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"delete":{"operationId":"deleteOrg","summary":"Delete organization (owner only)","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"description":"Organization deleted","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/agents":{"get":{"operationId":"getOrgAgents","summary":"List agents in organization","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"mine","in":"query","schema":{"type":"boolean","default":false},"description":"Filter to only current user's agents"},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"minimum":1,"maximum":500},"description":"Opt-in pagination: max agents to return. Omit limit AND offset for the full (unpaginated) listing. When supplied, the response adds total/limit/offset."},{"name":"offset","in":"query","schema":{"type":"integer","default":0,"minimum":0},"description":"Opt-in pagination: number of agents to skip."},{"name":"groupId","in":"query","schema":{"type":"string"},"description":"Filter the fleet by agent group. A group `<uuid>` returns only that group's members; the literal `ungrouped` returns only agents in no active group. A foreign-org or unknown id returns an empty page (indistinguishable from a missing id — no existence leak). The filter is applied before pagination, so `total` reflects it. Has NO effect when `scope=archived` (archived rows do not carry group data)."}],"responses":{"200":{"description":"Organization agents. Includes total/limit/offset only when limit or offset was supplied.","content":{"application/json":{"schema":{"type":"object","required":["agents"],"properties":{"agents":{"type":"array","items":{"$ref":"#/components/schemas/Agent"}},"total":{"type":"integer","description":"Total agents before pagination (present only when paginating)."},"limit":{"type":"integer","description":"Echoed page size (paginated only)."},"offset":{"type":"integer","description":"Echoed offset (paginated only)."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/orgs/{org_id}/agents/safe-house-summary":{"get":{"operationId":"getOrgAgentsSafeHouseSummary","summary":"Fleet view of each member agent's Safe House posture","tags":["Safe House"],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"description":"Per-agent posture summary.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/agents/{agent_id}/containment":{"get":{"operationId":"getAgentContainment","summary":"Get agent containment status","description":"Returns the current containment status and recent audit log entries. Any org role.","tags":["Agent Containment"],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Containment status","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"status":{"type":"string","enum":["active","paused","killed"]},"contained_at":{"type":["string","null"],"format":"date-time"},"contained_by":{"type":["string","null"]},"containment_reason":{"type":["string","null"]},"auto_containment_threshold":{"type":["integer","null"]},"log":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"action":{"type":"string"},"actor":{"type":"string"},"reason":{"type":["string","null"]},"previous_status":{"type":"string"},"new_status":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}},"security":[{"BearerAuth":[]}]}},"/orgs/{org_id}/agents/{agent_id}/containment-policy":{"put":{"operationId":"updateContainmentPolicy","summary":"Update auto-containment policy","description":"Set or disable the auto-containment threshold. When set, the agent will be automatically paused after N consecutive boundary violations. Requires owner or admin role.","tags":["Agent Containment"],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["auto_containment_threshold"],"properties":{"auto_containment_threshold":{"type":["integer","null"],"minimum":2,"description":"Number of consecutive boundary violations before auto-pause. Set to null to disable."}}}}}},"responses":{"200":{"description":"Policy updated","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"auto_containment_threshold":{"type":["integer","null"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}},"security":[{"BearerAuth":[]}]}},"/orgs/{org_id}/agents/{agent_id}/kill":{"post":{"operationId":"killAgent","summary":"Kill an agent","description":"Permanently stop an agent. Requires explicit reactivation to restore. Owner only.","tags":["Agent Containment"],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","description":"Reason for killing the agent"}}}}}},"responses":{"200":{"description":"Agent killed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"containment_status":{"type":"string","enum":["killed"]},"contained_at":{"type":"string","format":"date-time"},"contained_by":{"type":"string"},"containment_reason":{"type":["string","null"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}},"security":[{"BearerAuth":[]}]}},"/orgs/{org_id}/agents/{agent_id}/pause":{"post":{"operationId":"pauseAgent","summary":"Pause an agent","description":"Temporarily stop an agent from making API requests. Requires owner or admin role.","tags":["Agent Containment"],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","description":"Reason for pausing the agent"}}}}}},"responses":{"200":{"description":"Agent paused successfully","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"containment_status":{"type":"string","enum":["paused"]},"contained_at":{"type":"string","format":"date-time"},"contained_by":{"type":"string"},"containment_reason":{"type":["string","null"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}},"security":[{"BearerAuth":[]}]}},"/orgs/{org_id}/agents/{agent_id}/reactivate":{"post":{"operationId":"reactivateAgent","summary":"Reactivate a killed agent","description":"Restore a killed agent back to active state. Owner only.","tags":["Agent Containment"],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Agent reactivated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"containment_status":{"type":"string","enum":["active"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}},"security":[{"BearerAuth":[]}]}},"/orgs/{org_id}/agents/{agent_id}/resume":{"post":{"operationId":"resumeAgent","summary":"Resume a paused agent","description":"Resume a paused agent back to active state. Only works on paused agents. Requires owner or admin role.","tags":["Agent Containment"],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Agent resumed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"containment_status":{"type":"string","enum":["active"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}},"security":[{"BearerAuth":[]}]}},"/orgs/{org_id}/alignment-template":{"get":{"operationId":"getOrgAlignmentTemplateLegacy","summary":"DEPRECATED — use GET /v1/alignment/org/{org_id}.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/alignment/org/{org_id}`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Card Templates"],"security":[],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"putOrgAlignmentTemplateLegacy","summary":"DEPRECATED — use PUT /v1/alignment/org/{org_id}.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/alignment/org/{org_id}`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Card Templates"],"security":[],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"delete":{"operationId":"deleteOrgAlignmentTemplateLegacy","summary":"DEPRECATED — use DELETE /v1/alignment/org/{org_id}.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/alignment/org/{org_id}`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Card Templates"],"security":[],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/alignment-template/preview-compose":{"post":{"operationId":"postOrgAlignmentTemplatePreviewComposeLegacy","summary":"DEPRECATED — use POST /v1/alignment/org/{org_id}/preview-compose.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/alignment/org/{org_id}/preview-compose`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Card Templates"],"security":[],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/api-keys":{"post":{"operationId":"createOrgApiKey","summary":"Create organization API key","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"description":"Friendly name for the key (e.g., \"ci-prod\")."},"scopes":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyScope"},"default":["gateway","api:read","api:write"],"description":"Capability set for this org key (ADR-049). If omitted, the API substitutes the default. The caller is already verified as owner/admin of this org by the route's RBAC gate, so `admin:org` is implicit-eligible here; `admin:platform` still requires Mnemom-staff role."}}}}}},"responses":{"201":{"description":"Org API key created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKey"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"get":{"operationId":"listOrgApiKeys","summary":"List organization API keys","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"description":"Org API keys","content":{"application/json":{"schema":{"type":"object","properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/api-keys/{key_id}":{"delete":{"operationId":"revokeOrgApiKey","summary":"Revoke organization API key","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"key_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Key revoked","content":{"application/json":{"schema":{"type":"object","properties":{"revoked":{"type":"boolean"},"key_id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/api-keys/{key_id}/rotate":{"post":{"operationId":"rotateOrgApiKey","summary":"Rotate an organization API key","description":"Atomic mint-new + immediately-revoke-old, with the same `name` and `scopes` as the original. The full new secret is returned only in this response. No grace period — old key is invalid immediately. If you need overlap with an in-flight deploy, create a second key first via `POST /orgs/{org_id}/api-keys`, ship, then `DELETE` the old key. Owners and admins may rotate any org key; members may rotate keys they created.","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"key_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"New key minted, old key revoked.","content":{"application/json":{"schema":{"type":"object","properties":{"key_id":{"type":"string"},"key":{"type":"string","description":"Full secret. Capture now — never returned again."},"key_prefix":{"type":"string"},"name":{"type":"string"},"org_id":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"rotated_from":{"type":"string"},"old_key_revoked_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/audit-log":{"get":{"operationId":"getOrgAuditLog","summary":"Read the org audit log","description":"Returns request-level audit entries scoped to this org: events made with an org-level API key, plus any event on a `/v1/orgs/{org_id}/...` URL. Excludes Mnemom-staff actions on `/v1/admin/*` paths. Compliance-shaped — `owner`, `admin`, and `auditor` roles only.","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Audit entries, newest first.","content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"http_method":{"type":"string"},"path":{"type":"string"},"auth_method":{"type":"string","enum":["jwt","api_key","cookie","oauth","test_mode"]},"principal_type":{"type":"string","enum":["user","org"]},"principal_id":{"type":"string"},"key_id":{"type":["string","null"]},"status_code":{"type":"integer"}}}},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/avatar":{"put":{"operationId":"putOrgAvatar","summary":"Upload organization avatar","description":"Replace an organization's avatar image. Requires the authenticated principal to hold `owner` or `admin` role on the org.","tags":["Orgs"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"Avatar image. Validated for MIME type and size before upload."}}}}}},"responses":{"200":{"description":"Avatar uploaded; persistent URL returned","content":{"application/json":{"schema":{"type":"object","required":["avatar_url"],"properties":{"avatar_url":{"type":"string","format":"uri","description":"Public URL of the uploaded avatar (CDN-served).","example":"https://cdn.mnemom.ai/avatars/agents/mnm-7f3b9e2a/abc123.png"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"}}}},"/orgs/{org_id}/billing/portal-session":{"post":{"operationId":"createOrgBillingPortalSession","summary":"Open the Stripe Customer Portal for this org","description":"Mints a single-use URL into Stripe's hosted Customer Portal where the org owner can view invoices, download PDFs, update payment methods, change billing details, and manage their subscription. The portal is the primary surface for invoice access — there is no direct invoice API. `owner` only (the portal is a mixed read+mutate surface exposing subscription cancel / payment-method mutation; per the org RBAC matrix only `owner` holds `billing: full`, while `admin` and `auditor` hold `billing: view` and have a separate read-only path via `GET /orgs/{org_id}/billing/summary`). A non-owner receives 403 before any billing state is read — Stripe-customer existence is never disclosed to unauthorized roles.","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"return_url":{"type":"string","format":"uri","description":"Where Stripe redirects the customer after they finish in the portal. Must be `https://*.mnemom.ai`. Defaults to the dashboard billing page."}}}}}},"responses":{"200":{"description":"Portal session created. Redirect the customer to `url`.","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/billing/summary":{"get":{"operationId":"getOrgBillingSummary","summary":"Read-only billing summary for the org","description":"Plan + customer-safe account state + 30-day usage rollup. Does **not** include invoice history (use `POST /orgs/{org_id}/billing/portal-session` for that) or recent billing events (the org audit log covers events generally). Internal Stripe identifiers and Mnemom-staff notes are scrubbed from the response. `owner`, `admin`, and `auditor` only.","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"description":"Summary payload.","content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"object","additionalProperties":true},"plan":{"type":"object","additionalProperties":true},"usage_rollup":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","format":"date"},"check_count":{"type":"integer"},"tokens_in":{"type":"integer"},"tokens_out":{"type":"integer"},"cost_estimate":{"type":"number"}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/coherence":{"get":{"operationId":"getOrgCoherence","summary":"N-Way value coherence for the org fleet (with care-framed recommendations)","description":"Returns a dimensional team-coherence vector (pairwise_governance_median / floor / max, conflict_edge_count, outlier_agents, pairwise) computed from the active alignment cards of every agent in the org. The response also carries `recommendations[]` — care-framed actionable suggestions derived from the structural findings (cards-as-primitive Phase 4 W2.5). Requires at least 2 agents with alignment cards — returns `insufficient_agents` otherwise. Cached 5 minutes in `fleet_coherence_snapshots`; recommendations are recomputed on each read so older snapshots gain the field without backfill. Feature-gated: `nway_coherence`. See ADR-025 (E-05).","tags":["Organizations"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"x-feature-gate":"nway_coherence","parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"description":"Team-coherence result (or `insufficient_agents` stub).","content":{"application/json":{"schema":{"anyOf":[{"type":"object","description":"Team-coherence vector (v2 / ADR-025).","additionalProperties":true,"properties":{"pair_count":{"type":"integer"},"pairwise_governance_median":{"type":["number","null"]},"pairwise_governance_floor":{"type":["number","null"]},"conflict_edge_count":{"type":"integer"},"outlier_agents":{"type":"array"},"pairwise":{"type":"array"},"conscience_universal":{"type":["boolean","null"]},"recommendations":{"type":"array","description":"Care-framed actionable recommendations derived from the structural findings. Each entry carries a `for_finding` discriminator (`outlier_agents`, `pairwise_governance_floor`, `conflict_edges`) plus interpretive prose. cards-as-primitive Phase 4 W2.5.","items":{"type":"object","required":["for_finding","text"],"properties":{"for_finding":{"type":"string","enum":["outlier_agents","pairwise_governance_floor","conflict_edges"]},"text":{"type":"string"}}}}}},{"type":"object","properties":{"error":{"type":"string","enum":["insufficient_agents"]},"agent_count":{"type":"integer"},"message":{"type":"string"}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/orgs/{org_id}/conscience-values":{"get":{"operationId":"listOrgConscienceValues","summary":"List org conscience values","description":"Returns all conscience values for the org, along with mode and enabled status. Requires Enterprise plan with custom_conscience_values feature flag.","tags":["Conscience Values"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Conscience values list","content":{"application/json":{"schema":{"type":"object","properties":{"org_id":{"type":"string"},"mode":{"type":"string","enum":["augment","replace"]},"enabled":{"type":"boolean"},"values":{"type":"array","items":{"$ref":"#/components/schemas/OrgConscienceValue"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"post":{"operationId":"createOrgConscienceValue","summary":"Create org conscience value","description":"Create a new custom conscience value. Max 20 per org. Requires owner or admin role.","tags":["Conscience Values"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","description","type"],"properties":{"name":{"type":"string","minLength":1,"maxLength":50},"description":{"type":"string","minLength":1,"maxLength":500},"type":{"type":"string","enum":["BOUNDARY","FEAR","COMMITMENT","BELIEF","HOPE"]},"severity":{"type":"string","enum":["advisory","mandatory"],"default":"advisory"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgConscienceValue"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/orgs/{org_id}/conscience-values/log":{"get":{"operationId":"getOrgConscienceAuditLog","summary":"Get conscience values audit log","description":"Returns the audit trail for conscience value changes. Requires owner, admin, or auditor role.","tags":["Conscience Values"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Audit log entries","content":{"application/json":{"schema":{"type":"object","properties":{"org_id":{"type":"string"},"entries":{"type":"array","items":{"$ref":"#/components/schemas/OrgConscienceAuditEntry"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/orgs/{org_id}/conscience-values/mode":{"put":{"operationId":"updateOrgConscienceMode","summary":"Update org conscience mode","description":"Set the conscience mode (augment/replace) and enabled flag.","tags":["Conscience Values"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["augment","replace"]},"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"org_id":{"type":"string"},"mode":{"type":"string","enum":["augment","replace"]},"enabled":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/orgs/{org_id}/conscience-values/order":{"put":{"operationId":"reorderOrgConscienceValues","summary":"Reorder org conscience values","description":"Set the sort order for all conscience values.","tags":["Conscience Values"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["order"],"properties":{"order":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Reordered","content":{"application/json":{"schema":{"type":"object","properties":{"reordered":{"type":"boolean"},"order":{"type":"array","items":{"type":"string"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/orgs/{org_id}/conscience-values/{value_id}":{"patch":{"operationId":"updateOrgConscienceValue","summary":"Update org conscience value","description":"Update fields on an existing conscience value. Requires owner or admin role.","tags":["Conscience Values"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"value_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":50},"description":{"type":"string","minLength":1,"maxLength":500},"type":{"type":"string","enum":["BOUNDARY","FEAR","COMMITMENT","BELIEF","HOPE"]},"severity":{"type":"string","enum":["advisory","mandatory"]},"is_active":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgConscienceValue"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"delete":{"operationId":"deleteOrgConscienceValue","summary":"Delete org conscience value","description":"Permanently delete a conscience value. Requires owner or admin role.","tags":["Conscience Values"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"value_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"},"id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/orgs/{org_id}/costs":{"get":{"operationId":"getOrgCosts","summary":"Per-model cost rollup for the org","description":"Daily usage broken down by model with a USD cost estimate per row plus aggregate totals. Cost figures are estimates derived from Mnemom's published per-model pricing applied to your actual token volume; authoritative billing is in Stripe (see `POST /orgs/{org_id}/billing/portal-session`). Billing-shaped — `owner`, `admin`, and `auditor` only.","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"days","in":"query","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}}],"responses":{"200":{"description":"Daily cost rows + totals.","content":{"application/json":{"schema":{"type":"object","properties":{"period":{"type":"string","example":"daily"},"days":{"type":"integer"},"data":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","format":"date"},"model":{"type":"string"},"tokens_in":{"type":"integer"},"tokens_out":{"type":"integer"},"request_count":{"type":"integer"},"cost_usd":{"type":"number"}}}},"totals":{"type":"object","properties":{"total_cost_usd":{"type":"number"},"total_tokens_in":{"type":"integer"},"total_tokens_out":{"type":"integer"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/customer-voice":{"delete":{"operationId":"deleteOrgCustomerVoice","summary":"Erase all this org's Customer Voice feedback (GDPR)","description":"Bulk-erases every Aletheia Customer Voice feedback submission for this org via the SECURITY DEFINER `org_feedback_erase` RPC (migration 465), which deletes the org's `feedback_dispatch_overrides` rows first (unblocking their `ON DELETE RESTRICT` FK, MNE-2055) before deleting `feedback_submissions` (cascading to context bundle / attachments / triage / work items / resolutions / acknowledgements). Scoped strictly to `org_id` — an org can never erase another org's feedback. `owner`/`admin` only. Idempotent: a repeat call returns `deleted: 0`. Every erasure is recorded to the governance audit trail.","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"description":"Erasure receipt (AC4) — the number of submissions deleted by this call.","content":{"application/json":{"schema":{"type":"object","required":["deleted","org_id"],"properties":{"deleted":{"type":"integer"},"org_id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/customer-voice/export":{"get":{"operationId":"getOrgCustomerVoiceExport","summary":"Export this org's Customer Voice feedback (GDPR)","description":"Exports every Aletheia Customer Voice feedback submission for this org, for GDPR data-portability requests (`customer-voice-privacy.mdx`). Paginates the SECURITY DEFINER `org_feedback_read` RPC (migration 405) internally so the export is never silently truncated at the RPC's per-call page cap; if an extreme call-count safety valve is ever hit, the response says so explicitly via `truncated`/`cap` rather than dropping rows quietly. `owner`, `admin`, and `auditor` roles only. Every export is recorded to the governance audit trail.","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"description":"All Customer Voice feedback submissions for this org.","content":{"application/json":{"schema":{"type":"object","required":["entries","count","exported_at"],"properties":{"entries":{"type":"array","items":{"type":"object","additionalProperties":true}},"count":{"type":"integer"},"exported_at":{"type":"string","format":"date-time"},"truncated":{"type":"boolean","description":"Present and `true` only if the internal pagination safety valve was hit before reaching the true tail of the org's submissions. Absent otherwise."},"cap":{"type":"integer","description":"Present alongside `truncated: true` — the row ceiling that was hit."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/customer-voice/settings":{"get":{"operationId":"getOrgCustomerVoiceSettings","summary":"Read this org's Customer Voice retention settings","description":"Returns the org's Aletheia Customer Voice retention configuration (`feedback_retention_settings`, migration 464) — the documented default (`retention_days: null`, retain indefinitely) if the org has never configured one. `enforcement_active` is always `false` today: this build ships configuration + storage + audit only, not an enforcing deletion cron (tracked follow-up, MNE-440/MNE-443). `owner`, `admin`, and `auditor` roles only. Every read is recorded to the governance audit trail.","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"description":"This org's Customer Voice retention settings.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetentionSettings"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchOrgCustomerVoiceSettings","summary":"Update this org's Customer Voice retention settings","description":"Upserts the org's Aletheia Customer Voice retention configuration (`feedback_retention_settings`, migration 464). `retention_days` must be an integer in `[1, 3650]`, or `null` to retain indefinitely; anything else is rejected with `400`. `enforcement_active` is always `false` in the response today (honest-voice — see the GET description). `owner`/`admin` only. Every write is recorded to the governance audit trail with a before/after diff.","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["retention_days"],"properties":{"retention_days":{"type":["integer","null"],"minimum":1,"maximum":3650,"description":"Retention window in days, or `null` to retain indefinitely."}}}}}},"responses":{"200":{"description":"The updated Customer Voice retention settings.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetentionSettings"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/customer-voice/{submission_id}":{"delete":{"operationId":"deleteOrgCustomerVoiceSubmission","summary":"Erase one Customer Voice feedback submission (GDPR)","description":"Erases a single Aletheia Customer Voice feedback submission via the same SECURITY DEFINER `org_feedback_erase` RPC (migration 465) as the bulk-delete route, with `p_submission_id` set — one code path, one isolation guarantee. A `submission_id` that doesn't exist, or that belongs to another org, returns a non-disclosing `404` (indistinguishable from the caller's point of view, mirroring the feedback-acknowledgement endpoint) with zero rows touched. `owner`/`admin` only. Every erasure is recorded to the governance audit trail.","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"$ref":"#/components/parameters/SubmissionId"}],"responses":{"200":{"description":"Erasure receipt for the one deleted submission.","content":{"application/json":{"schema":{"type":"object","required":["deleted","submission_id"],"properties":{"deleted":{"type":"integer","enum":[1]},"submission_id":{"type":"string","format":"uuid"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/deployments":{"get":{"operationId":"listOrgDeployments","summary":"List self-hosted deployments for an org","description":"Any org member (owner / admin / member / viewer / auditor) may list deployments. Filter by `status` (`active`, `inactive`, `degraded`).","tags":["Licensing"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["active","inactive","degraded"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Deployment list.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"deployments":{"type":"array","items":{"$ref":"#/components/schemas/SelfHostedDeployment"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"post":{"operationId":"registerOrgDeployment","summary":"Register a new self-hosted deployment","description":"Requires org `owner` or `admin`. The `license_id` must already exist and belong to this org (verified via `verify_org_license` RPC). The deployment starts in `active` status.","tags":["Licensing"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["instance_name","instance_id","license_id"],"properties":{"instance_name":{"type":"string"},"instance_id":{"type":"string"},"license_id":{"type":"string"},"region":{"type":["string","null"]},"version":{"type":["string","null"]},"instance_metadata":{"type":"object","additionalProperties":true}}}}}},"responses":{"201":{"description":"Deployment registered.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelfHostedDeployment"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/deployments/{deployment_id}":{"get":{"operationId":"getOrgDeployment","summary":"Get a self-hosted deployment","tags":["Licensing"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deployment detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelfHostedDeployment"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"updateOrgDeployment","summary":"Update a self-hosted deployment","description":"Partial update. Requires org `owner` or `admin`. Allowed fields: `instance_name`, `region`, `status` (`active`/`inactive`/`degraded`), `version`, `instance_metadata`.","tags":["Licensing"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","minProperties":1,"properties":{"instance_name":{"type":"string"},"region":{"type":["string","null"]},"status":{"type":"string","enum":["active","inactive","degraded"]},"version":{"type":["string","null"]},"instance_metadata":{"type":"object","additionalProperties":true}}}}}},"responses":{"200":{"description":"Update accepted.","content":{"application/json":{"schema":{"type":"object","properties":{"deployment_id":{"type":"string"},"updated":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"delete":{"operationId":"deleteOrgDeployment","summary":"Delete a self-hosted deployment","description":"Requires org `owner` or `admin`. Hard-deletes the `self_hosted_deployments` row. The license remains valid — re-register to replace.","tags":["Licensing"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"deployment_id":{"type":"string"},"deleted":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/drift":{"get":{"operationId":"getOrgDrift","summary":"Paginated drift alerts for an org fleet","description":"Returns active and recent drift alerts for every agent in the org, plus a summary block (total_active, agents_drifting, high_severity, trend). Any org member may read. Feature-gated: `fleet_dashboard`.","tags":["Drift"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"x-feature-gate":"fleet_dashboard","parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Drift alerts + summary.","content":{"application/json":{"schema":{"type":"object","properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/DriftAlert"}},"summary":{"type":"object","properties":{"total_active":{"type":"integer"},"agents_drifting":{"type":"integer"},"high_severity":{"type":"integer"},"trend":{"type":"string","enum":["stable","worsening","improving"]}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/orgs/{org_id}/drift/{alert_id}/acknowledge":{"post":{"operationId":"acknowledgeOrgDriftAlert","summary":"Acknowledge a drift alert","description":"Marks a drift alert as acknowledged. Governance-scoped mutation: only org owner / admin may acknowledge (member, viewer and auditor cannot). Unknown `alert_id` returns 404. Emits a `drift.resolved` webhook (fail-open). Feature-gated: `fleet_dashboard`.","tags":["Drift"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"x-feature-gate":"fleet_dashboard","parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"alert_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Acknowledged.","content":{"application/json":{"schema":{"type":"object","properties":{"acknowledged":{"type":"boolean"},"alert_id":{"type":"string"},"acknowledged_by":{"type":"string"},"acknowledged_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/orgs/{org_id}/export/fleet":{"get":{"operationId":"exportOrgFleet","summary":"Export a snapshot of the org's agent fleet","description":"Returns a fleet roster in CSV (default) or PDF format, suitable for compliance review / board reporting. Any org member may export. Feature-gated: `fleet_dashboard`.","tags":["Organizations"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"x-feature-gate":"fleet_dashboard","parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"format","in":"query","required":false,"schema":{"type":"string","enum":["csv","pdf"],"default":"csv"}}],"responses":{"200":{"description":"Fleet export.","content":{"text/csv":{"schema":{"type":"string"}},"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/orgs/{org_id}/feedback":{"get":{"operationId":"getOrgFeedback","summary":"Read this org's feedback","description":"Returns the Aletheia Customer Voice feedback submitted within this org (with each row's latest triage decision, linked work-item, and resolution), newest first. Scoped strictly to `org_id` by the SECURITY DEFINER `org_feedback_read` RPC — an org can never read another org's feedback. `owner`, `admin`, and `auditor` roles only. Every read is recorded to the governance audit trail.","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Feedback submissions for this org, newest first.","content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"category":{"type":"string"},"status":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"sentiment":{"type":["string","null"]},"cluster_id":{"type":["string","null"],"format":"uuid"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"triage_decision":{"type":["string","null"]},"work_item_repo":{"type":["string","null"]},"work_item_url":{"type":["string","null"]},"resolved_at":{"type":["string","null"],"format":"date-time"}}}},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/governance/coverage":{"get":{"operationId":"getOrgGovernanceCoverage","summary":"30-day governance coverage rollup","description":"Aggregate metrics: signals fired vs. acknowledged vs. resolved per source + severity over a configurable window. Default window is 30 days.","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"window_days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":90,"default":30}}],"responses":{"200":{"description":"Coverage rollup.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GovernanceCoverageReport"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/governance/escalation-rules":{"get":{"operationId":"listGovernanceEscalationRules","summary":"List escalation rules for an org","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"description":"Escalation rules listing.","content":{"application/json":{"schema":{"type":"object","required":["org_id","rules"],"properties":{"org_id":{"type":"string","description":"The org these rules belong to (echoed from the path)."},"rules":{"type":"array","items":{"$ref":"#/components/schemas/GovernanceEscalationRule"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"post":{"operationId":"createGovernanceEscalationRule","summary":"Create an escalation rule","description":"Authorized: org_admin or org_owner.","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["name","predicate","destination_ids"],"properties":{"name":{"type":"string","description":"Human-readable name for the escalation rule, shown in the operator console."},"predicate":{"$ref":"#/components/schemas/GovernanceEscalationPredicate","description":"Match condition (by source, severity, scope, and/or pattern_type) that a signal must satisfy to fire this rule."},"destination_ids":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Allowed empty when enabled is false (Tier 4 §4.4 default rules)"},"enabled":{"type":"boolean","default":true,"description":"Whether the rule is active and evaluated against incoming signals (default true)."}}}}}},"responses":{"201":{"description":"Escalation rule.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GovernanceEscalationRule"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/governance/escalation-rules/{rule_id}":{"get":{"operationId":"getGovernanceEscalationRule","summary":"Get an escalation rule by id","description":"Authorized: any org member (owner, admin, member, viewer, auditor).","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"rule_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the escalation rule to fetch."}],"responses":{"200":{"description":"Escalation rule.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GovernanceEscalationRule"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"updateGovernanceEscalationRule","summary":"Update an escalation rule","description":"Authorized: org_admin or org_owner.","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"rule_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the escalation rule to act on."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string"},"predicate":{"$ref":"#/components/schemas/GovernanceEscalationPredicate"},"destination_ids":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Allowed empty when enabled is false (Tier 4 §4.4 default rules)"},"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Escalation rule.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GovernanceEscalationRule"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"delete":{"operationId":"deleteGovernanceEscalationRule","summary":"Delete an escalation rule","description":"Authorized: org_admin or org_owner.","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"rule_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the escalation rule to act on."}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","required":["ok"],"additionalProperties":false,"properties":{"ok":{"type":"boolean","enum":[true]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/governance/notification-destinations":{"get":{"operationId":"listGovernanceDestinations","summary":"List notification destinations for an org","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"description":"Notification destinations listing.","content":{"application/json":{"schema":{"type":"object","required":["org_id","destinations"],"properties":{"org_id":{"type":"string","description":"The org these destinations belong to (echoed from the path)."},"destinations":{"type":"array","items":{"$ref":"#/components/schemas/GovernanceNotificationDestination"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"post":{"operationId":"createGovernanceDestination","summary":"Create a notification destination","description":"Authorized: org_admin or org_owner.","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["channel","config"],"properties":{"channel":{"$ref":"#/components/schemas/GovernanceNotificationChannel","description":"Delivery channel for this destination: webhook, slack, email, or pagerduty."},"config":{"type":"object","additionalProperties":true,"description":"Channel-specific delivery settings (e.g. webhook { url, secret }, slack { webhook_url }, email { to }, pagerduty { routing_key })."},"filter":{"$ref":"#/components/schemas/GovernanceDestinationFilter","description":"Optional filter limiting which signals reach this destination (by source, severity, scope, or pattern_type); omit to receive all."},"enabled":{"type":"boolean","default":true,"description":"Whether the destination is active and eligible to receive dispatches (default true)."},"display_name":{"type":"string","description":"Optional human-readable label shown in the operator console."}}}}}},"responses":{"201":{"description":"Notification destination.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GovernanceNotificationDestination"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/governance/notification-destinations/{destination_id}":{"patch":{"operationId":"updateGovernanceDestination","summary":"Update a notification destination","description":"Authorized: org_admin or org_owner.","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"destination_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the notification destination to act on."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"config":{"type":"object","additionalProperties":true},"filter":{"$ref":"#/components/schemas/GovernanceDestinationFilter"},"enabled":{"type":"boolean"},"display_name":{"type":["string","null"]}}}}}},"responses":{"200":{"description":"Notification destination.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GovernanceNotificationDestination"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"delete":{"operationId":"deleteGovernanceDestination","summary":"Delete a notification destination","description":"Authorized: org_admin or org_owner.","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"destination_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the notification destination to act on."}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","required":["ok"],"additionalProperties":false,"properties":{"ok":{"type":"boolean","enum":[true]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/governance/notification-destinations/{destination_id}/test":{"post":{"operationId":"testGovernanceDestination","summary":"Send a synthetic signal through a destination","description":"Bypasses escalation rules and dispatches a test payload directly to the destination. Records `last_tested_at` + `last_test_status` on the row.","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"destination_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the notification destination to act on."}],"responses":{"200":{"description":"Test outcome.","content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["ok","failed"]},"error":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/governance/signals":{"get":{"operationId":"listOrgGovernanceSignals","summary":"List governance signals for an org","description":"Returns governance signals scoped to the given org, filterable by source, severity, status, and pattern_type. Any org member may read.","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"source","in":"query","required":false,"schema":{"$ref":"#/components/schemas/GovernanceSignalSource"},"description":"Filter by source detector."},{"name":"severity","in":"query","required":false,"schema":{"$ref":"#/components/schemas/GovernanceSignalSeverity"},"description":"Filter by severity."},{"name":"status","in":"query","required":false,"schema":{"$ref":"#/components/schemas/GovernanceSignalStatus"},"description":"Filter by workflow status."},{"name":"pattern_type","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by pattern_type within the source's taxonomy."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"description":"Maximum number of signals to return, most recent first (1–200, default 50)."}],"responses":{"200":{"description":"Governance signals listing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GovernanceSignalsListResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/invitations":{"post":{"operationId":"inviteMember","summary":"Invite member to organization","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["admin","member","viewer","auditor"],"default":"member"}}}}}},"responses":{"201":{"description":"Invitation created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgInvitation"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"get":{"operationId":"listInvitations","summary":"List pending invitations","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"description":"Invitations list","content":{"application/json":{"schema":{"type":"object","properties":{"invitations":{"type":"array","items":{"$ref":"#/components/schemas/OrgInvitation"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/invitations/{invitation_id}":{"delete":{"operationId":"revokeInvitation","summary":"Revoke a pending invitation","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"invitation_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Invitation revoked","content":{"application/json":{"schema":{"type":"object","properties":{"revoked":{"type":"boolean"},"invitation_id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/members":{"get":{"operationId":"listMembers","summary":"List organization members","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"description":"Members list","content":{"application/json":{"schema":{"type":"object","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/OrgMember"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/members/{user_id}":{"patch":{"operationId":"updateMemberRole","summary":"Update member role (owner only)","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"user_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["role"],"properties":{"role":{"type":"string","enum":["admin","member","viewer","auditor"]}}}}}},"responses":{"200":{"description":"Role updated","content":{"application/json":{"schema":{"type":"object","properties":{"org_id":{"type":"string"},"user_id":{"type":"string"},"old_role":{"type":"string"},"new_role":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"delete":{"operationId":"removeMember","summary":"Remove member or self-leave","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"user_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Member removed","content":{"application/json":{"schema":{"type":"object","properties":{"removed":{"type":"boolean"},"org_id":{"type":"string"},"user_id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/protection-template":{"get":{"operationId":"getOrgProtectionTemplateLegacy","summary":"DEPRECATED — use GET /v1/protection/org/{org_id}.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/protection/org/{org_id}`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Card Templates"],"security":[],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"putOrgProtectionTemplateLegacy","summary":"DEPRECATED — use PUT /v1/protection/org/{org_id}.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/protection/org/{org_id}`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Card Templates"],"security":[],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"delete":{"operationId":"deleteOrgProtectionTemplateLegacy","summary":"DEPRECATED — use DELETE /v1/protection/org/{org_id}.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/protection/org/{org_id}`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Card Templates"],"security":[],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/protection-template/preview-compose":{"post":{"operationId":"postOrgProtectionTemplatePreviewComposeLegacy","summary":"DEPRECATED — use POST /v1/protection/org/{org_id}/preview-compose.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/protection/org/{org_id}/preview-compose`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Card Templates"],"security":[],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/restore":{"post":{"operationId":"restoreOrgSelfServe","summary":"Self-serve restore a tombstoned organization (owner or admin, within 30 days of tombstoning)","description":"MNE-2503: within 30 days of `tombstoned_at`, the org's own owner or admin can restore it themselves — no mnemom-admin required. Refused (403) past the 30-day window (only the mnemom-admin-only restore path remains after that). Also clears a pending `scheduled_tombstone_at` on an org that was never actually tombstoned (no separate cancel-schedule endpoint). If the org has a paused billing subscription, `confirm_billing_resume` must be `true` in the request body or the whole restore is refused (400) — never partially applied. Gated behind the `ORG_SELF_SERVE_RESTORE_ENABLED` flag; 404s (as if the route doesn't exist) when that flag is off.","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"confirm_billing_resume":{"type":"boolean","description":"Required (must be true) when the org has a paused subscription; irrelevant otherwise."}}}}}},"responses":{"200":{"description":"Organization restored (or its pending schedule cleared, or a safe no-op)","content":{"application/json":{"schema":{"type":"object","properties":{"restored":{"type":"boolean"},"schedule_cleared":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/safe-house/enable":{"post":{"operationId":"enableOrgSafeHouse","summary":"Enable or change the Safe House posture for an org","description":"Customer-admin entry point to set the Safe House mode for an organization. Mirrors the staff-only `POST /v1/admin/safe-house/enable` route; both call the same `enable_sh_for_org(p_org_id, p_mode)` RPC. Caller must be an `owner` or `admin` of the target org.","tags":["Safe House"],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["disabled","off","observe","enforce","enforce_sync"],"default":"observe","description":"Target Safe House mode. Defaults to `observe` when omitted."}}}}}},"responses":{"200":{"description":"Mode applied. Response shape mirrors the staff endpoint.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/sso":{"get":{"operationId":"getSsoConfig","summary":"Get SSO configuration for organization","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"description":"SSO config or not configured","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"configureSso","summary":"Configure SAML SSO for organization (owner only)","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["metadata_url","allowed_domains"],"properties":{"metadata_url":{"type":"string","format":"uri"},"idp_name":{"type":"string"},"default_role":{"type":"string","enum":["admin","member","viewer","auditor"],"default":"member"},"allowed_domains":{"type":"array","items":{"type":"string"},"minItems":1},"enforced":{"type":"boolean","default":false}}}}}},"responses":{"200":{"description":"SSO configured","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"delete":{"operationId":"removeSso","summary":"Remove SSO configuration (owner only)","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"description":"SSO removed","content":{"application/json":{"schema":{"type":"object","properties":{"removed":{"type":"boolean"},"note":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/orgs/{org_id}/sso/test":{"post":{"operationId":"testSso","summary":"Test SSO metadata URL validity","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"metadata_url":{"type":"string","format":"uri"}}}}}},"responses":{"200":{"description":"SSO test result","content":{"application/json":{"schema":{"type":"object","properties":{"valid":{"type":"boolean"},"error":{"type":["string","null"]},"metadata_url":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/orgs/{org_id}/teams":{"get":{"operationId":"listOrgTeams","summary":"List teams in organization","description":"List all teams belonging to an organization, filtered by status.","tags":["Teams"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"status","in":"query","schema":{"type":"string","enum":["active","archived"],"default":"active"},"description":"Filter by team status"},{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Page number"},{"name":"per_page","in":"query","schema":{"type":"integer","default":50,"maximum":200},"description":"Results per page (max 200)"}],"responses":{"200":{"description":"Paginated list of teams","content":{"application/json":{"schema":{"type":"object","properties":{"teams":{"type":"array","items":{"$ref":"#/components/schemas/Team"}},"total":{"type":"integer"},"page":{"type":"integer"},"per_page":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/orgs/{org_id}/trust-posture":{"get":{"operationId":"getOrgTrustPosture","summary":"Get the org's effective trust posture (Platform → Org cascade)","description":"Org-level shortcut for the Platform → Org cascade. Closes the T7-F4 agent-affordance gap — agents asking 'what trust posture has this org published?' can hit one endpoint instead of walking org → teams → per-team posture. Distinct from `/teams/{team_id}/effective-posture` which includes the team layer. Returns `effective` = the org's assigned posture when set, else the platform default (Charter §I13 floor `tp-platform-standard`).","tags":["Postures"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Org-level effective trust posture.","content":{"application/json":{"schema":{"type":"object","required":["org_id","org_name","gathered","effective"],"properties":{"org_id":{"type":"string"},"org_slug":{"type":["string","null"]},"org_name":{"type":"string"},"gathered":{"type":"object","properties":{"platform_default":{"type":["object","null"],"description":"Platform-default posture layer (always present in healthy state)."},"org_assigned":{"type":["object","null"],"description":"Org's explicitly-chosen default posture, or null if the org inherits the platform default."}}},"effective":{"type":["object","null"],"description":"Org-effective layer (org_assigned ?? platform_default)."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/usage":{"get":{"operationId":"getOrgUsage","summary":"Daily request + token totals for the org","description":"Operational usage metrics — request count plus token volume per day. Dashboard-shaped: visible to all org roles except viewer (members and auditors retain access for self-monitoring and compliance respectively). For dollar-cost rollups see `GET /orgs/{org_id}/costs`.","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"days","in":"query","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}}],"responses":{"200":{"description":"Daily usage rows.","content":{"application/json":{"schema":{"type":"object","properties":{"period":{"type":"string","example":"daily"},"days":{"type":"integer"},"data":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","format":"date"},"requests":{"type":"integer"},"tokens_in":{"type":"integer"},"tokens_out":{"type":"integer"}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/usage/by-person":{"get":{"operationId":"getOrgUsageByPerson","summary":"Per-person, per-model consumption for the org","description":"Query-time aggregation of token/request consumption grouped by attributed person, provider, and model, scoped ONLY to the org's own usage_events via the immutable attribution_org_id snapshot (MNE-3213). Consumption only — never spend/cost/currency; see `GET /orgs/{org_id}/costs` for the dollar-cost rollup. Billing-shaped: `owner`, `admin`, and `auditor` only (`member`/`viewer` never receive this data). `days` is restricted to 7, 30, or 90 for v1. Cursor pagination is deterministic on `(total_tokens DESC, user_id, provider, model)`; `totals` and `attribution_rate` are computed over the complete filtered result before pagination. Behind the `USAGE_ATTRIBUTION_API_ENABLED` flag (default false in every environment) — while disabled this returns 404 to every caller, including owners.","tags":["Organizations"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"days","in":"query","schema":{"type":"integer","enum":[7,30,90],"default":30}},{"name":"person_id","in":"query","schema":{"type":"string"}},{"name":"provider","in":"query","schema":{"type":"string"}},{"name":"model","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":100}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Per-person, per-model consumption rows + org-wide totals for the window.","content":{"application/json":{"schema":{"type":"object","properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"},"collection_started_at":{"type":"string","format":"date-time","nullable":true,"description":"Earliest v1-attributed event for this org, independent of the selected filters. Null until the org has a v1 event."},"data":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":"string","nullable":true},"display_name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"membership_state":{"type":"string","enum":["active","former","unattributed"]},"provider":{"type":"string"},"model":{"type":"string"},"tokens_in":{"type":"string","description":"64-bit-safe total; transported as a string."},"tokens_out":{"type":"string","description":"64-bit-safe total; transported as a string."},"request_count":{"type":"string","description":"64-bit-safe total; transported as a string."}}}},"totals":{"type":"object","properties":{"tokens_in":{"type":"string"},"tokens_out":{"type":"string"},"request_count":{"type":"string"},"attributed_request_count":{"type":"string"},"unattributed_request_count":{"type":"string"},"attribution_rate":{"type":"number","minimum":0,"maximum":1}}},"next_cursor":{"type":"string","nullable":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/webhooks":{"post":{"operationId":"createWebhookEndpoint","summary":"Create a webhook endpoint","description":"Create a new webhook endpoint for the organization. Returns the signing secret (shown only once). Maximum 5 endpoints per organization.","tags":["Webhook Notifications"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"HTTPS URL that will receive webhook POST requests"},"description":{"type":"string","description":"Human-readable description of this endpoint"},"event_types":{"type":"array","items":{"type":"string","enum":["integrity.violation","integrity.checkpoint","drift.resolved","conscience.escalation","quota.warning","quota.exceeded","subscription.status_changed","agent.paused","agent.resumed","agent.killed","conscience.values_updated","reputation.score_changed","reputation.grade_changed","quota.risk_exceeded","quota.risk_warning","team.created","team.archived","team.member_added","team.member_removed","team.card_updated","quota.team_reputation_exceeded","quota.team_reputation_warning","quota.sh_warning","sh.evaluation.warn","sh.evaluation.quarantine","sh.evaluation.block","sh.canary.triggered","sh.session.escalated","sh.campaign.detected","sh.review.triggered","sh.review.approved","sh.review.denied","sh.review.expired","recipe.promoted","recipe.retired","recipe.candidate.created","reviewer-mode.changed","trace.created","trace.verified","trace.failed","trace.escalation_required","policy.violation","transaction.completed","alignment_card.updated","protection_card.updated","org_alignment_template.updated","org_alignment_template.deleted","org_protection_template.updated","org_protection_template.deleted","agent.exemption.granted","agent.exemption.revoked","sideband.coherence.fired","sideband.fault_line.fired","sideband.fleet.fired","sideband.drift.fired","advisory.published","ioc.added","network.campaign.closed"]},"description":"Event types to subscribe to. Empty array means all events. See the webhook event catalog for the full list and per-event payload schemas."}}}}}},"responses":{"201":{"description":"Webhook endpoint created. Response includes signing_secret (shown only once).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"get":{"operationId":"listWebhookEndpoints","summary":"List webhook endpoints","description":"List all webhook endpoints for the organization. Signing secrets are not included.","tags":["Webhook Notifications"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"description":"List of webhook endpoints","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEndpointPublic"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/orgs/{org_id}/webhooks/deliveries":{"get":{"operationId":"getWebhookDeliveryLog","summary":"Get webhook delivery log","description":"Paginated delivery log for the organization. Optionally filter by endpoint_id.","tags":["Webhook Notifications"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"endpoint_id","in":"query","schema":{"type":"string"},"description":"Filter deliveries to a specific endpoint"},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":100},"description":"Number of deliveries to return (max 100)"},{"name":"offset","in":"query","schema":{"type":"integer","default":0},"description":"Offset for pagination"}],"responses":{"200":{"description":"Delivery log entries","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/orgs/{org_id}/webhooks/deliveries/{delivery_id}/redeliver":{"post":{"operationId":"redeliverWebhookEvent","summary":"Redeliver a webhook event","description":"Create a new delivery attempt for a previously failed event. A new delivery row is created with next_attempt_at set to now.","tags":["Webhook Notifications"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"delivery_id","in":"path","required":true,"schema":{"type":"string"},"description":"Delivery identifier (e.g. whd-abc12345)"}],"responses":{"201":{"description":"New delivery created","content":{"application/json":{"schema":{"type":"object","properties":{"delivery_id":{"type":"string"},"event_id":{"type":"string"},"status":{"type":"string","enum":["pending"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/orgs/{org_id}/webhooks/events/{event_id}/replay":{"post":{"operationId":"replayWebhookEvent","summary":"Replay a webhook event to its eligible endpoints","description":"Re-dispatches a previously recorded webhook event to all org endpoints subscribed to its event_type (or to the explicit subset supplied in the request body). Requires the `webhook_notifications` feature flag and owner/admin role on the target org. Cross-tenant access returns 404. Replay is idempotent on the `Idempotency-Key` header; a replayed key with a different body returns 422 and a conflicting in-flight key returns 409. When no endpoints are eligible the response is 200 with an empty `deliveries` array; when at least one delivery is enqueued the response is 201 with delivery descriptors (and an optional `failed_endpoints` list for endpoints that could not be enqueued).","tags":["Webhook Notifications"],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"event_id","in":"path","required":true,"description":"Identifier of the webhook event to replay. Must belong to the path org_id; cross-tenant lookups return 404.","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"Client-supplied key that makes replay idempotent. Re-sending the same key with the same body returns the original result; re-sending with a different body returns 422; a conflicting in-flight key returns 409.","schema":{"type":"string","minLength":1,"maxLength":255}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"endpoint_ids":{"type":"array","description":"Optional explicit subset of endpoint ids to replay to. Endpoints not subscribed to the event's type are silently skipped. When omitted, all eligible endpoints are targeted.","items":{"type":"string","format":"uuid"},"maxItems":100,"uniqueItems":true}}}}}},"responses":{"200":{"description":"No eligible endpoints — nothing was enqueued. Returned when the event has no subscribers (or the supplied `endpoint_ids` subset matches none).","content":{"application/json":{"schema":{"type":"object","required":["event_id","event_type","deliveries","message"],"properties":{"event_id":{"type":"string","format":"uuid"},"event_type":{"type":"string"},"deliveries":{"type":"array","maxItems":0,"items":{}},"message":{"type":"string"}}}}}},"201":{"description":"One or more deliveries were enqueued for replay.","content":{"application/json":{"schema":{"type":"object","required":["event_id","event_type","deliveries"],"properties":{"event_id":{"type":"string","format":"uuid"},"event_type":{"type":"string"},"deliveries":{"type":"array","items":{"type":"object","required":["delivery_id","endpoint_id"],"properties":{"delivery_id":{"type":"string","format":"uuid"},"endpoint_id":{"type":"string","format":"uuid"}}}},"failed_endpoints":{"type":"array","description":"Endpoints that matched the event but could not be enqueued (e.g. transient infrastructure error). Each entry names the endpoint and the reason.","items":{"type":"object","required":["endpoint_id","reason"],"properties":{"endpoint_id":{"type":"string","format":"uuid"},"reason":{"type":"string"}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}},"security":[{"BearerAuth":[]}]}},"/orgs/{org_id}/webhooks/health":{"get":{"operationId":"getOrgWebhookHealth","summary":"Webhook delivery health for this org","description":"Returns active + disabled endpoint counts, 24-hour delivery counts (success / failed / total), success rate, and the top event types delivered in the last 24 hours. Useful for Status-page-style dashboards or monitoring integrations. Read-only: `owner`, `admin`, and `auditor`.","tags":["Webhook Notifications"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"description":"Health metrics.","content":{"application/json":{"schema":{"type":"object","properties":{"active_endpoints":{"type":"integer"},"disabled_endpoints":{"type":"integer"},"deliveries_24h":{"type":"integer"},"success_24h":{"type":"integer"},"failed_24h":{"type":"integer"},"success_rate_24h":{"type":"number"},"top_event_types":{"type":"array","items":{"type":"object","properties":{"event_type":{"type":"string"},"count":{"type":"integer"}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/orgs/{org_id}/webhooks/listen":{"get":{"operationId":"listenWebhookEvents","summary":"Stream webhook events for an org over Server-Sent Events","description":"Opens a Server-Sent Events stream that emits webhook events delivered to the org in near-real-time. Requires the `webhook_notifications` feature flag and owner/admin role on the target org. The cursor is resolved from the `since` query parameter, falling back to the `Last-Event-ID` header when `since` is absent — clients reconnecting after a drop should send the last event id they observed. The stream caps at 5 minutes per connection, polls the underlying queue every 1 second, and emits a keepalive comment every 15 seconds. Frame types emitted on the stream:\n\n- `ready` — sent immediately after the stream opens, carries the resolved cursor.\n- `webhook.event` — one frame per webhook event, payload mirrors the event record.\n- keepalive — SSE comment line (`:keepalive`) every 15s to keep intermediaries from idling the connection.\n- `close` — sent when the 5-minute cap is reached, before the server closes the socket.\n- `error` — sent on unrecoverable stream errors before the socket closes.","tags":["Webhook Notifications"],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"since","in":"query","required":false,"description":"Cursor (event id) to resume from. When omitted, the server falls back to the `Last-Event-ID` request header; when neither is supplied, the stream starts at the current tail.","schema":{"type":"string"}},{"name":"Last-Event-ID","in":"header","required":false,"description":"Standard SSE reconnection header. Used as the cursor when the `since` query parameter is not supplied.","schema":{"type":"string"}}],"responses":{"200":{"description":"Server-Sent Events stream of webhook events. The connection is capped at 5 minutes; clients should reconnect and resume via `Last-Event-ID` or `since`.","headers":{"Cache-Control":{"description":"Disables intermediary caching of the stream.","schema":{"type":"string","enum":["no-cache"]}},"X-Accel-Buffering":{"description":"Disables proxy response buffering (nginx-family) so frames flush immediately.","schema":{"type":"string","enum":["no"]}},"Connection":{"description":"Keeps the underlying TCP connection open for the duration of the stream.","schema":{"type":"string","enum":["keep-alive"]}}},"content":{"text/event-stream":{"schema":{"type":"string","description":"Sequence of SSE frames. Each non-keepalive frame has an `event:` line naming the frame type (`ready`, `webhook.event`, `close`, `error`), an `id:` line carrying the event cursor (for `webhook.event` frames), and a `data:` line containing a JSON payload. Keepalive frames are SSE comments (`:keepalive`)."}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"BearerAuth":[]}]}},"/orgs/{org_id}/webhooks/{endpoint_id}":{"get":{"operationId":"getWebhookEndpoint","summary":"Get webhook endpoint details","description":"Get details for a single webhook endpoint. Signing secret is not included.","tags":["Webhook Notifications"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"$ref":"#/components/parameters/EndpointId"}],"responses":{"200":{"description":"Webhook endpoint details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointPublic"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"patch":{"operationId":"updateWebhookEndpoint","summary":"Update webhook endpoint","description":"Update an existing webhook endpoint. Re-enabling a disabled endpoint resets the failure counter.","tags":["Webhook Notifications"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"$ref":"#/components/parameters/EndpointId"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"New HTTPS URL"},"description":{"type":"string","description":"Optional human-readable label for the endpoint, shown in the operator console."},"event_types":{"type":"array","items":{"type":"string","enum":["integrity.violation","integrity.checkpoint","drift.resolved","conscience.escalation","quota.warning","quota.exceeded","subscription.status_changed","agent.paused","agent.resumed","agent.killed","conscience.values_updated","reputation.score_changed","reputation.grade_changed","quota.risk_exceeded","quota.risk_warning","team.created","team.archived","team.member_added","team.member_removed","team.card_updated","quota.team_reputation_exceeded","quota.team_reputation_warning","quota.sh_warning","sh.evaluation.warn","sh.evaluation.quarantine","sh.evaluation.block","sh.canary.triggered","sh.session.escalated","sh.campaign.detected","sh.review.triggered","sh.review.approved","sh.review.denied","sh.review.expired","recipe.promoted","recipe.retired","recipe.candidate.created","reviewer-mode.changed","trace.created","trace.verified","trace.failed","trace.escalation_required","policy.violation","transaction.completed","alignment_card.updated","protection_card.updated","org_alignment_template.updated","org_alignment_template.deleted","org_protection_template.updated","org_protection_template.deleted","agent.exemption.granted","agent.exemption.revoked","sideband.coherence.fired","sideband.fault_line.fired","sideband.fleet.fired","sideband.drift.fired","advisory.published","ioc.added","network.campaign.closed"]},"description":"Replacement set of event types this endpoint subscribes to; replaces the prior subscription in full."},"is_active":{"type":"boolean","description":"Set to true to re-enable a disabled endpoint (resets failure counter)"}}}}}},"responses":{"200":{"description":"Updated endpoint","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointPublic"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"delete":{"operationId":"deleteWebhookEndpoint","summary":"Delete webhook endpoint","description":"Permanently delete a webhook endpoint and all its delivery history.","tags":["Webhook Notifications"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"$ref":"#/components/parameters/EndpointId"}],"responses":{"200":{"description":"Endpoint deleted","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"},"endpoint_id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/orgs/{org_id}/webhooks/{endpoint_id}/rotate-secret":{"post":{"operationId":"rotateWebhookSecret","summary":"Rotate webhook signing secret","description":"Generate a new signing secret for the endpoint. The new secret is returned once. Previous secret is immediately invalidated.","tags":["Webhook Notifications"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"$ref":"#/components/parameters/EndpointId"}],"responses":{"200":{"description":"New signing secret (shown only once)","content":{"application/json":{"schema":{"type":"object","properties":{"endpoint_id":{"type":"string"},"signing_secret":{"type":"string","description":"New 32-byte hex-encoded signing secret. Store securely — not retrievable again."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/orgs/{org_id}/webhooks/{endpoint_id}/test":{"post":{"operationId":"testWebhookEndpoint","summary":"Send test webhook delivery","description":"Send a synchronous test delivery to the endpoint with a synthetic webhook.test event. Returns the delivery result immediately.","tags":["Webhook Notifications"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"$ref":"#/components/parameters/EndpointId"}],"responses":{"200":{"description":"Test delivery result","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"status":{"type":["integer","null"],"description":"HTTP response status code from the endpoint"},"latency_ms":{"type":["integer","null"],"description":"Round-trip time in milliseconds"},"error":{"type":["string","null"],"description":"Error message if delivery failed"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/plans":{"get":{"operationId":"listPublicPlans","security":[],"summary":"List public pricing plans","tags":["Billing"],"responses":{"200":{"description":"Public plans","content":{"application/json":{"schema":{"type":"object","properties":{"plans":{"type":"array","items":{"$ref":"#/components/schemas/Plan"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/plans/public":{"get":{"operationId":"listPublicPlansAlias","summary":"List public pricing plans (alias of `/plans`)","description":"Returns non-archived, public-visibility plans sorted by `sort_order`. Identical to `GET /plans`; this alias exists for stable linking from marketing pages.","tags":["Billing"],"security":[],"responses":{"200":{"description":"Public plan list.","content":{"application/json":{"schema":{"type":"object","required":["plans"],"properties":{"plans":{"type":"array","items":{"$ref":"#/components/schemas/Plan"}}}}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/policies/evaluate":{"post":{"operationId":"evaluatePolicy","summary":"Evaluate an agent's derived policy against tools","description":"Evaluate a list of tools against the policy DERIVED from the agent's published canonical alignment card (capabilities + enforcement + escalation triggers). Returns a verdict with detailed violations, warnings, card coverage gaps, and overall coverage percentage. Requires a published canonical card for the agent (PUT /v1/agents/{id}/alignment-card first, else 404). No standalone policy document is accepted — the card is the source of truth (UC-8).","tags":["Policy"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["agent_id","tools"],"properties":{"agent_id":{"type":"string","description":"Agent whose canonical alignment card the policy is derived from. Must have a published canonical card."},"tools":{"type":"array","minItems":1,"items":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Tool identifier to evaluate (e.g. \"fs_write\")."}}},"description":"Non-empty list of tools to evaluate against the agent's derived policy."},"context":{"type":"string","default":"cicd","description":"Evaluation surface/context (default \"cicd\")."},"dry_run":{"type":"boolean","default":false,"description":"When true, the evaluation result is not persisted to policy_evaluations."}}}}}},"responses":{"200":{"description":"Policy evaluation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyEvaluationResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/policies/evaluate/historical":{"post":{"operationId":"evaluatePolicyHistorical","summary":"Evaluate a card against an agent's historical traces","description":"Replay an agent's recent AIP traces through the policy derived from a card to identify what would have been blocked, escalated, or flagged. By default the agent's current canonical alignment card is used; supply `card_json` to dry-run a hypothetical card instead. Useful for understanding the impact of a card/policy change before rolling it out. No standalone policy document is accepted (UC-8).","tags":["Policy"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["agent_id"],"properties":{"agent_id":{"type":"string","description":"Agent whose historical traces will be replayed."},"card_json":{"type":"object","additionalProperties":true,"description":"Optional hypothetical alignment card to evaluate against. If omitted, the agent's current canonical card is used (404 if the agent has none and no card_json is supplied)."},"limit":{"type":"integer","default":50,"maximum":200,"description":"Maximum number of recent traces to evaluate (capped at 200)."}}}}}},"responses":{"200":{"description":"Historical evaluation result","content":{"application/json":{"schema":{"type":"object","required":["agent_id"],"properties":{"agent_id":{"type":"string"},"card_id":{"type":"string","description":"Card the traces were evaluated against."},"total_traces":{"type":"integer","description":"Number of traces returned by the evaluation."},"results":{"type":"array","description":"Per-trace verdicts (or {skipped:true} for traces with no tool calls).","items":{"type":"object","properties":{"trace_id":{"type":"string"},"verdict":{"type":"string"},"violations":{"type":"array","items":{"type":"object"}},"warnings":{"type":"array","items":{"type":"object"}},"skipped":{"type":"boolean"}}}},"summary":{"type":"object","properties":{"pass":{"type":"integer"},"warn":{"type":"integer"},"fail":{"type":"integer"},"skipped":{"type":"integer"}}},"message":{"type":"string","description":"Present only when the agent has no historical traces."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/postures":{"get":{"operationId":"listPostures","summary":"List postures","tags":["Postures"],"description":"Returns platform-default postures plus, when org_id is supplied, the org's postures. Soft-deleted postures excluded by default.","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"org_id","in":"query","schema":{"type":"string"},"description":"Limit to platform-defaults + this org's postures."},{"name":"include_platform","in":"query","schema":{"type":"boolean","default":true},"description":"Whether to include platform-default postures in the listing (default true)."},{"name":"include_deleted","in":"query","schema":{"type":"boolean","default":false},"description":"Whether to include soft-deleted postures in the listing (default false)."},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"minimum":1,"maximum":200},"description":"Opt-in pagination: max postures to return. Omit limit AND offset for the full (unpaginated) listing. When supplied, the response adds total/limit/offset and only the returned page is body-hydrated."},{"name":"offset","in":"query","schema":{"type":"integer","default":0,"minimum":0},"description":"Opt-in pagination: number of postures to skip."}],"responses":{"200":{"description":"Postures listing. Includes total/limit/offset only when limit or offset was supplied.","content":{"application/json":{"schema":{"type":"object","required":["postures"],"properties":{"postures":{"type":"array","items":{"$ref":"#/components/schemas/Posture"}},"total":{"type":"integer","description":"Total postures before pagination (present only when paginating)."},"limit":{"type":"integer","description":"Echoed page size (paginated only)."},"offset":{"type":"integer","description":"Echoed offset (paginated only)."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"post":{"operationId":"createPosture","summary":"Create a posture","description":"Authorized: org_admin / org_owner for org-scope; platform admins for platform-scope.","tags":["Postures"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string"},"description":"Client-supplied idempotency token (required). Replays within 24 hours return the stored result; reusing a key with a different body returns 409. See ADR-023."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug","name","scope","body"],"properties":{"slug":{"type":"string","description":"URL-safe identifier for the posture, unique within its scope (lowercase letters, digits, and hyphens)."},"name":{"type":"string","description":"Human-readable display name for the posture."},"description":{"type":"string","description":"Optional human-readable summary of what this posture enforces."},"scope":{"$ref":"#/components/schemas/PostureScope","description":"Ownership scope: `platform` (Mnemom-default, staff only) or `org` (tenant-owned; requires org_id)."},"org_id":{"type":"string","description":"Required when scope=org."},"body":{"$ref":"#/components/schemas/PostureBody","description":"Trust posture body (PostureBody v1.0): the sideband, fleet_identification, and fan_out configuration this posture enforces."}}}}}},"responses":{"201":{"description":"Posture.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Posture"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/postures/{posture_id}":{"get":{"operationId":"getPosture","summary":"Read a posture's current revision","tags":["Postures"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"posture_id","in":"path","required":true,"schema":{"type":"string","pattern":"^tp-[a-z0-9-]{1,64}$"},"description":"Posture ID (tp-{8-hex})."}],"responses":{"200":{"description":"Posture.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Posture"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"putPosture","summary":"Write a new revision of a posture (forward-only)","description":"Creates a new immutable revision; updates current_revision_id pointer.","tags":["Postures"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string"},"description":"Client-supplied idempotency token (required). Replays within 24 hours return the stored result; reusing a key with a different body returns 409. See ADR-023."},{"name":"posture_id","in":"path","required":true,"schema":{"type":"string","pattern":"^tp-[a-z0-9-]{1,64}$"},"description":"Posture ID (tp-{8-hex})."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["body"],"properties":{"body":{"$ref":"#/components/schemas/PostureBody","description":"New trust posture body (PostureBody v1.0) to persist as the next revision; replaces the prior body in full."},"change_note":{"type":"string","description":"Optional note describing this revision, recorded in the posture's revision history."}}}}}},"responses":{"200":{"description":"Updated posture with new revision.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostureRevision"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"delete":{"operationId":"deletePosture","summary":"Soft-delete a posture","description":"Sets deleted_at; revisions retained for audit.","tags":["Postures"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string"},"description":"Client-supplied idempotency token (required). Replays within 24 hours return the stored result; reusing a key with a different body returns 409. See ADR-023."},{"name":"posture_id","in":"path","required":true,"schema":{"type":"string","pattern":"^tp-[a-z0-9-]{1,64}$"},"description":"Posture ID (tp-{8-hex})."}],"responses":{"200":{"description":"Soft-deleted (sets deleted_at; revisions retained for audit).","content":{"application/json":{"schema":{"type":"object","required":["posture_id","deleted"],"additionalProperties":false,"properties":{"posture_id":{"type":"string"},"deleted":{"type":"boolean","enum":[true]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/postures/{posture_id}/assign":{"post":{"operationId":"assignPosture","summary":"Assign a posture to a team","description":"Sets the team's active posture. One active posture per team. Authorized: org_admin / org_owner / team_admin.","tags":["Postures"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string"},"description":"Client-supplied idempotency token (required). Replays within 24 hours return the stored result; reusing a key with a different body returns 409. See ADR-023."},{"name":"posture_id","in":"path","required":true,"schema":{"type":"string","pattern":"^tp-[a-z0-9-]{1,64}$"},"description":"Posture ID (tp-{8-hex})."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["team_id"],"properties":{"team_id":{"type":"string","format":"uuid","description":"UUID of the team to assign this posture to (becomes the team's single active posture)."},"revision_id":{"type":"string","description":"Pin to a specific revision (default: current_revision_id)."}}}}}},"responses":{"201":{"description":"Assignment created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostureAssignment"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/postures/{posture_id}/assignments/{team_id}":{"delete":{"operationId":"unassignPosture","summary":"Unassign a team from a posture","description":"Authorized: org_admin / org_owner / team_admin.","tags":["Postures"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string"},"description":"Client-supplied idempotency token (required). Replays within 24 hours return the stored result; reusing a key with a different body returns 409. See ADR-023."},{"name":"posture_id","in":"path","required":true,"schema":{"type":"string","pattern":"^tp-[a-z0-9-]{1,64}$"},"description":"Posture ID (tp-{8-hex})."},{"name":"team_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the team whose posture assignment to remove."}],"responses":{"200":{"description":"Unassigned (the team's posture assignment was removed).","content":{"application/json":{"schema":{"type":"object","required":["posture_id","team_id","removed"],"additionalProperties":false,"properties":{"posture_id":{"type":"string"},"team_id":{"type":"string","format":"uuid"},"removed":{"type":"boolean","enum":[true]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/postures/{posture_id}/clone":{"post":{"operationId":"clonePosture","summary":"Clone a posture into an org","description":"Copies the posture and its current revision into the target org's scope. Authorized: org_admin / org_owner of the destination org.","tags":["Postures"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string"},"description":"Client-supplied idempotency token (required). Replays within 24 hours return the stored result; reusing a key with a different body returns 409. See ADR-023."},{"name":"posture_id","in":"path","required":true,"schema":{"type":"string","pattern":"^tp-[a-z0-9-]{1,64}$"},"description":"Posture ID (tp-{8-hex})."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["target_org_id"],"properties":{"target_org_id":{"type":"string","description":"ID of the org that will own the cloned posture (the clone is created with scope=org)."},"name":{"type":"string","description":"Optional override for the cloned posture's name."}}}}}},"responses":{"201":{"description":"Posture.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Posture"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/postures/{posture_id}/diff":{"get":{"operationId":"diffPostureRevisions","summary":"Structural diff between two revisions","tags":["Postures"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"posture_id","in":"path","required":true,"schema":{"type":"string","pattern":"^tp-[a-z0-9-]{1,64}$"},"description":"Posture ID (tp-{8-hex})."},{"name":"from","in":"query","required":true,"schema":{"type":"integer","minimum":1},"description":"Revision number to diff from (the older/base revision)."},{"name":"to","in":"query","required":true,"schema":{"type":"integer","minimum":1},"description":"Revision number to diff to (the newer/target revision)."}],"responses":{"200":{"description":"Diff payload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostureDiff"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/postures/{posture_id}/effects":{"get":{"operationId":"getPostureEffects","summary":"Analytics rollup for a posture","description":"Counts of teams using, agents affected, and events emitted under this posture revision over the configured window.","tags":["Postures"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"posture_id","in":"path","required":true,"schema":{"type":"string","pattern":"^tp-[a-z0-9-]{1,64}$"},"description":"Posture ID (tp-{8-hex})."},{"name":"hours","in":"query","schema":{"type":"integer","minimum":1,"maximum":720,"default":24}}],"responses":{"200":{"description":"Effects rollup.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostureEffects"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/postures/{posture_id}/preview-compose":{"post":{"operationId":"previewComposePosture","summary":"Preview the composition this posture would produce for a team","description":"Composes alignment + protection cards using the posture body, the team's templates, and per-agent exemptions, without persisting. Useful for diff'ing before assigning.","tags":["Postures"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"posture_id","in":"path","required":true,"schema":{"type":"string","pattern":"^tp-[a-z0-9-]{1,64}$"},"description":"Posture ID (tp-{8-hex})."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["team_id"],"properties":{"team_id":{"type":"string","format":"uuid","description":"UUID of the team to compose the preview for (uses the team's templates and per-agent exemptions)."}}}}}},"responses":{"200":{"description":"Composed preview.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostureComposePreview"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/postures/{posture_id}/revisions":{"get":{"operationId":"listPostureRevisions","summary":"List all revisions of a posture","tags":["Postures"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"posture_id","in":"path","required":true,"schema":{"type":"string","pattern":"^tp-[a-z0-9-]{1,64}$"},"description":"Posture ID (tp-{8-hex})."}],"responses":{"200":{"description":"Revisions in chronological order.","content":{"application/json":{"schema":{"type":"object","required":["posture_id","revisions"],"properties":{"posture_id":{"type":"string","description":"The posture these revisions belong to (echoed from the path)."},"revisions":{"type":"array","items":{"$ref":"#/components/schemas/PostureRevision"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/postures/{posture_id}/revisions/{revision_number}":{"get":{"operationId":"getPostureRevision","summary":"Read a specific revision","tags":["Postures"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"posture_id","in":"path","required":true,"schema":{"type":"string","pattern":"^tp-[a-z0-9-]{1,64}$"},"description":"Posture ID (tp-{8-hex})."},{"name":"revision_number","in":"path","required":true,"schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"Posture revision body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostureRevision"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/presentations":{"get":{"operationId":"listMyPresentations","summary":"List presentations granted to the current user.","description":"Returns the presentations the caller holds an ACTIVE grant for (revoked_at IS NULL and not expired), each with the caller's tier. Drives the `/dashboard/presentations/` menu — an empty list means the menu is hidden. Authed user. MNE-1428.","tags":["Presentations"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Presentations granted to the caller (may be empty).","content":{"application/json":{"schema":{"type":"object","required":["presentations"],"properties":{"presentations":{"type":"array","items":{"type":"object","description":"A granted presentation, flattened with the caller's grant metadata.","required":["id","slug","title","status","tier","grant_id"],"properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","description":"URL-safe id, e.g. 'inside-mnemom'."},"title":{"type":"string"},"agent_id":{"type":["string","null"],"description":"The presentation's agent (e.g. Aletheia). prod agents.id; no FK."},"status":{"type":"string","enum":["draft","live","archived"]},"created_by":{"type":"string","format":"uuid","description":"auth.users.id of the minting admin."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"grant_id":{"type":"string","format":"uuid"},"tier":{"type":"string","enum":["L1","L2","L3"]},"expires_at":{"type":["string","null"],"format":"date-time"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/presentations/{slug}":{"get":{"operationId":"getPresentation","summary":"Get a presentation by slug (with the caller's tier).","description":"Returns the presentation and the caller's granted tier. 404 if no such presentation; 403 if the caller holds no active grant for it. Authed user. MNE-1428.","tags":["Presentations"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"The presentation slug."}],"responses":{"200":{"description":"The presentation + the caller's tier.","content":{"application/json":{"schema":{"type":"object","required":["presentation","tier"],"properties":{"presentation":{"type":"object","required":["id","slug","title","status","created_by","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","description":"URL-safe id, e.g. 'inside-mnemom'."},"title":{"type":"string"},"agent_id":{"type":["string","null"],"description":"The presentation's agent (e.g. Aletheia). prod agents.id; no FK."},"status":{"type":"string","enum":["draft","live","archived"]},"created_by":{"type":"string","format":"uuid","description":"auth.users.id of the minting admin."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"tier":{"type":"string","enum":["L1","L2","L3"]},"expires_at":{"type":["string","null"],"format":"date-time"},"voiceEnabled":{"type":"boolean","description":"Whether Aletheia voice mode is enabled for this caller. The FE gates the voice toggle on this. Always true on a 200: presentation access alone now grants both chat and voice, so a caller with no active grant gets a 403 rather than this payload with voiceEnabled:false."}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/presentations/{slug}/accept":{"post":{"operationId":"acceptPresentationInvite","summary":"Accept a presentation invite (attach the grant to the caller).","description":"The endpoint the invite email's CTA lands at after the recipient signs in / signs up. The single-use token comes from the body `{token}` or the `?token=` query param; it's hashed and matched to a pending grant for THIS presentation. On success the grant is attached to the caller (user_id + accepted_at set, token consumed) and the caller's tier is returned. The invite email is address-specific: the caller's account email MUST match the grant email (case-insensitive) or a 403 is returned. Authed user. Requires an `Idempotency-Key` header. MNE-1428.","tags":["Presentations"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"The presentation slug."},{"name":"token","in":"query","required":false,"schema":{"type":"string"},"description":"The single-use invite token. May instead be supplied in the JSON body as `token`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string"},"description":"Idempotency key (UUID). Replays within 24h return the same response."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","description":"The single-use invite token."}}}}}},"responses":{"200":{"description":"Invite accepted (or idempotently already accepted by this caller). Returns the presentation + the caller's tier.","content":{"application/json":{"schema":{"type":"object","required":["presentation","tier"],"properties":{"presentation":{"type":"object","required":["id","slug","title","status","created_by","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","description":"URL-safe id, e.g. 'inside-mnemom'."},"title":{"type":"string"},"agent_id":{"type":["string","null"],"description":"The presentation's agent (e.g. Aletheia). prod agents.id; no FK."},"status":{"type":"string","enum":["draft","live","archived"]},"created_by":{"type":"string","format":"uuid","description":"auth.users.id of the minting admin."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"tier":{"type":"string","enum":["L1","L2","L3"]},"accepted":{"type":"boolean"},"already_accepted":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"410":{"description":"The invite has expired.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","properties":{"code":{"type":"integer"},"message":{"type":"string"}}}}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/presentations/{slug}/chat":{"post":{"operationId":"presentationChat","summary":"Send a governed turn to the presentation's agent (Aletheia).","description":"One governed Aletheia turn (MNE-1428): routed through the Mnemom gateway (Safe House / AIP / CLPI / back-door screen in-path), executing read-only Mnemom MCP tools + a curated readiness brief scoped to the viewer's grant tier. Returns her answer, the per-round verdict cascade ({cfd,aip,policy,cbd}), citations, and a compact attestation. Authed user; requires an ACTIVE grant for the presentation. A Safe House hard-block is a governance success, not an error: it returns 200 with `blocked:true` and no answer. Chat is intentionally NOT idempotent (each turn is new), so no Idempotency-Key is required.","tags":["Presentations"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"The presentation slug."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["message"],"properties":{"message":{"type":"string","description":"The viewer's turn.","maxLength":4000},"deck":{"type":"string","description":"The deck's own text, handed over by the page that is already rendering it, so Aletheia reads it as her primary source. Capped server-side."},"history":{"type":"array","description":"Optional prior turns for multi-turn context. Only {role:'user'|'assistant', content:string} entries are honored; the newest 20 are kept.","items":{"type":"object","properties":{"role":{"type":"string","enum":["user","assistant"]},"content":{"type":"string"}}}}}}}}},"responses":{"200":{"description":"The turn's result. `ok:false` with `blocked:true` means Safe House withheld the response (governance success).","content":{"application/json":{"schema":{"type":"object","required":["ok","blocked","answer","citations","verdicts","attestation","tier"],"properties":{"ok":{"type":"boolean"},"blocked":{"type":"boolean"},"answer":{"type":["string","null"]},"tier":{"type":"string","enum":["L1","L2","L3"]},"citations":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"detail":{"type":"string"}}}},"verdicts":{"type":"array","items":{"type":"object","properties":{"round":{"type":"integer"},"cfd":{"type":["string","null"]},"aip":{"type":["string","null"]},"policy":{"type":["string","null"]},"cbd":{"type":["string","null"]},"advisory":{"type":["string","null"]}}}},"attestation":{"type":"object","properties":{"agent_id":{"type":["string","null"]},"session":{"type":["string","null"]},"model":{"type":"string"},"aip_checkpoint_id":{"type":["string","null"]},"screened_intervention":{"type":"boolean"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"description":"The governed chat runtime is currently unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Presentation chat is not configured on this deployment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/presentations/{slug}/voice/register":{"post":{"operationId":"presentationVoiceRegister","summary":"Start an Aletheia voice session for the presentation.","description":"Opens a voice session for the presentation's agent (Aletheia, MNE-1428 voice). Creates a Retell web call, mints a short-lived scoped voice-grant token, and hands it plus the deck + scope to the separate voice backend, which then proxies each spoken turn to `POST /v1/presentations/{slug}/chat` bearing that token. Governance (Safe House / tier / tools) stays entirely in the chat runtime — this endpoint re-implements none of it, and the token is authentication-only (the active grant remains the sole authority). Authed user; requires an ACTIVE grant. Returns the Retell web-call access token + call id for the browser SDK. Not idempotent (each session is new), so no Idempotency-Key is required.","tags":["Presentations"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"description":"The presentation slug."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"deck":{"type":"string","description":"The deck's own text, handed to the voice backend so Aletheia reads it as her primary source. Capped server-side."}}}}}},"responses":{"200":{"description":"The voice session was created. Returns the Retell web-call access token + call id for the browser's Retell web-call SDK.","content":{"application/json":{"schema":{"type":"object","required":["access_token","call_id"],"properties":{"access_token":{"type":"string","description":"The Retell web-call access token for the browser SDK."},"call_id":{"type":"string","description":"The Retell call id."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"description":"The voice provider or the voice backend failed to start the session.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Voice is not configured on this deployment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/protection/agent/{agent_id}":{"get":{"operationId":"getProtectionByAgent","summary":"Get this layer's protection manifest","description":"Returns the agent-scope protection spec as authored. Response is content-negotiated — YAML by default, or JSON with `Accept: application/json`. Pass `?include_composition=true` to include the `_composition` metadata block describing which scopes were merged. Pass `?include=sources` (see ADR-053) for the scope-resolution envelope — the contributing layers plus the composed result; the envelope shape is scope-specific (the four-scope `{teams[], agent}` body is the agent variant consumed by the dashboard editor). ETag is computed from `content_hash` (cards-as-primitive Phase 1); `If-None-Match` returns 304. For the composed view across scopes, use the `/effective` sub-resource (Wave 2).","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"include_composition","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include the `_composition` metadata block on the response body."},{"name":"Accept","in":"header","required":false,"schema":{"type":"string","enum":["text/yaml","application/yaml","application/json"]},"description":"Response format. YAML is canonical; JSON is returned only on explicit `application/json`. The `?include=sources` envelope is JSON-only."},{"name":"include","in":"query","required":false,"schema":{"type":"string","enum":["sources"]},"description":"When `sources`, returns the four-scope envelope `{platform, org, teams[], agent, composed, composed_stale, my_role}` (see ADR-053). The envelope is JSON-only."}],"responses":{"200":{"description":"Protection manifest at this scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the canonical body. Stable across reads; changes on PUT.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter (cards-as-primitive Phase 1).","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Schema identity.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnifiedProtectionCard"},{"$ref":"#/components/schemas/ProtectionCardSourcesEnvelope"}]}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}}}},"304":{"description":"Not Modified — the client's `If-None-Match` matches the current ETag."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"putProtectionByAgent","summary":"Publish or replace the protection manifest","description":"Accepts YAML (`text/yaml`, `application/yaml`) or JSON. Body is the full `UnifiedProtectionCard`; server-side composition merges it across the platform → org → team → agent cascade and writes the canonical composed card. Requires `Idempotency-Key`. Honors an optional `If-Match` for optimistic concurrency (stale → 412). Body cap 128 KiB. See ADR-008 and ADR-023.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result. See ADR-023."},{"name":"If-Match","in":"header","required":false,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optional optimistic-concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape) to make the write conditional: a stale ETag returns `412 Precondition Failed`, a malformed one `400`. Omit it to publish unconditionally."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}},"application/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}}}},"responses":{"200":{"description":"Composed canonical card after the write.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the new canonical body.","schema":{"type":"string"}},"X-Card-Version":{"description":"Bumped monotonically on every PUT that changes content_hash.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/agent/{agent_id}/effective":{"get":{"operationId":"getProtectionEffectiveByAgent","summary":"Get effective (composed) protection with provenance","description":"Returns the composed canonical protection card (platform → org → team → agent cascade applied) with `_composition.field_provenance` always populated. The provenance map carries per-key `{layer, layer_id?, kind?}` entries showing which authoring scope contributed each leaf. Caller-aware redaction: layer labels (`platform` / `org` / `team` / `agent` / `derived`) are always visible; `layer_id` is only revealed to callers who can read that scope. cards-as-primitive Phase 4 W2.2.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"Composed effective card with per-key field_provenance.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the composed body.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/agent/{agent_id}/explain":{"post":{"operationId":"explainProtectionByAgent","summary":"Explain policy evaluation for the protection card","description":"Calls the policy engine in dry-run mode against the agent's composed protection card and returns a structured trace + care-framed remediations. Optional `enrich: true` runs an LLM pass over the structured remediations to produce long-form prose; off by default. Read-style POST — no state mutation, no Idempotency-Key.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"turn_id":{"type":"string","description":"Optional — bind to a specific gateway turn."},"request_snippet":{"type":"object","description":"Optional — hypothetical tool call to explain.","properties":{"tool_name":{"type":"string"},"tool_args":{"type":"object","additionalProperties":true}}},"enrich":{"type":"boolean","description":"When true, runs an LLM pass over the structured remediations. Off by default."}}}}}},"responses":{"200":{"description":"Policy evaluation trace + remediations.","content":{"application/json":{"schema":{"type":"object","required":["ok","resource","reasoning","suggested_remediations","enriched"],"properties":{"ok":{"type":"boolean","const":true},"resource":{"type":"string","enum":["protection"]},"trace":{"type":"object","description":"EvaluationResult from @mnemom/policy-engine. Null for protection in V1.","nullable":true},"reasoning":{"type":"string","description":"Care-framed prose summary."},"suggested_remediations":{"type":"array","items":{"type":"object","required":["for","index","remediation"],"properties":{"for":{"type":"string","enum":["violation","warning","card_gap"]},"index":{"type":"integer"},"remediation":{"type":"string"},"method":{"type":"string"},"url":{"type":"string"}}}},"enriched":{"type":"boolean","description":"True when the LLM enrichment ran."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/agent/{agent_id}/mode":{"put":{"operationId":"putProtectionModeByAgent","summary":"Replace mode settings","description":"PUT replaces the entire `mode` block (the protection master switch (`off` / `observe` / `nudge` / `enforce`)). The current spec at the agent scope is read; the new `mode` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Sync recompose — the response carries the new canonical ETag + version.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"string","enum":["off","observe","nudge","enforce"]}},"application/yaml":{"schema":{"type":"string","enum":["off","observe","nudge","enforce"]}},"text/yaml":{"schema":{"type":"string","enum":["off","observe","nudge","enforce"]}}}},"responses":{"200":{"description":"The `mode` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["mode"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"string","enum":["off","observe","nudge","enforce"]},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchProtectionModeByAgent","summary":"Update mode settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `mode` block (the protection master switch (`off` / `observe` / `nudge` / `enforce`)). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"string","enum":["off","observe","nudge","enforce"]}}}},"responses":{"200":{"description":"The `mode` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["mode"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"string","enum":["off","observe","nudge","enforce"]},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/agent/{agent_id}/preview-compose":{"post":{"operationId":"previewComposeProtectionByAgent","summary":"Preview composed protection (dry run)","description":"Composes the cascade against a hypothetical body at the agent layer and returns conflicts + the composed view. No DB writes. Used by the dashboard editor for live conflict markers.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}},"application/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}}}},"responses":{"200":{"description":"Preview-compose result: composed card + conflicts + coherence violations.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","description":"Always true on a 200 (the dry-run completed)."},"composed":{"$ref":"#/components/schemas/UnifiedProtectionCard"},"conflicts":{"type":"array","items":{"type":"object"}},"coherence_violations":{"type":"array","items":{"type":"object"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/agent/{agent_id}/screen_surfaces":{"put":{"operationId":"putProtectionScreensurfacesByAgent","summary":"Replace screen surfaces settings","description":"PUT replaces the entire `screen_surfaces` block (which traffic surfaces the protection card inspects). The current spec at the agent scope is read; the new `screen_surfaces` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Sync recompose — the response carries the new canonical ETag + version.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}}},"application/yaml":{"schema":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}}},"text/yaml":{"schema":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}}}}},"responses":{"200":{"description":"The `screen_surfaces` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["screen_surfaces"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchProtectionScreensurfacesByAgent","summary":"Update screen surfaces settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `screen_surfaces` block (which traffic surfaces the protection card inspects). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}}}}},"responses":{"200":{"description":"The `screen_surfaces` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["screen_surfaces"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/agent/{agent_id}/simulate":{"post":{"operationId":"simulateProtectionByAgent","summary":"Simulate gateway evaluation against the protection card","description":"Pure-sync simulation: calls @mnemom/policy-engine twice (once with `context: \"gateway\"`, once with `context: \"observer\"`) using `dryRun: true` against the agent's current composed alignment card. Returns `{allowed, conditions, suggestions, gateway_decision, observer_assessment}`. Never crosses worker boundaries — no real gateway / observer state change.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"candidate_input":{"type":"object","description":"Hypothetical conversation snippet.","properties":{"messages":{"type":"array","items":{"type":"object","additionalProperties":true}}}},"candidate_tool_call":{"type":"object","description":"Hypothetical tool invocation. Synthesized into an assistant message with a toolUses block when `candidate_input.messages` is absent.","properties":{"tool_name":{"type":"string"},"tool_args":{"type":"object","additionalProperties":true}}}}}}}},"responses":{"200":{"description":"Simulation result.","content":{"application/json":{"schema":{"type":"object","required":["ok","resource","allowed","conditions","suggestions","gateway_decision","observer_assessment","evaluated_at"],"properties":{"ok":{"type":"boolean","const":true},"resource":{"type":"string","enum":["protection"]},"allowed":{"type":"string","enum":["true","false","conditional"]},"conditions":{"type":"array","items":{"type":"string"}},"suggestions":{"type":"array","items":{"type":"string"}},"gateway_decision":{"type":"object","properties":{"verdict":{"type":"string","enum":["pass","warn","fail"]},"violations":{"type":"array","items":{"type":"object"}},"warnings":{"type":"array","items":{"type":"object"}},"missing_receipts":{"type":"array","items":{"type":"string"}}}},"observer_assessment":{"type":"object","properties":{"verdict":{"type":"string","enum":["pass","warn","fail"]},"violations":{"type":"array","items":{"type":"object"}},"warnings":{"type":"array","items":{"type":"object"}}}},"evaluated_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/agent/{agent_id}/thresholds":{"put":{"operationId":"putProtectionThresholdsByAgent","summary":"Replace thresholds settings","description":"PUT replaces the entire `thresholds` block (warn / quarantine / block trip points (warn ≤ quarantine ≤ block, ∈ [0, 1])). The current spec at the agent scope is read; the new `thresholds` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Sync recompose — the response carries the new canonical ETag + version.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}}},"application/yaml":{"schema":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}}},"text/yaml":{"schema":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}}}}},"responses":{"200":{"description":"The `thresholds` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["thresholds"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchProtectionThresholdsByAgent","summary":"Update thresholds settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `thresholds` block (warn / quarantine / block trip points (warn ≤ quarantine ≤ block, ∈ [0, 1])). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}}}}},"responses":{"200":{"description":"The `thresholds` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["thresholds"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/agent/{agent_id}/trusted_sources":{"put":{"operationId":"putProtectionTrustedsourcesByAgent","summary":"Replace trusted sources settings","description":"PUT replaces the entire `trusted_sources` block (domain / agent / IP-range allow-list bypassing screening). The current spec at the agent scope is read; the new `trusted_sources` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Sync recompose — the response carries the new canonical ETag + version.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}}},"application/yaml":{"schema":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}}},"text/yaml":{"schema":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"The `trusted_sources` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["trusted_sources"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchProtectionTrustedsourcesByAgent","summary":"Update trusted sources settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `trusted_sources` block (domain / agent / IP-range allow-list bypassing screening). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"The `trusted_sources` primitive was updated at the agent scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter of the agent's canonical card.","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["agent"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["trusted_sources"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"version":{"type":"integer","minimum":1},"field_provenance":{"type":"object"},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/org/{org_id}":{"get":{"operationId":"getProtectionByOrg","summary":"Get this layer's protection manifest","description":"Returns the org-scope protection spec as authored. Response is content-negotiated — YAML by default, or JSON with `Accept: application/json`. Pass `?include_composition=true` to include the `_composition` metadata block describing which scopes were merged. Pass `?include=sources` (see ADR-053) for the scope-resolution envelope — the contributing layers plus the composed result; the envelope shape is scope-specific. ETag is computed from `content_hash` (cards-as-primitive Phase 1); `If-None-Match` returns 304. For the composed view across scopes, use the `/effective` sub-resource (Wave 2).","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"include_composition","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include the `_composition` metadata block on the response body."},{"name":"Accept","in":"header","required":false,"schema":{"type":"string","enum":["text/yaml","application/yaml","application/json"]},"description":"Response format. YAML is canonical; JSON is returned only on explicit `application/json`. The `?include=sources` envelope is JSON-only."},{"name":"include","in":"query","required":false,"schema":{"type":"string","enum":["sources"]},"description":"When `sources`, returns the scope-resolution envelope for this scope (the contributing layers + the composed result); the envelope shape is scope-specific (see ADR-053). The envelope is JSON-only."}],"responses":{"200":{"description":"Protection manifest at this scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the canonical body. Stable across reads; changes on PUT.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter (cards-as-primitive Phase 1).","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Schema identity.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"org_id":{"type":"string","format":"uuid"},"name":{"type":["string","null"]},"template":{"description":"The authored template JSON, or `null` when none is set."},"enabled":{"type":"boolean"}}}},"text/yaml":{"schema":{"type":"object","properties":{"org_id":{"type":"string","format":"uuid"},"name":{"type":["string","null"]},"template":{"description":"The authored template JSON, or `null` when none is set."},"enabled":{"type":"boolean"}}}}}},"304":{"description":"Not Modified — the client's `If-None-Match` matches the current ETag."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"putProtectionByOrg","summary":"Publish or replace the protection manifest","description":"Accepts YAML (`text/yaml`, `application/yaml`) or JSON. Body is the full `UnifiedProtectionCard`; server-side composition merges it across the platform → org → team → agent cascade and writes the canonical composed card. Requires `Idempotency-Key`. Body cap 128 KiB. See ADR-008 and ADR-023.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result. See ADR-023."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}},"application/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}}}},"responses":{"200":{"description":"Stored template wrapper after the write.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the new canonical body.","schema":{"type":"string"}},"X-Card-Version":{"description":"Bumped monotonically on every PUT that changes content_hash.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"type":"object","properties":{"org_id":{"type":"string","format":"uuid"},"template":{"description":"The stored template JSON after the write, or `null` when cleared."},"enabled":{"type":"boolean"},"agents_flagged_for_recompose":{"type":"integer","description":"Number of active member agents queued for re-composition."}}}},"text/yaml":{"schema":{"type":"object","properties":{"org_id":{"type":"string","format":"uuid"},"template":{"description":"The stored template JSON after the write, or `null` when cleared."},"enabled":{"type":"boolean"},"agents_flagged_for_recompose":{"type":"integer","description":"Number of active member agents queued for re-composition."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"delete":{"operationId":"deleteProtectionByOrg","summary":"Clear this protection layer","description":"Removes the org-scope protection authoring; downstream scopes fall through to the next layer up in the cascade.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"responses":{"200":{"description":"Cleared. Returns the deletion confirmation (`deleted: true`, `template: null`) and the count of agents flagged for recompose; the next read returns the composed view without this layer. (The handler returns this 200-with-body, not 204.)","content":{"application/json":{"schema":{"type":"object","properties":{"org_id":{"type":"string","format":"uuid"},"template":{"type":"null","description":"Always `null` after a delete."},"enabled":{"type":"boolean"},"deleted":{"type":"boolean","description":"Always `true`."},"agents_flagged_for_recompose":{"type":"integer","description":"Number of active member agents queued for re-composition."}}}},"text/yaml":{"schema":{"type":"object","properties":{"org_id":{"type":"string","format":"uuid"},"template":{"type":"null","description":"Always `null` after a delete."},"enabled":{"type":"boolean"},"deleted":{"type":"boolean","description":"Always `true`."},"agents_flagged_for_recompose":{"type":"integer","description":"Number of active member agents queued for re-composition."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/org/{org_id}/mode":{"put":{"operationId":"putProtectionModeByOrg","summary":"Replace mode settings","description":"PUT replaces the entire `mode` block (the protection master switch (`off` / `observe` / `nudge` / `enforce`)). The current spec at the org scope is read; the new `mode` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"string","enum":["off","observe","nudge","enforce"]}},"application/yaml":{"schema":{"type":"string","enum":["off","observe","nudge","enforce"]}},"text/yaml":{"schema":{"type":"string","enum":["off","observe","nudge","enforce"]}}}},"responses":{"200":{"description":"The `mode` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["mode"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"string","enum":["off","observe","nudge","enforce"]},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchProtectionModeByOrg","summary":"Update mode settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `mode` block (the protection master switch (`off` / `observe` / `nudge` / `enforce`)). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"string","enum":["off","observe","nudge","enforce"]}}}},"responses":{"200":{"description":"The `mode` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["mode"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"string","enum":["off","observe","nudge","enforce"]},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/org/{org_id}/preview-compose":{"post":{"operationId":"previewComposeProtectionByOrg","summary":"Preview composed protection (dry run)","description":"Composes the cascade against a hypothetical body at the org layer and returns conflicts + the composed view. No DB writes. Used by the dashboard editor for live conflict markers.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}},"application/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}}}},"responses":{"200":{"description":"Preview-compose result: composed card + conflicts + coherence violations.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","description":"Always true on a 200 (the dry-run completed)."},"composed":{"$ref":"#/components/schemas/UnifiedProtectionCard"},"conflicts":{"type":"array","items":{"type":"object"}},"coherence_violations":{"type":"array","items":{"type":"object"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/org/{org_id}/screen_surfaces":{"put":{"operationId":"putProtectionScreensurfacesByOrg","summary":"Replace screen surfaces settings","description":"PUT replaces the entire `screen_surfaces` block (which traffic surfaces the protection card inspects). The current spec at the org scope is read; the new `screen_surfaces` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}}},"application/yaml":{"schema":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}}},"text/yaml":{"schema":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}}}}},"responses":{"200":{"description":"The `screen_surfaces` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["screen_surfaces"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchProtectionScreensurfacesByOrg","summary":"Update screen surfaces settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `screen_surfaces` block (which traffic surfaces the protection card inspects). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}}}}},"responses":{"200":{"description":"The `screen_surfaces` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["screen_surfaces"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/org/{org_id}/thresholds":{"put":{"operationId":"putProtectionThresholdsByOrg","summary":"Replace thresholds settings","description":"PUT replaces the entire `thresholds` block (warn / quarantine / block trip points (warn ≤ quarantine ≤ block, ∈ [0, 1])). The current spec at the org scope is read; the new `thresholds` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}}},"application/yaml":{"schema":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}}},"text/yaml":{"schema":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}}}}},"responses":{"200":{"description":"The `thresholds` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["thresholds"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchProtectionThresholdsByOrg","summary":"Update thresholds settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `thresholds` block (warn / quarantine / block trip points (warn ≤ quarantine ≤ block, ∈ [0, 1])). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}}}}},"responses":{"200":{"description":"The `thresholds` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["thresholds"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/org/{org_id}/trusted_sources":{"put":{"operationId":"putProtectionTrustedsourcesByOrg","summary":"Replace trusted sources settings","description":"PUT replaces the entire `trusted_sources` block (domain / agent / IP-range allow-list bypassing screening). The current spec at the org scope is read; the new `trusted_sources` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}}},"application/yaml":{"schema":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}}},"text/yaml":{"schema":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"The `trusted_sources` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["trusted_sources"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchProtectionTrustedsourcesByOrg","summary":"Update trusted sources settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `trusted_sources` block (domain / agent / IP-range allow-list bypassing screening). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/OrgId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"The `trusted_sources` primitive was updated at the org scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["org"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["trusted_sources"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/platform/{scope_id}":{"get":{"operationId":"getProtectionByPlatform","summary":"Get this layer's protection manifest","description":"Returns the platform-scope protection spec as authored. Response is content-negotiated — YAML by default, or JSON with `Accept: application/json`. Pass `?include_composition=true` to include the `_composition` metadata block describing which scopes were merged. Pass `?include=sources` (see ADR-053) for the scope-resolution envelope — the contributing layers plus the composed result; the envelope shape is scope-specific. ETag is computed from `content_hash` (cards-as-primitive Phase 1); `If-None-Match` returns 304. For the composed view across scopes, use the `/effective` sub-resource (Wave 2).","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"include_composition","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include the `_composition` metadata block on the response body."},{"name":"Accept","in":"header","required":false,"schema":{"type":"string","enum":["text/yaml","application/yaml","application/json"]},"description":"Response format. YAML is canonical; JSON is returned only on explicit `application/json`. The `?include=sources` envelope is JSON-only."},{"name":"include","in":"query","required":false,"schema":{"type":"string","enum":["sources"]},"description":"When `sources`, returns the scope-resolution envelope for this scope (the contributing layers + the composed result); the envelope shape is scope-specific (see ADR-053). The envelope is JSON-only."}],"responses":{"200":{"description":"Protection manifest at this scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the canonical body. Stable across reads; changes on PUT.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter (cards-as-primitive Phase 1).","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Schema identity.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/PlatformCardDefaultsResponse"},{"$ref":"#/components/schemas/PlatformCardSourcesEnvelope"}]}},"text/yaml":{"schema":{"$ref":"#/components/schemas/PlatformCardDefaultsResponse"}}}},"304":{"description":"Not Modified — the client's `If-None-Match` matches the current ETag."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"putProtectionByPlatform","summary":"Publish or replace the protection manifest","description":"Accepts YAML (`text/yaml`, `application/yaml`) or JSON. Body is the full `UnifiedProtectionCard`; server-side composition merges it across the platform → org → team → agent cascade and writes the canonical composed card. Requires `Idempotency-Key`. Body cap 128 KiB. See ADR-008 and ADR-023.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result. See ADR-023."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}},"application/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}}}},"responses":{"200":{"description":"Composed canonical card after the write.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the new canonical body.","schema":{"type":"string"}},"X-Card-Version":{"description":"Bumped monotonically on every PUT that changes content_hash.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/platform/{scope_id}/mode":{"put":{"operationId":"putProtectionModeByPlatform","summary":"Replace mode settings","description":"PUT replaces the entire `mode` block (the protection master switch (`off` / `observe` / `nudge` / `enforce`)). The current spec at the platform scope is read; the new `mode` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"string","enum":["off","observe","nudge","enforce"]}},"application/yaml":{"schema":{"type":"string","enum":["off","observe","nudge","enforce"]}},"text/yaml":{"schema":{"type":"string","enum":["off","observe","nudge","enforce"]}}}},"responses":{"200":{"description":"The `mode` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["mode"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"string","enum":["off","observe","nudge","enforce"]},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchProtectionModeByPlatform","summary":"Update mode settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `mode` block (the protection master switch (`off` / `observe` / `nudge` / `enforce`)). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"string","enum":["off","observe","nudge","enforce"]}}}},"responses":{"200":{"description":"The `mode` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["mode"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"string","enum":["off","observe","nudge","enforce"]},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/platform/{scope_id}/preview-compose":{"post":{"operationId":"previewComposeProtectionByPlatform","summary":"Preview composed protection (dry run)","description":"Composes the cascade against a hypothetical body at the platform layer and returns conflicts + the composed view. No DB writes. Used by the dashboard editor for live conflict markers.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}},"application/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}}}},"responses":{"200":{"description":"Preview-compose result: composed card + conflicts + coherence violations.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","description":"Always true on a 200 (the dry-run completed)."},"composed":{"$ref":"#/components/schemas/UnifiedProtectionCard"},"conflicts":{"type":"array","items":{"type":"object"}},"coherence_violations":{"type":"array","items":{"type":"object"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/platform/{scope_id}/screen_surfaces":{"put":{"operationId":"putProtectionScreensurfacesByPlatform","summary":"Replace screen surfaces settings","description":"PUT replaces the entire `screen_surfaces` block (which traffic surfaces the protection card inspects). The current spec at the platform scope is read; the new `screen_surfaces` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}}},"application/yaml":{"schema":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}}},"text/yaml":{"schema":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}}}}},"responses":{"200":{"description":"The `screen_surfaces` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["screen_surfaces"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchProtectionScreensurfacesByPlatform","summary":"Update screen surfaces settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `screen_surfaces` block (which traffic surfaces the protection card inspects). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}}}}},"responses":{"200":{"description":"The `screen_surfaces` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["screen_surfaces"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/platform/{scope_id}/thresholds":{"put":{"operationId":"putProtectionThresholdsByPlatform","summary":"Replace thresholds settings","description":"PUT replaces the entire `thresholds` block (warn / quarantine / block trip points (warn ≤ quarantine ≤ block, ∈ [0, 1])). The current spec at the platform scope is read; the new `thresholds` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}}},"application/yaml":{"schema":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}}},"text/yaml":{"schema":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}}}}},"responses":{"200":{"description":"The `thresholds` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["thresholds"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchProtectionThresholdsByPlatform","summary":"Update thresholds settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `thresholds` block (warn / quarantine / block trip points (warn ≤ quarantine ≤ block, ∈ [0, 1])). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}}}}},"responses":{"200":{"description":"The `thresholds` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["thresholds"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/platform/{scope_id}/trusted_sources":{"put":{"operationId":"putProtectionTrustedsourcesByPlatform","summary":"Replace trusted sources settings","description":"PUT replaces the entire `trusted_sources` block (domain / agent / IP-range allow-list bypassing screening). The current spec at the platform scope is read; the new `trusted_sources` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}}},"application/yaml":{"schema":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}}},"text/yaml":{"schema":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"The `trusted_sources` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["trusted_sources"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchProtectionTrustedsourcesByPlatform","summary":"Update trusted sources settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `trusted_sources` block (domain / agent / IP-range allow-list bypassing screening). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"scope_id","in":"path","required":true,"schema":{"type":"string","enum":["default"]},"description":"Always `default` — the platform scope is a singleton; any other value returns 400 with care-framed guidance pointing at `default`."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"The `trusted_sources` primitive was updated at the platform scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["platform"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["trusted_sources"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/scaffold":{"post":{"operationId":"scaffoldProtection","summary":"Scaffold protection from a description","description":"Calls an LLM (Claude Haiku by default; opt into Sonnet via `model: \"sonnet\"`) with the catalog and tools-registry context, returns a YAML manifest scaffold + care-framed reasoning prose + suggested catalog entries + coverage gaps. Never auto-commits — the caller reviews and edits before PUT. Cached by (model + scope + description + hints) hash; 24-hour TTL.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["description"],"properties":{"description":{"type":"string","minLength":20,"maxLength":2000,"description":"Free-form description of the agent / scope. Untrusted input — the system prompt instructs the model not to follow embedded directives."},"scope":{"type":"string","enum":["platform","org","team","agent"],"description":"Hint to the model about which scope the manifest will live at."},"hints":{"type":"object","description":"Free-form key/value hints (industry, risk_appetite, existing_tools, etc).","additionalProperties":true},"model":{"type":"string","enum":["haiku","sonnet"],"description":"Claude model to invoke. `haiku` is the default; `sonnet` for prose-heavy reasoning."}}}}}},"responses":{"200":{"description":"Scaffold ready. Editable; never auto-commits.","content":{"application/json":{"schema":{"type":"object","required":["ok","resource","manifest","reasoning","cached","model"],"properties":{"ok":{"type":"boolean","const":true},"resource":{"type":"string","enum":["protection"]},"manifest":{"type":"string","description":"YAML body of the scaffolded manifest."},"reasoning":{"type":"string","description":"Care-framed prose explanation."},"suggested_catalog_entries":{"type":"array","items":{"type":"string"}},"coverage_gaps":{"type":"array","items":{"type":"object","properties":{"axis":{"type":"string"},"note":{"type":"string"}},"required":["note"]}},"parse_warnings":{"type":"array","items":{"type":"string"}},"cached":{"type":"boolean","description":"True when the response was served from the description-hash cache."},"model":{"type":"string","description":"Claude model id used for the call."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"$ref":"#/components/responses/ServiceUnavailable"},"504":{"$ref":"#/components/responses/BadGateway"}}}},"/protection/team/{team_id}":{"get":{"operationId":"getProtectionByTeam","summary":"Get this layer's protection manifest","description":"Returns the team-scope protection spec as authored. Response is content-negotiated — YAML by default, or JSON with `Accept: application/json`. Pass `?include_composition=true` to include the `_composition` metadata block describing which scopes were merged. Pass `?include=sources` (see ADR-053) for the scope-resolution envelope — the contributing layers plus the composed result; the envelope shape is scope-specific. ETag is computed from `content_hash` (cards-as-primitive Phase 1); `If-None-Match` returns 304. For the composed view across scopes, use the `/effective` sub-resource (Wave 2).","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"include_composition","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include the `_composition` metadata block on the response body."},{"name":"Accept","in":"header","required":false,"schema":{"type":"string","enum":["text/yaml","application/yaml","application/json"]},"description":"Response format. YAML is canonical; JSON is returned only on explicit `application/json`. The `?include=sources` envelope is JSON-only."},{"name":"include","in":"query","required":false,"schema":{"type":"string","enum":["sources"]},"description":"When `sources`, returns the scope-resolution envelope for this scope (the contributing layers + the composed result); the envelope shape is scope-specific (see ADR-053). The envelope is JSON-only."}],"responses":{"200":{"description":"Protection manifest at this scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the canonical body. Stable across reads; changes on PUT.","schema":{"type":"string"}},"X-Card-Version":{"description":"Monotonic version counter (cards-as-primitive Phase 1).","schema":{"type":"integer","minimum":1}},"X-Mnemom-Schema":{"description":"Schema identity.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"org_id":{"type":"string","format":"uuid"},"name":{"type":["string","null"]},"template":{"description":"The authored template JSON, or `null` when none is set."},"enabled":{"type":"boolean"}}}},"text/yaml":{"schema":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"org_id":{"type":"string","format":"uuid"},"name":{"type":["string","null"]},"template":{"description":"The authored template JSON, or `null` when none is set."},"enabled":{"type":"boolean"}}}}}},"304":{"description":"Not Modified — the client's `If-None-Match` matches the current ETag."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"putProtectionByTeam","summary":"Publish or replace the protection manifest","description":"Accepts YAML (`text/yaml`, `application/yaml`) or JSON. Body is the full `UnifiedProtectionCard`; server-side composition merges it across the platform → org → team → agent cascade and writes the canonical composed card. Requires `Idempotency-Key`. Body cap 128 KiB. See ADR-008 and ADR-023.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result. See ADR-023."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}},"application/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}}}},"responses":{"200":{"description":"Stored template wrapper after the write.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the new canonical body.","schema":{"type":"string"}},"X-Card-Version":{"description":"Bumped monotonically on every PUT that changes content_hash.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"org_id":{"type":"string","format":"uuid"},"template":{"description":"The stored template JSON after the write, or `null` when cleared."},"enabled":{"type":"boolean"},"agents_flagged_for_recompose":{"type":"integer","description":"Number of active member agents queued for re-composition."}}}},"text/yaml":{"schema":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"org_id":{"type":"string","format":"uuid"},"template":{"description":"The stored template JSON after the write, or `null` when cleared."},"enabled":{"type":"boolean"},"agents_flagged_for_recompose":{"type":"integer","description":"Number of active member agents queued for re-composition."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"delete":{"operationId":"deleteProtectionByTeam","summary":"Clear this protection layer","description":"Removes the team-scope protection authoring; downstream scopes fall through to the next layer up in the cascade.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"200":{"description":"Cleared. Returns the deletion confirmation (`deleted: true`, `template: null`) and the count of agents flagged for recompose; the next read returns the composed view without this layer. (The handler returns this 200-with-body, not 204.)","content":{"application/json":{"schema":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"org_id":{"type":"string","format":"uuid"},"template":{"type":"null","description":"Always `null` after a delete."},"enabled":{"type":"boolean"},"deleted":{"type":"boolean","description":"Always `true`."},"agents_flagged_for_recompose":{"type":"integer","description":"Number of active member agents queued for re-composition."}}}},"text/yaml":{"schema":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"org_id":{"type":"string","format":"uuid"},"template":{"type":"null","description":"Always `null` after a delete."},"enabled":{"type":"boolean"},"deleted":{"type":"boolean","description":"Always `true`."},"agents_flagged_for_recompose":{"type":"integer","description":"Number of active member agents queued for re-composition."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/team/{team_id}/mode":{"put":{"operationId":"putProtectionModeByTeam","summary":"Replace mode settings","description":"PUT replaces the entire `mode` block (the protection master switch (`off` / `observe` / `nudge` / `enforce`)). The current spec at the team scope is read; the new `mode` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"string","enum":["off","observe","nudge","enforce"]}},"application/yaml":{"schema":{"type":"string","enum":["off","observe","nudge","enforce"]}},"text/yaml":{"schema":{"type":"string","enum":["off","observe","nudge","enforce"]}}}},"responses":{"200":{"description":"The `mode` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["mode"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"string","enum":["off","observe","nudge","enforce"]},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchProtectionModeByTeam","summary":"Update mode settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `mode` block (the protection master switch (`off` / `observe` / `nudge` / `enforce`)). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"string","enum":["off","observe","nudge","enforce"]}}}},"responses":{"200":{"description":"The `mode` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["mode"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"string","enum":["off","observe","nudge","enforce"]},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/team/{team_id}/preview-compose":{"post":{"operationId":"previewComposeProtectionByTeam","summary":"Preview composed protection (dry run)","description":"Composes the cascade against a hypothetical body at the team layer and returns conflicts + the composed view. No DB writes. Used by the dashboard editor for live conflict markers.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}},"application/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}},"text/yaml":{"schema":{"$ref":"#/components/schemas/UnifiedProtectionCard"}}}},"responses":{"200":{"description":"Preview-compose result: composed card + conflicts + coherence violations.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","description":"Always true on a 200 (the dry-run completed)."},"composed":{"$ref":"#/components/schemas/UnifiedProtectionCard"},"conflicts":{"type":"array","items":{"type":"object"}},"coherence_violations":{"type":"array","items":{"type":"object"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/team/{team_id}/screen_surfaces":{"put":{"operationId":"putProtectionScreensurfacesByTeam","summary":"Replace screen surfaces settings","description":"PUT replaces the entire `screen_surfaces` block (which traffic surfaces the protection card inspects). The current spec at the team scope is read; the new `screen_surfaces` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}}},"application/yaml":{"schema":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}}},"text/yaml":{"schema":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}}}}},"responses":{"200":{"description":"The `screen_surfaces` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["screen_surfaces"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchProtectionScreensurfacesByTeam","summary":"Update screen surfaces settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `screen_surfaces` block (which traffic surfaces the protection card inspects). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}}}}},"responses":{"200":{"description":"The `screen_surfaces` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["screen_surfaces"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["incoming","outgoing","tool_calls","tool_responses"],"properties":{"incoming":{"type":"boolean"},"outgoing":{"type":"boolean"},"tool_calls":{"type":"boolean"},"tool_responses":{"type":"boolean"}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/team/{team_id}/thresholds":{"put":{"operationId":"putProtectionThresholdsByTeam","summary":"Replace thresholds settings","description":"PUT replaces the entire `thresholds` block (warn / quarantine / block trip points (warn ≤ quarantine ≤ block, ∈ [0, 1])). The current spec at the team scope is read; the new `thresholds` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}}},"application/yaml":{"schema":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}}},"text/yaml":{"schema":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}}}}},"responses":{"200":{"description":"The `thresholds` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["thresholds"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchProtectionThresholdsByTeam","summary":"Update thresholds settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `thresholds` block (warn / quarantine / block trip points (warn ≤ quarantine ≤ block, ∈ [0, 1])). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}}}}},"responses":{"200":{"description":"The `thresholds` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["thresholds"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["warn","quarantine","block"],"properties":{"warn":{"type":"number","minimum":0,"maximum":1},"quarantine":{"type":"number","minimum":0,"maximum":1},"block":{"type":"number","minimum":0,"maximum":1}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/protection/team/{team_id}/trusted_sources":{"put":{"operationId":"putProtectionTrustedsourcesByTeam","summary":"Replace trusted sources settings","description":"PUT replaces the entire `trusted_sources` block (domain / agent / IP-range allow-list bypassing screening). The current spec at the team scope is read; the new `trusted_sources` is spliced in; the merged spec is validated; recompose is triggered. Requires `Idempotency-Key` and `If-Match`. Async fan-out — the response carries `agents_flagged_for_recompose`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}}},"application/yaml":{"schema":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}}},"text/yaml":{"schema":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"The `trusted_sources` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["trusted_sources"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"patchProtectionTrustedsourcesByTeam","summary":"Update trusted sources settings","description":"PATCH applies RFC 7396 JSON Merge Patch to the `trusted_sources` block (domain / agent / IP-range allow-list bypassing screening). `null` deletes a key; missing keeps; present replaces. Arrays are replaced wholesale (not item-merged). Requires `Idempotency-Key` and `If-Match`.","tags":["Protection"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Client-supplied idempotency token. Replays within 24 hours return the stored result verbatim. See ADR-023."},{"name":"If-Match","in":"header","required":true,"schema":{"type":"string","pattern":"^\"sha256:[0-9a-f]{64}\"$"},"description":"Optimistic concurrency token. Pass the `ETag` from a recent `GET` (`\"sha256:<hex64>\"` shape). A stale ETag returns `412 Precondition Failed`; a missing header returns `428 Precondition Required`. See RFC 9110 §13.1.1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"The `trusted_sources` primitive was updated at the team scope.","headers":{"ETag":{"description":"`\"sha256:<hex>\"` of the spec at this scope after the write.","schema":{"type":"string"}},"X-Mnemom-Schema":{"description":"Sub-resource response schema identifier.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","scope","scope_id","resource","primitive","verb","value","content_hash"],"properties":{"ok":{"type":"boolean","const":true},"scope":{"type":"string","enum":["team"]},"scope_id":{"type":"string"},"resource":{"type":"string","enum":["protection"]},"primitive":{"type":"string","enum":["trusted_sources"]},"verb":{"type":"string","enum":["put","patch"]},"value":{"type":"object","required":["domains","agent_ids","ip_ranges"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"agent_ids":{"type":"array","items":{"type":"string"}},"ip_ranges":{"type":"array","items":{"type":"string"}}}},"content_hash":{"type":"string","description":"New `sha256:<hex64>` of the spec at this scope after the write."},"agents_flagged_for_recompose":{"type":"integer","minimum":0},"_warnings":{"type":"object","description":"Pre-existing structural issues outside the modified primitive. Present only when the existing spec carries unrelated validation problems; never blocks the write."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"$ref":"#/components/responses/PreconditionFailed"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"428":{"$ref":"#/components/responses/PreconditionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/realtime/governance":{"get":{"operationId":"subscribeGovernanceRealtime","summary":"Subscribe to live governance signal updates (SSE)","description":"Server-Sent Events stream that emits one `event: signal` per `governance_signals` insert/update matching the caller's filter. For `scope=org|agent` it ALSO emits an `event: agent.claimed` frame (`{agent_id, org_id, name, claimed_at}`) when an agent is claimed into the scope, so an open dashboard shows it appear live (Dojo MNE-521). RBAC mirrors the REST list endpoints: `scope=platform` requires Mnemom staff; `scope=org|team|agent` requires org membership. The stream emits an initial `event: ready` marker, then events as they arrive, plus periodic `:heartbeat` comments. Connection lifetime is capped at 5 minutes — clients should reconnect.","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"scope","in":"query","required":false,"schema":{"type":"string","enum":["platform","org","team","agent"],"default":"org"},"description":"Subscription scope. `platform` requires staff; the rest require the matching scope id."},{"name":"org_id","in":"query","required":false,"schema":{"type":"string"}},{"name":"team_id","in":"query","required":false,"schema":{"type":"string"}},{"name":"agent_id","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream of governance signal events.","content":{"text/event-stream":{"schema":{"type":"string","description":"Newline-delimited SSE frames: `event: ready` then `event: signal\\ndata: <GovernanceSignal JSON>` per update, plus `:heartbeat` comments."}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/recipes/{recipeId}/report":{"post":{"operationId":"reportRecipeFnFp","summary":"Report a false-positive or false-negative against a protection recipe","description":"Files a false-negative ('fn') or false-positive ('fp') report against an existing detection_recipes id. The customer is recorded as the 'created' identity on the recipe_review_actions chain; the candidate lands in `pending` state and awaits review. Requires customer-session auth (JWT cookie / bearer) OR an API key. **Idempotency-Key header is REQUIRED** — the body hash is folded into the reservation so a customer can re-submit with corrected details without 422'ing.","tags":["Recipes"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"recipeId","in":"path","required":true,"description":"The detection_recipes id the report is filed against (the recipe that misfired or failed to fire).","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string"},"description":"Client-supplied UUID (or comparable) for de-duplication. Same key + same body within 24h replays the prior response; same key + different body returns 422."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","summary"],"properties":{"type":{"type":"string","enum":["fn","fp"],"description":"'fn' (false negative — recipe should have fired) or 'fp' (false positive — recipe fired on legitimate behaviour)."},"summary":{"type":"string","minLength":1,"description":"Customer's description of what happened."},"evidence":{"type":"string","description":"Optional raw payload / log excerpt the admin reviewer can inspect."},"agent_id":{"type":"string","description":"Optional. Customer's agent id, when the report concerns a specific agent."},"checkpoint_id":{"type":"string","description":"Optional. Related integrity_checkpoints id (helps the reviewer correlate)."}}}}}},"responses":{"201":{"description":"Candidate created; awaiting review.","content":{"application/json":{"schema":{"type":"object","required":["ok","candidate_id","type","related_recipe_id"],"properties":{"ok":{"type":"boolean","enum":[true]},"candidate_id":{"type":"string"},"type":{"type":"string","enum":["fn","fp"]},"related_recipe_id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/reputation/batch":{"post":{"operationId":"batchReputation","x-proxied":"REPUTATION_SERVICE","summary":"Batch reputation lookup (auth required)","description":"Returns reputation rows for up to 50 agent ids. Requires API key or bearer JWT (rate-limited as `search_batch` — 30/min per auth principal). Private-visibility agents return a stub row with `score: null`.","tags":["Reputation"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["agent_ids"],"properties":{"agent_ids":{"type":"array","items":{"type":"string"},"maxItems":50,"minItems":0}}}}}},"responses":{"200":{"description":"Scores (private rows return stubs).","content":{"application/json":{"schema":{"type":"object","required":["scores"],"properties":{"scores":{"type":"array","items":{"oneOf":[{"$ref":"#/components/schemas/ReputationScore"},{"type":"object","properties":{"agent_id":{"type":"string"},"visibility":{"type":"string","enum":["private"]},"score":{"type":"null"},"grade":{"type":"null"}}}]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/reputation/benchmarks":{"get":{"operationId":"getReputationBenchmarks","x-proxied":"REPUTATION_SERVICE","summary":"Aggregate reputation benchmarks","description":"Returns mean/median/p25/p75/p90 score and a grade-distribution histogram across every eligible agent. Cached. Public, rate-limited (`benchmarks` bucket).","tags":["Reputation"],"security":[],"responses":{"200":{"description":"Benchmark stats.","content":{"application/json":{"schema":{"type":"object","required":["total_eligible","mean_score","median_score","p25_score","p75_score","p90_score","grade_distribution"],"properties":{"total_eligible":{"type":"integer"},"mean_score":{"type":"number"},"median_score":{"type":"number"},"p25_score":{"type":"number"},"p75_score":{"type":"number"},"p90_score":{"type":"number"},"grade_distribution":{"type":"object","additionalProperties":{"type":"integer"}}}}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/reputation/compare":{"get":{"operationId":"compareReputation","x-proxied":"REPUTATION_SERVICE","summary":"Compare 2–10 agents' reputation scores","description":"Returns the reputation rows for the given agent ids (comma-separated, 2–10). Private-visibility agents are silently filtered out. Public endpoint, cached 5 min.","tags":["Reputation"],"security":[],"parameters":[{"name":"ids","in":"query","required":true,"schema":{"type":"string"},"description":"Comma-separated list of 2–10 agent ids."}],"responses":{"200":{"description":"Comparison result.","content":{"application/json":{"schema":{"type":"object","required":["agents"],"properties":{"agents":{"type":"array","items":{"$ref":"#/components/schemas/ReputationScore"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/reputation/search":{"get":{"operationId":"searchReputationDirectory","x-proxied":"REPUTATION_SERVICE","summary":"Search the public reputation directory","description":"Lists agents whose reputation visibility is `public`, with optional filters. `q` matches on agent name (or `smolt-`/`mnm-` ID prefix). Unclaimed, not-rated (NR) agents appear at the bottom when the filters permit. Page-based pagination.","tags":["Reputation"],"security":[],"parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string"},"description":"Name search (ilike) or agent-id prefix match."},{"name":"grade","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to one grade (e.g. `AAA`, `B`, `NR`)."},{"name":"confidence","in":"query","required":false,"description":"Filter to agents at a given reputation-confidence level (driven by how much evidence backs the score).","schema":{"type":"string","enum":["high","medium","low","insufficient"]}},{"name":"sort","in":"query","required":false,"description":"Result ordering. Default \"score\" (highest-rated first); other supported keys order by recency or name.","schema":{"type":"string","default":"score"}},{"name":"page","in":"query","required":false,"description":"1-based page number for pagination. Default 1.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","required":false,"description":"Number of results per page. 1–100, default 20.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"Directory page.","content":{"application/json":{"schema":{"type":"object","required":["agents","total","page","per_page"],"properties":{"agents":{"type":"array","items":{"$ref":"#/components/schemas/ReputationScore"}},"total":{"type":"integer"},"page":{"type":"integer"},"per_page":{"type":"integer"}}}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/reputation/{agent_id}":{"get":{"operationId":"getReputation","x-proxied":"REPUTATION_SERVICE","summary":"Get reputation score for an agent","description":"Returns the agent's current reputation: numeric score (0–1000), letter grade (AAA–D, NR for not-rated), tier, five-component breakdown, 30-day trend, and an A2A trust extension block for interop. Private-visibility agents return 403 to non-owners. Public endpoint, IP-rate-limited (lookup bucket).","tags":["Reputation"],"security":[],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"Reputation score with A2A trust extension.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReputationScore"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/reputation/{agent_id}/badge.svg":{"get":{"operationId":"getReputationBadge","x-proxied":"REPUTATION_SERVICE","summary":"Embeddable SVG reputation badge","description":"Returns an SVG image (image/svg+xml) showing the agent's grade + score, suitable for embedding in GitHub README files, docs, or dashboards. Public, rate-limited (`badge` bucket).","tags":["Reputation"],"security":[],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"SVG badge.","content":{"image/svg+xml":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/reputation/{agent_id}/events":{"get":{"operationId":"getReputationEvents","x-proxied":"REPUTATION_SERVICE","summary":"List recent reputation events","description":"Returns up to 50 most-recent reputation events (violation detected, card amendment, reclassification applied, etc). Public endpoint.","tags":["Reputation"],"security":[],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"Recent events.","content":{"application/json":{"schema":{"type":"object","required":["events"],"properties":{"events":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/reputation/{agent_id}/history":{"get":{"operationId":"getReputationHistory","x-proxied":"REPUTATION_SERVICE","summary":"Get weekly reputation snapshots","description":"Returns up to 52 weekly snapshots of the agent's reputation (most recent first). Public endpoint.","tags":["Reputation"],"security":[],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"Weekly snapshots.","content":{"application/json":{"schema":{"type":"object","required":["snapshots"],"properties":{"snapshots":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/reputation/{agent_id}/og-image":{"get":{"operationId":"getReputationOgImage","x-proxied":"REPUTATION_SERVICE","summary":"Open Graph share-card image for an agent","description":"Returns a 1200×630 PNG (or rendered HTML fallback) suitable for `og:image` link previews when the agent's profile is shared.","tags":["Reputation"],"security":[],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"Share-card image.","content":{"image/png":{"schema":{"type":"string","format":"binary"}},"text/html":{"schema":{"type":"string"}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/reputation/{agent_id}/recompute":{"post":{"operationId":"recomputeReputationScore","summary":"Trigger score recomputation","description":"Trigger a full recomputation of the agent's reputation and compliance scores. This re-evaluates all checkpoints, reclassifications, and card amendments to produce an updated score. Useful after bulk reclassifications or policy changes.","tags":["Reclassification"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"},"description":"Agent identifier"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","description":"Reason for triggering recomputation"},"include_reclassifications":{"type":"boolean","default":true,"description":"Whether to include pending reclassifications in the recomputation"}}}}}},"responses":{"200":{"description":"Recomputation result with new scores","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"previous_score":{"type":"number"},"new_score":{"type":"number"},"delta":{"type":"number"},"reclassifications_applied":{"type":"integer"},"recomputed_at":{"type":"string","format":"date-time"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/reputation/{agent_id}/verify":{"get":{"operationId":"verifyReputation","x-proxied":"REPUTATION_SERVICE","summary":"Cryptographic verification bundle for an agent's reputation","description":"Returns the score plus a `verification` block containing: the latest certificate hash, the agent's Merkle root, checkpoint count, first/last checkpoint timestamps, and a `hash_chain_valid` flag. Response is Cache-Control 3600s. Public endpoint.","tags":["Reputation"],"security":[],"parameters":[{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"Verification bundle.","headers":{"Cache-Control":{"schema":{"type":"string","example":"public, max-age=3600, s-maxage=3600"}}},"content":{"application/json":{"schema":{"type":"object","required":["agent_id","score","grade","computed_at","verification"],"properties":{"agent_id":{"type":"string"},"score":{"type":"number"},"grade":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"verification":{"type":["object","null"],"properties":{"latest_certificate_hash":{"type":["string","null"]},"merkle_root":{"type":["string","null"]},"checkpoint_count":{"type":"integer"},"first_checkpoint":{"type":["string","null"],"format":"date-time"},"last_checkpoint":{"type":["string","null"],"format":"date-time"},"hash_chain_valid":{"type":"boolean"},"certificate_url":{"type":["string","null"]}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/risk/assess":{"post":{"operationId":"assessRisk","x-proxied":"RISK_SERVICE","summary":"Assess risk for a single agent action","description":"Compute an individual risk assessment for an agent about to take an action. Requires JWT auth and the `risk_assessment` feature flag on the caller's plan. Dispatches a ZK proof request asynchronously (best-effort; check `/risk/proofs/{proof_id}` to retrieve). Cached for 5 minutes per `{agent_id, action_type, risk_tolerance, amount}` tuple.","tags":["Risk"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["agent_id","context"],"properties":{"agent_id":{"type":"string"},"source":{"type":"string","enum":["api","playground"],"default":"api"},"context":{"type":"object","required":["action_type"],"properties":{"action_type":{"type":"string","enum":["financial_transaction","data_access","task_delegation","tool_invocation","autonomous_operation","multi_agent_coordination"]},"amount":{"type":"number"},"counterparty_id":{"type":"string"},"use_case":{"type":"string"},"risk_tolerance":{"type":"string","enum":["conservative","moderate","aggressive"],"default":"moderate"}}}}}}}},"responses":{"200":{"description":"Risk assessment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RiskAssessment"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/risk/assess/team":{"post":{"operationId":"assessTeamRisk","x-proxied":"RISK_SERVICE","summary":"Assess risk for a team of agents","description":"Compute a team-level risk assessment given an explicit `agent_ids` list (or a `team_id` to resolve the roster). Produces three-pillar results: portfolio, coherence, concentration, plus weakest-link and Shapley attribution. Dispatches a team-coherence ZK proof asynchronously.","tags":["Risk"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["context"],"properties":{"agent_ids":{"type":"array","items":{"type":"string"},"description":"Explicit agent roster; required if `team_id` is not provided."},"team_id":{"type":"string","description":"Resolve roster from this team id; required if `agent_ids` is not provided."},"source":{"type":"string","enum":["api","playground"]},"context":{"type":"object","required":["action_type"],"properties":{"action_type":{"type":"string"},"amount":{"type":"number"},"use_case":{"type":"string"},"risk_tolerance":{"type":"string"},"team_task":{"type":"string"},"coordination_mode":{"type":"string"},"trigger":{"type":"string"},"governance_median":{"type":["number","null"]},"conflict_edge_count":{"type":"integer"},"conscience_universal":{"type":["boolean","null"]}}}}}}}},"responses":{"200":{"description":"Team risk assessment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamRiskAssessment"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/risk/assessments/{assessment_id}":{"get":{"operationId":"getRiskAssessment","x-proxied":"RISK_SERVICE","summary":"Get a single risk assessment by id","tags":["Risk"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"assessment_id","in":"path","required":true,"schema":{"type":"string"},"description":"Individual assessment id (`ra-…`)."}],"responses":{"200":{"description":"Assessment row.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RiskAssessment"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/risk/history/{agent_id}":{"get":{"operationId":"getRiskHistory","x-proxied":"RISK_SERVICE","summary":"List historical risk assessments for an agent","tags":["Risk"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AgentId"},{"name":"limit","in":"query","required":false,"description":"Maximum number of risk assessments to return (most recent first). 1–100, default 20.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"offset","in":"query","required":false,"description":"Number of assessments to skip before returning results, for pagination. Default 0.","schema":{"type":"integer","minimum":0,"default":0}},{"name":"include_playground","in":"query","required":false,"description":"When true, include assessments produced in playground/test runs alongside production ones. Default false (production only).","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"History page.","content":{"application/json":{"schema":{"type":"object","properties":{"assessments":{"type":"array","items":{"$ref":"#/components/schemas/RiskAssessment"}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/risk/proofs/{proof_id}":{"get":{"operationId":"getRiskProof","x-proxied":"RISK_SERVICE","summary":"Get a ZK proof for a risk assessment","description":"Retrieve a ZK proof artifact (individual or team-coherence) by its proof id. Proofs are generated fire-and-forget after `/risk/assess` and `/risk/assess/team` and may take tens of seconds to complete.","tags":["Risk"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"proof_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Proof row (status, artifact, metadata).","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/risk/team-assessments/{assessment_id}":{"get":{"operationId":"getTeamRiskAssessment","x-proxied":"RISK_SERVICE","summary":"Get a single team risk assessment by id","tags":["Risk"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"assessment_id","in":"path","required":true,"schema":{"type":"string"},"description":"Team assessment id (`tra-…`)."}],"responses":{"200":{"description":"Team assessment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamRiskAssessment"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/risk/team-history/{team_id}":{"get":{"operationId":"getTeamRiskHistory","x-proxied":"RISK_SERVICE","summary":"List historical team risk assessments for a team","tags":["Risk"],"security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"History page.","content":{"application/json":{"schema":{"type":"object","properties":{"team_id":{"type":"string"},"assessments":{"type":"array","items":{"$ref":"#/components/schemas/TeamRiskAssessment"}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/safe-house/audit":{"get":{"operationId":"safeHouseAuditLog","summary":"Audit log for Safe House actions","tags":["Safe House"],"responses":{"200":{"description":"Audit entries.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/campaigns":{"get":{"operationId":"listSafeHouseCampaigns","summary":"List detected threat campaigns","tags":["Safe House"],"responses":{"200":{"description":"Campaigns.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/campaigns/{campaign_id}/resolve":{"post":{"operationId":"resolveSafeHouseCampaign","summary":"Resolve a detected campaign","tags":["Safe House"],"parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"resolution":{"type":"string"},"notes":{"type":"string"}}}}}},"responses":{"200":{"description":"Resolved."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/canaries":{"get":{"operationId":"listSafeHouseCanaries","summary":"List canary credentials for an agent","tags":["Safe House"],"parameters":[{"name":"agent_id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Canary list.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SafeHouseCanary"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"post":{"operationId":"createSafeHouseCanary","summary":"Create a canary credential","description":"Generates a format-valid but non-functional credential (api_key / password / database_url / ssh_key / oauth_token). The canary value is **only returned on creation** — plant it in the agent's context so exfiltration attempts trip it.","tags":["Safe House"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["agent_id","canary_type"],"properties":{"agent_id":{"type":"string"},"canary_type":{"type":"string","enum":["api_key","password","database_url","ssh_key","oauth_token"]}}}}}},"responses":{"201":{"description":"Canary created. `canary_value` is returned once and must be captured.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SafeHouseCanary"},{"type":"object","required":["canary_value"],"properties":{"canary_value":{"type":"string"}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/canaries/{canary_id}/status":{"get":{"operationId":"getCanaryStatus","summary":"Check whether a canary has been triggered","tags":["Safe House"],"parameters":[{"name":"canary_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Canary status (no value returned).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SafeHouseCanary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/cbd/evaluations":{"get":{"operationId":"listCbdEvaluations","summary":"Query outbound (egress) Safe House evaluations","description":"Same shape as `/safe-house/evaluations`, but scoped to outbound (egress) screening — exfiltration detection on agent-originated traffic.","tags":["Safe House"],"deprecated":true,"responses":{"200":{"description":"Evaluation page.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SafeHouseEvaluationPage"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/cbd/evaluations/{evaluation_id}":{"get":{"operationId":"getCbdEvaluation","summary":"Get a single outbound (egress) evaluation","tags":["Safe House"],"deprecated":true,"parameters":[{"name":"evaluation_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Evaluation record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SafeHouseEvaluation"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/config/bulk-apply":{"post":{"operationId":"safeHouseBulkApply","summary":"Bulk apply a Safe House config to up to 500 agents","tags":["Safe House"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["agent_ids","config"],"properties":{"agent_ids":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":500},"config":{"type":"object","properties":{"mode":{"type":"string","enum":["disabled","off","observe","enforce","enforce_sync"]},"thresholds":{"type":"object","properties":{"warn":{"type":"number"},"quarantine":{"type":"number"},"block":{"type":"number"}}},"screen_surfaces":{"type":"array","items":{"type":"string"}},"trusted_sources":{"type":"array","items":{"type":"string"}},"settings":{"type":"object","additionalProperties":true}}}}}}}},"responses":{"200":{"description":"Applied.","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"integer"},"failed":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/context-cards":{"get":{"operationId":"safeHouseContextCards","summary":"List customer-authored context cards used for trust inference","tags":["Safe House"],"responses":{"200":{"description":"Context cards.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/evaluations":{"get":{"operationId":"listSafeHouseEvaluations","summary":"Query inbound Safe House evaluations","description":"Paginated query of `sh_evaluations` (inbound prompt screening). Time-bounded by `from`/`to` (default last 24h). Cursor-paginated via `after`.","tags":["Safe House"],"parameters":[{"name":"agent_id","in":"query","required":false,"schema":{"type":"string"}},{"name":"verdict","in":"query","required":false,"schema":{"type":"string"}},{"name":"threat_type","in":"query","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"min_risk","in":"query","required":false,"schema":{"type":"number"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"default":25}},{"name":"after","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Evaluation page.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SafeHouseEvaluationPage"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/evaluations/{evaluation_id}":{"get":{"operationId":"getSafeHouseEvaluation","summary":"Get a single Safe House evaluation","tags":["Safe House"],"parameters":[{"name":"evaluation_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Evaluation record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SafeHouseEvaluation"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/feed":{"get":{"operationId":"safeHouseFeed","summary":"Server-Sent Events stream of Safe House evaluations","description":"Long-lived SSE stream that pushes new Safe House evaluations in near-real-time. Polls internally every 2s, heartbeats every ~15s, and closes after 5 minutes (client should reconnect). Filter by agent, org, surface, verdict list (comma-separated), and minimum risk.","tags":["Safe House"],"parameters":[{"name":"agent_id","in":"query","required":false,"schema":{"type":"string"}},{"name":"org_id","in":"query","required":false,"schema":{"type":"string"}},{"name":"surface","in":"query","required":false,"schema":{"type":"string"}},{"name":"verdict","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated verdict filter (e.g. `quarantine,block`)."},{"name":"min_risk","in":"query","required":false,"schema":{"type":"number"}}],"responses":{"200":{"description":"SSE stream; each `data:` line is a JSON event (agent_id, verdict, overall_risk, top_threat, …).","content":{"text/event-stream":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/ingest-pattern":{"post":{"operationId":"safeHouseIngestPattern","summary":"Ingest a customer-supplied threat pattern","description":"Customer-submitted patterns feed the L1/L2 detection pipeline. See also the arena's public pattern feed.","tags":["Safe House"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"201":{"description":"Pattern ingested."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/metrics/risk-dist":{"get":{"operationId":"safeHouseMetricsRiskDist","summary":"Risk-score distribution over a window","tags":["Safe House"],"responses":{"200":{"description":"Distribution buckets.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/metrics/summary":{"get":{"operationId":"safeHouseMetricsSummary","summary":"Aggregate verdict counts over a window","tags":["Safe House"],"parameters":[{"name":"agent_id","in":"query","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Summary counts.","content":{"application/json":{"schema":{"type":"object","properties":{"pass":{"type":"integer"},"warn":{"type":"integer"},"quarantine":{"type":"integer"},"block":{"type":"integer"},"total":{"type":"integer"},"block_rate":{"type":"number"},"warn_rate":{"type":"number"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/metrics/threats":{"get":{"operationId":"safeHouseMetricsThreats","summary":"Threat-type histogram over a window","tags":["Safe House"],"responses":{"200":{"description":"Histogram.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/metrics/timeseries":{"get":{"operationId":"safeHouseMetricsTimeseries","summary":"Time-series of verdict counts","tags":["Safe House"],"parameters":[{"name":"agent_id","in":"query","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"bucket","in":"query","required":false,"schema":{"type":"string","enum":["hour","day"],"default":"hour"}}],"responses":{"200":{"description":"Buckets.","content":{"application/json":{"schema":{"type":"object","properties":{"buckets":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/outbound/evaluations":{"get":{"operationId":"listOutboundEvaluations","summary":"Query outbound (egress) Safe House evaluations","description":"Same shape as `/safe-house/evaluations`, but scoped to outbound (egress) screening — exfiltration detection on agent-originated traffic.","tags":["Safe House"],"responses":{"200":{"description":"Evaluation page.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SafeHouseEvaluationPage"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/outbound/evaluations/{evaluation_id}":{"get":{"operationId":"getOutboundEvaluation","summary":"Get a single outbound (egress) evaluation","tags":["Safe House"],"parameters":[{"name":"evaluation_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Evaluation record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SafeHouseEvaluation"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/patterns":{"get":{"operationId":"listSafeHousePatterns","summary":"List active threat patterns","tags":["Safe House"],"parameters":[{"name":"threat_type","in":"query","required":false,"schema":{"type":"string"}},{"name":"source","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"default":50}}],"responses":{"200":{"description":"Active patterns.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SafeHousePattern"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"post":{"operationId":"createSafeHousePattern","summary":"Add a new threat pattern","description":"Requires API key or bearer JWT. `label: \"benign\"` adds a known-safe pattern (reduces false positives).","tags":["Safe House"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["threat_type","content","label"],"properties":{"threat_type":{"type":"string"},"content":{"type":"string"},"label":{"type":"string","enum":["malicious","benign"]},"source":{"type":"string","default":"arena"},"minhash":{"type":["string","null"]},"metadata":{"type":"object","additionalProperties":true}}}}}},"responses":{"201":{"description":"Pattern created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SafeHousePattern"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/quarantine":{"get":{"operationId":"listQuarantine","summary":"List quarantined messages","description":"Returns quarantined messages for the caller's org, filterable by status. Quarantine holds messages that **Safe House** flagged during inbound screening.","tags":["Safe House"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","released","deleted","confirmed_threat","all"],"default":"pending"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"default":25}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Quarantine page.","content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/QuarantineItem"}},"total":{"type":["integer","null"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/quarantine/{quarantine_id}":{"get":{"operationId":"getQuarantineItem","summary":"Get a single quarantined message","tags":["Safe House"],"parameters":[{"name":"quarantine_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Quarantine record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuarantineItem"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"delete":{"operationId":"deleteQuarantineItem","summary":"Delete a quarantine item without releasing","description":"Marks the item `deleted`. The underlying content hash is retained for audit. No refund of the original (blocked) prompt to the calling agent.","tags":["Safe House"],"parameters":[{"name":"quarantine_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"quarantine_id":{"type":"string"},"status":{"type":"string","enum":["deleted"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/quarantine/{quarantine_id}/release":{"post":{"operationId":"releaseQuarantineItem","summary":"Release a quarantined message back to the agent","description":"Flip status to `released`. Pass `is_false_positive: true` in the body to record a calibration signal and write a benign-labeled pattern (helps tune L1/L2 detection).","tags":["Safe House"],"parameters":[{"name":"quarantine_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"is_false_positive":{"type":"boolean","default":false}}}}}},"responses":{"200":{"description":"Released.","content":{"application/json":{"schema":{"type":"object","properties":{"quarantine_id":{"type":"string"},"status":{"type":"string","enum":["released"]},"false_positive_recorded":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/quarantine/{quarantine_id}/report":{"post":{"operationId":"reportQuarantineThreat","summary":"Confirm a quarantined message as a threat","description":"Marks the item `confirmed_threat` for arena sideband analysis. Does **not** write to `sh_threat_patterns` — the quarantine store holds only a content hash, and the pattern table requires plaintext.","tags":["Safe House"],"parameters":[{"name":"quarantine_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Confirmed.","content":{"application/json":{"schema":{"type":"object","properties":{"quarantine_id":{"type":"string"},"status":{"type":"string","enum":["confirmed_threat"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/report-incident":{"post":{"operationId":"safeHouseReportIncident","summary":"Report a security incident","description":"Agent self-reporting of a security incident. Authenticated by the agent's own possession proof (AgentAuth, `X-Mnemom-Agent-Proof`) — not a user/account api-key. 401 on absent/malformed/unmatched proof.","tags":["Safe House"],"security":[{"AgentAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"201":{"description":"Incident recorded."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/reviews":{"get":{"operationId":"listSafeHouseReviews","summary":"List the calling agent's review-hold lifecycle","description":"The reconcile/backfill (\"pull, truth\") leg of the Safe House review-hold lifecycle (Task A1, canonical-consumer plan) — the same shape delivered live via the `sh.review.*` webhook. Agent-scoped, not org/user-scoped: `agent_id` is always resolved from the caller's own possession proof (AgentAuth), never from a query parameter, so one agent can never read another's reviews.","tags":["Safe House"],"security":[{"AgentAuth":[]}],"parameters":[{"name":"run_id","in":"query","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","allowed","denied","expired"]}},{"name":"since","in":"query","required":false,"description":"ISO timestamp; exclusive lower bound on `created_at`.","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","required":false,"description":"Clamped to [1, 100]; defaults to 50.","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"The agent's review-hold lifecycle rows, newest first.","content":{"application/json":{"schema":{"type":"object","required":["reviews"],"properties":{"reviews":{"type":"array","items":{"$ref":"#/components/schemas/ReviewLifecycle"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/reviews/{review_id}":{"get":{"operationId":"getSafeHouseReview","summary":"Get a single review-hold lifecycle row by id","description":"Agent-scoped (Task A2, canonical-consumer plan): returns **404, never 403**, for a `review_id` belonging to another agent — the lookup is always scoped to the caller's own authenticated identity, so an unowned id and an unknown id are indistinguishable (no existence leak).","tags":["Safe House"],"security":[{"AgentAuth":[]}],"parameters":[{"name":"review_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The review-hold lifecycle row.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewLifecycle"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/reviews/{review_id}/held-content":{"post":{"operationId":"revealSafeHouseReviewHeldContent","summary":"Reveal the decrypted withheld content of a review-hold","description":"Return the decrypted original held message of a Safe House review-hold so an authorized human can read it before ruling (Wave 4). POST (not GET) so the `SameSite=Lax` session cookie makes it CSRF-safe like `/resolve`; the request carries no body. Customer/human auth (an authenticated member of the org that governs the review's agent, or platform staff). A `review_id` outside the caller's authority returns **404, never 403** (no existence leak, mirroring resolve). The decrypt happens gateway-side (keys never leave the gateway) and is strictly read-only — it never changes the hold's state. The plaintext is disclosed only after its reveal is durably audit-logged. Works for a hold in any status. Fails closed (**502**) on a gateway/vault error or an audit-write failure — never a fabricated or unaudited plaintext.","tags":["Safe House"],"parameters":[{"name":"review_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The decrypted held content.","content":{"application/json":{"schema":{"type":"object","required":["review_id","content"],"properties":{"review_id":{"type":"string"},"content":{"type":"string","description":"The decrypted original held message."}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"}}}},"/safe-house/reviews/{review_id}/resolve":{"post":{"operationId":"resolveSafeHouseReview","summary":"Resolve a human-tier review-hold (allow/deny/escalate)","description":"The human decider for a Safe House review-hold (Wave 4). Customer/human auth (an authenticated org member, or platform staff) — the resolver is ALWAYS the authenticated principal, NEVER read from the body. A `review_id` outside the caller's org fleet returns **404, never 403** (no existence leak). `allow`/`deny` finalize the hold through the gateway (a NEW Ed25519-signed decision row; on `allow`, the decrypted original plus a single-use, content-bound allow-token are returned). `escalate` is **non-terminal**: it records the action, signals higher-tier attention, and leaves the hold `pending`. When the agent's card requires dual-control, a terminal ruling needs **two distinct** resolvers to concur — a same-identity second action returns **409**, and divergent votes escalate.","tags":["Safe House"],"parameters":[{"name":"review_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["decision"],"properties":{"decision":{"type":"string","enum":["allow","deny","escalate"],"description":"`allow`/`deny` finalize (single-control) or count toward dual-control concurrence; `escalate` is non-terminal."},"reason":{"type":"string","description":"Optional free-text rationale recorded on the approvals ledger."}}}}}},"responses":{"200":{"description":"The resolution outcome. Terminal on a finalized `allow`/`deny` (with the allow-token + decrypted content on `allow`); otherwise `pending` (escalated, or awaiting a second dual-control approver).","content":{"application/json":{"schema":{"type":"object","required":["review_id","status"],"properties":{"review_id":{"type":"string"},"status":{"type":"string","enum":["allowed","denied","pending"]},"allow_token":{"type":"string","description":"Single-use, `content_hash`-bound, short-TTL token honored by the gateway on re-submit. Present only on a finalized `allow`."},"content":{"type":"string","description":"The decrypted original held content. Present only on a finalized `allow`."},"awaiting":{"type":"string","enum":["second_approver"],"description":"Present when dual-control is required and this is the first concurring resolver."},"escalated":{"type":"boolean","description":"True when the action escalated the hold for higher-tier attention (explicit escalate, or divergent dual-control votes)."},"reason":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"}}}},"/safe-house/sessions":{"get":{"operationId":"listSafeHouseSessions","summary":"List Safe House sessions (threat clusters)","tags":["Safe House"],"responses":{"200":{"description":"Session list.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/stats":{"get":{"operationId":"getSafeHouseStats","summary":"Aggregate Safe House evaluation stats","tags":["Safe House"],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"default":7}}],"responses":{"200":{"description":"Per-tenant verdict counts + threat-type histogram over the window, scoped to the caller's org. Empty window returns zeroed counts (never 500).","content":{"application/json":{"schema":{"type":"object","properties":{"verdicts":{"type":"object","description":"Count of evaluations by verdict (pass/warn/quarantine/block).","additionalProperties":{"type":"integer"}},"threat_types":{"type":"array","description":"Top threat types by occurrence over the window.","items":{"type":"object","properties":{"threat_type":{"type":"string"},"count":{"type":"integer"}}}},"period_days":{"type":"integer"},"total_messages":{"type":"integer","description":"Total evaluations in the window."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/safe-house/threshold-suggestions":{"get":{"operationId":"safeHouseThresholdSuggestions","summary":"Adaptive threshold recommendations","description":"Returns suggested warn/quarantine/block thresholds based on recent evaluation history, to reduce false positives without losing threat coverage.","tags":["Safe House"],"responses":{"200":{"description":"Suggested thresholds (array; empty when no history accumulated yet or on internal fallback).","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/sign/operator-attestation":{"post":{"operationId":"signOperatorAttestation","summary":"Sign an operator attestation envelope","description":"Returns an Ed25519-signed envelope binding the operator's identity + role to a free-form statement about an asserted subject. Used for compliance attestation chains where an operator's signature is required (e.g., closing a critical governance signal with a note that's later shown in audit).","tags":["Verification"],"security":[{"BearerAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorAttestationRequest"}}}},"responses":{"201":{"description":"Signed attestation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorAttestationResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/sim/agents/{agent_id}/force-end":{"post":{"operationId":"forceEndAgentSimSessions","summary":"Force-end every active sim session for an agent (runaway recovery).","description":"DB-authoritative, Durable-Object-independent recovery for a stuck/runaway Dojo session: aborts every non-terminal (`pending`/`running`/`paused`) `dojo_sim_sessions` row for the agent directly in the control plane, clearing the one-active-session-per-agent lock even when the per-session runner DO has crashed or been evicted (the ghost-DO case `/sim/{session_id}/stop` cannot resolve, because that path no-ops the DB when the DO has no in-memory state). Keyed by `agent_id` because a locked-out caller holds the agent id, not the orphaned session id. Idempotent: returns `{ ok: true, ended: 0 }` when nothing was active. MNE-531.","tags":["Dojo"],"parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Active sessions aborted (or none were active).","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"ended":{"type":"integer","description":"Number of sessions aborted."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/sim/sessions":{"post":{"operationId":"createSimSession","summary":"Create a Dojo sim session and begin the runner (\"Begin Sim\").","description":"Creates a `dojo_sim_sessions` row for the agent + scenario and starts the server-side runner (a per-session Durable Object that drives the Agent Smith ↔ agent loop and survives the human closing the tab). The runner resolves the agent's gateway compute key server-side BY `agent_id` (via the agent↔TryMeConfig link from onboarding) — the cleartext key never travels in the request. Emits SimEvents readable via `GET /v1/sim/{session_id}/stream`. MNE-531.\n\nThis operation returns `409` for THREE distinct causes; branch on the stable `error.code`, NEVER on the status alone (a client that assumes 409 means \"a session is already running\" will offer a force-end remedy that cannot help, succeeds at ending nothing, and loops):\n\n- `active_sim_session` — the agent already has a `pending`/`running`/`paused` session. `error.details.session_id` carries the BLOCKING session's id so the client can stop that session directly. It is omitted (no `details` at all) on the DB unique-constraint backstop path, where a concurrent create raced the pre-check and the racing session's id is not known.\n- `dojo_provider_key_missing` — no dojo provider key resolves for the agent's provider. An admin must set it (`/admin/dojo`) and the agent must be bound to its Try-Me config. Force-ending sessions does nothing for this.\n- `agent_unnamed` — `agents.name` is empty for this agent, and the sim needs a name to spar as it. Remedy: `PUT /v1/agents/{id}` with `{\"name\": \"…\"}` (2-32 chars, letters/digits/hyphens), then retry. Names are normally written at birth from the gateway's `x-mnemom-agent` header, but birth is NOT the only writer — do not send the operator back through birth for an agent that already exists. Force-ending sessions does nothing for this.\n\nAn unrecognised or absent code on a 409 should fall back to displaying `error.message` verbatim rather than assuming any of the above.","tags":["Dojo"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["agent_id","scenario_id"],"properties":{"agent_id":{"type":"string","description":"Prod agent id to spar (the runner resolves its compute key server-side)."},"scenario_id":{"type":"string","description":"dojo_scenarios.id (e.g. 'db-shepherd')."},"mode":{"type":"string","enum":["auto","manual"],"default":"auto"},"max_turns":{"type":"integer","minimum":1},"reviewer_kind":{"type":"string","enum":["builtin_opus","human"],"default":"builtin_opus","description":"The review policy for this run's Safe House review-holds (Wave 4 §13). 'builtin_opus' (default) resolves synchronously; 'human' routes a hold to the human-tier resolve endpoint. Assigns the sim agent to the corresponding STANDING, non-weakenable team-scope review-policy team before the run starts — this is owner-authoritative policy, never a per-agent card upsert the agent could weaken."},"capture_payloads":{"type":"boolean","default":false,"description":"Mnemom-staff only: arm raw-payload capture for the debug export BEFORE the run starts, so payloads are captured from turn 1 (MNE-923). Honored only when the caller is a platform admin (capture is staff-only); ignored otherwise."}}}}}},"responses":{"201":{"description":"Session created and runner started.","content":{"application/json":{"schema":{"type":"object","required":["session_id","agent_id","scenario_id","mode","state"],"properties":{"session_id":{"type":"string","format":"uuid"},"agent_id":{"type":"string"},"scenario_id":{"type":"string"},"mode":{"type":"string","enum":["auto","manual"]},"state":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/sim/{session_id}/attack":{"post":{"operationId":"submitSimManualAttack","summary":"Submit a Manual-mode Agent Smith attack.","description":"In Manual mode the human supplies Agent Smith's turn; this injects one Smith↔agent exchange into the running session. 409 if the session is not running or is in Auto mode. MNE-531.","tags":["Dojo"],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["attack"],"properties":{"attack":{"type":"string","description":"The adversarial prompt."}}}}}},"responses":{"200":{"description":"Attack accepted; the exchange is scheduled.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/sim/{session_id}/capture":{"post":{"operationId":"setSimCapturePayloads","summary":"Toggle raw-payload capture for a Dojo run (Mnemom staff).","description":"Sets the session's `capture_payloads` flag. When ON, the runner records `debug`-kind SimEvents carrying the raw outbound model request envelope + latency for the staff debug export (`GET /sim/{id}/export?audience=debug`). Default OFF (faithful 'sim user state'). Read fresh by the runner each tick, so a toggle takes effect on the next turn. Mnemom-staff ONLY. MNE-692.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"True to record raw model payloads for this run; false to stop."}}}}}},"responses":{"200":{"description":"Capture flag updated.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"session_id":{"type":"string","format":"uuid"},"capture_payloads":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/sim/{session_id}/config":{"post":{"operationId":"updateSimConfig","summary":"Update a running Dojo sim session's live config (mode / security posture / judge).","description":"Lets the operator change three run controls WHILE a sim is actively running (previously fixed at Begin-Sim): `mode` (auto/manual), `security_posture_in_prompt` (the A/B prompt toggle), and `reviewer_kind` (builtin_opus/human — the Judge). A partial update — every field is optional; only changed fields need be present. `security_posture_in_prompt` takes effect on the NEXT turn. Switching `reviewer_kind` re-homes the sim agent's team-scope review policy (remove from the old team, assign to the new); a real change is only available for the db-shepherd scenario and 502s if the reassignment fails (the session's reviewer_kind is left unchanged). Switching `mode` from manual to auto resumes the auto-tick loop immediately; auto to manual halts it after the in-flight turn. 404 if the session doesn't exist; 409 if it has already reached a terminal state. MNE-531 (dojo live-config).","tags":["Dojo"],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["auto","manual"],"description":"Switch between Auto (server-paced) and Manual (human-attack) mode."},"security_posture_in_prompt":{"type":"boolean","description":"A/B toggle for whether the agent's system prompt is security-aware. Takes effect on the next turn."},"reviewer_kind":{"type":"string","enum":["builtin_opus","human"],"description":"The Judge for this run's review holds. Only available for the db-shepherd scenario."}}}}}},"responses":{"200":{"description":"Config updated; returns the resulting effective config.","content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["auto","manual"]},"security_posture_in_prompt":{"type":"boolean"},"reviewer_kind":{"type":"string","enum":["builtin_opus","human"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/InternalServerError"}}}},"/sim/{session_id}/export":{"get":{"operationId":"exportSimRun","summary":"Export a full Dojo run to a downloadable file.","description":"Dumps the complete, timestamped record of a run. `audience=ciso` (customer/CISO, the default) returns the run summary, transcript, per-checkpoint verdicts, nudges, tools and breaches PLUS signed verification pointers so a third party can independently re-verify the Ed25519 checkpoint chain — it never includes raw model payloads, and is authorized for the session's agent owner (ADR-062). `audience=debug` additionally includes the full raw event stream with captured model payloads and is Mnemom-staff ONLY. Choose `json` (canonical), `yaml`, or `md` (readable transcript). MNE-692.","tags":["Dojo"],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"audience","in":"query","required":false,"schema":{"type":"string","enum":["ciso","debug"],"default":"ciso"},"description":"`ciso` (customer, default) or `debug` (Mnemom staff — raw payloads)."},{"name":"format","in":"query","required":false,"schema":{"type":"string","enum":["json","yaml","md"],"default":"json"},"description":"Serialization format of the downloaded file."}],"responses":{"200":{"description":"The run export as a downloadable attachment (`Content-Disposition`). Content type follows `format`: `application/json`, `application/yaml`, or `text/markdown`.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}},"application/yaml":{"schema":{"type":"string"}},"text/markdown":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/sim/{session_id}/heartbeat":{"post":{"operationId":"heartbeatSimSession","summary":"Keep an Auto Dojo sim session alive (liveness lease).","description":"The dashboard POSTs this ~every 10s while it is actively watching an Auto run. The runner stops the run gracefully if no heartbeat arrives within its grace window, so a closed/abandoned tab can't keep driving the gateway. Idempotent; returns `{ running: false }` once the session has ended. MNE-782.","tags":["Dojo"],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Heartbeat recorded (or no-op when the session is not running).","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"running":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/sim/{session_id}/stop":{"post":{"operationId":"stopSimSession","summary":"Abort a running Dojo sim session.","description":"Stops the runner loop and marks the session aborted. Idempotent. MNE-531.","tags":["Dojo"],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Session stopped.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/sim/{session_id}/stream":{"get":{"operationId":"streamSimEvents","summary":"Server-Sent Events stream of the Dojo sparring narrative.","description":"Returns a `text/event-stream` connection emitting the ordered `dojo_sim_events` for a session, one `sim_event` frame per row in `id` order. Per-connection cap of 5 minutes; clients reconnect with `Last-Event-ID` (the last seen event `id`) or `?since=<id>` to resume. Defaults to replaying from the start so a dashboard opening mid-sim sees the full narrative. MNE-517 §2 / MNE-520.","tags":["Dojo"],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"since","in":"query","required":false,"schema":{"type":"integer","minimum":0},"description":"Event-id cursor; omit to replay from the start of the session."},{"name":"Last-Event-ID","in":"header","required":false,"schema":{"type":"integer","minimum":0},"description":"SSE reconnect convention; takes precedence over `since` when both are present."}],"responses":{"200":{"description":"SSE stream (`text/event-stream`). Each frame is `event: sim_event\\nid: <id>\\ndata: {...}\\n\\n`.","content":{"text/event-stream":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/smith/config/{scenario}":{"get":{"operationId":"getSmithConfig","summary":"Get the per-scenario Agent Smith sparring config (admin console).","description":"Returns the stored per-scenario sparring config (objective, strategic frame, technique toolbox, reward function, evolution knobs, attacker substrate). When no row exists yet, returns the defaults merged with `scenario_id` so the editor always renders a complete form. Admin-only. MNE-819.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"scenario","in":"path","required":true,"schema":{"type":"string"},"description":"dojo_scenarios.id the config applies to."}],"responses":{"200":{"description":"The stored config, or the defaults when none exists yet.","content":{"application/json":{"schema":{"type":"object","required":["scenario_id","objective","strategic_frame","technique_toolbox","reward_function","evolution","substrate"],"properties":{"scenario_id":{"type":"string"},"objective":{"type":"string","description":"Free-form attacker objective."},"strategic_frame":{"type":"string"},"technique_toolbox":{"type":"array","items":{"type":"string"},"description":"Technique slugs/ids the attacker may draw on."},"reward_function":{"type":"object","required":["breach","near_miss","refused","novelty_bonus"],"properties":{"breach":{"type":"number"},"near_miss":{"type":"number"},"refused":{"type":"number"},"novelty_bonus":{"type":"number"}}},"evolution":{"type":"object","required":["cadence","novelty_gate"],"properties":{"cadence":{"type":"string","description":"Free-form cadence label."},"novelty_gate":{"type":"number","minimum":0,"maximum":1,"description":"Min novelty [0,1] a candidate must clear to enter the archive."}}},"substrate":{"type":"object","required":["provider","model"],"properties":{"provider":{"type":"string","enum":["anthropic","openai","google"]},"model":{"type":"string"}}},"updated_at":{"type":["string","null"],"format":"date-time"},"updated_by":{"type":["string","null"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"putSmithConfig","summary":"Upsert the per-scenario Agent Smith sparring config (admin console).","description":"Idempotently upserts the per-scenario sparring config keyed by `scenario_id`. Validates the structured blocks (substrate.provider ∈ providers, evolution.novelty_gate ∈ [0,1], technique_toolbox is string[], reward_function values finite). `updated_by`/`updated_at` are SERVER-set from the principal — the client's values are ignored. Returns the stored row. Admin-only. MNE-819.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"scenario","in":"path","required":true,"schema":{"type":"string"},"description":"dojo_scenarios.id the config applies to."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Partial config; omitted blocks fall back to the defaults. Any updated_by/updated_at sent is ignored (server-set).","properties":{"objective":{"type":"string"},"strategic_frame":{"type":"string"},"technique_toolbox":{"type":"array","items":{"type":"string"}},"reward_function":{"type":"object","properties":{"breach":{"type":"number"},"near_miss":{"type":"number"},"refused":{"type":"number"},"novelty_bonus":{"type":"number"}}},"evolution":{"type":"object","properties":{"cadence":{"type":"string"},"novelty_gate":{"type":"number","minimum":0,"maximum":1}}},"substrate":{"type":"object","properties":{"provider":{"type":"string","enum":["anthropic","openai","google"]},"model":{"type":"string"}}}}}}}},"responses":{"200":{"description":"The stored config.","content":{"application/json":{"schema":{"type":"object","required":["scenario_id","objective","strategic_frame","technique_toolbox","reward_function","evolution","substrate"],"properties":{"scenario_id":{"type":"string"},"objective":{"type":"string","description":"Free-form attacker objective."},"strategic_frame":{"type":"string"},"technique_toolbox":{"type":"array","items":{"type":"string"},"description":"Technique slugs/ids the attacker may draw on."},"reward_function":{"type":"object","required":["breach","near_miss","refused","novelty_bonus"],"properties":{"breach":{"type":"number"},"near_miss":{"type":"number"},"refused":{"type":"number"},"novelty_bonus":{"type":"number"}}},"evolution":{"type":"object","required":["cadence","novelty_gate"],"properties":{"cadence":{"type":"string","description":"Free-form cadence label."},"novelty_gate":{"type":"number","minimum":0,"maximum":1,"description":"Min novelty [0,1] a candidate must clear to enter the archive."}}},"substrate":{"type":"object","required":["provider","model"],"properties":{"provider":{"type":"string","enum":["anthropic","openai","google"]},"model":{"type":"string"}}},"updated_at":{"type":["string","null"],"format":"date-time"},"updated_by":{"type":["string","null"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/smith/coverage":{"get":{"operationId":"getSmithCoverage","summary":"Agent Smith coverage grid (admin console).","description":"Returns the full 5×2 (tactic × surface) coverage grid for the /admin/agent-smith Coverage heatmap: per-cell technique count, stable count, weighted mean attack-success-rate (asr), and a derived strength signal. `asr` is null when a cell has no telemetry yet (honest — no fabricated 0.0). `?scenario=` scopes the metric roll-up to one scenario; absent → the global view. Admin-only. MNE-813.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"scenario","in":"query","required":false,"schema":{"type":"string"},"description":"Scope the metric roll-up to one scenario slug. Absent → global."}],"responses":{"200":{"description":"The coverage grid.","content":{"application/json":{"schema":{"type":"object","required":["scenario","cells"],"properties":{"scenario":{"type":["string","null"]},"cells":{"type":"array","items":{"type":"object","required":["tactic","tactic_order","target_surface","technique_count","stable_count","asr","strength","weak"],"properties":{"tactic":{"type":"string","enum":["pretext","authority-spoof","injection","rationalized-destruction","exfiltration"]},"tactic_order":{"type":"integer"},"target_surface":{"type":"string","enum":["read","write"]},"technique_count":{"type":"integer"},"stable_count":{"type":"integer"},"asr":{"type":["number","null"]},"strength":{"type":"number"},"weak":{"type":"boolean"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/smith/evolutions":{"get":{"operationId":"getSmithEvolutions","summary":"Agent Smith arms-race co-evolution timeline (briefing).","description":"Returns the red/blue arms-race timeline for one scenario (`?scenario=` required): red Agent Smith evolutions (QD archive cells, oldest first) interleaved with the blue AEGIS counters that neutralised them, stable-sorted by timestamp. A red evolution is flagged `countered` once a later AEGIS edge lands against it. Briefing-class read, all authenticated users (NOT admin-only). MNE-818.","tags":["Dojo"],"parameters":[{"name":"scenario","in":"query","required":true,"schema":{"type":"string"},"description":"The scenario slug to build the timeline for."}],"responses":{"200":{"description":"The interleaved red/blue arms-race timeline.","content":{"application/json":{"schema":{"type":"object","required":["scenario","events"],"properties":{"scenario":{"type":"string"},"events":{"type":"array","items":{"type":"object","required":["side","ts"],"properties":{"side":{"type":"string","enum":["smith","aegis"],"description":"smith = a red attacker evolution; aegis = a blue defensive counter."},"ts":{"type":"string","description":"ISO timestamp the event landed."},"evo_version":{"type":"integer"},"technique_id":{"type":"string"},"name":{"type":"string"},"strategy":{"type":"string"},"tactic":{"type":"string","enum":["pretext","authority-spoof","injection","rationalized-destruction","exfiltration"]},"triggering_verdict":{"type":["string","null"],"enum":["held","caught","leak","contagion","bent",null]},"countered":{"type":"boolean"},"countered_by":{"type":"string"},"patch_id":{"type":"string"},"counters_technique_id":{"type":"string"},"inferred":{"type":"boolean","description":"Whether the counter is telemetry-inferred (not a hand-verified causal link)."}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/smith/live-evo":{"get":{"operationId":"getSmithLiveEvo","summary":"Agent Smith live evolution generation (admin console).","description":"Returns the live Agent-Smith evolution generation for the /admin/agent-smith Overview header: `max_evo` = max(evo_version) across ALL QD archive cells, and `by_scenario` = per-scenario max(evo_version) (scenario-sorted). Fixes the Overview reading a hardcoded 'Evo 0'. Fail-soft → { max_evo: 0, by_scenario: [] } on a control-plane outage (honest 'nothing measured', never fabricated). Admin-only. MNE-1309.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"The global + per-scenario live evolution generation.","content":{"application/json":{"schema":{"type":"object","required":["max_evo","by_scenario"],"properties":{"max_evo":{"type":"integer","description":"Max evo_version across every archive cell (0 when none)."},"by_scenario":{"type":"array","items":{"type":"object","required":["scenario","evo"],"properties":{"scenario":{"type":"string"},"evo":{"type":"integer"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/smith/profile":{"get":{"operationId":"getSmithProfile","summary":"Agent Smith matchup profile (Evo badge).","description":"The light, customer-facing matchup profile of Agent Smith for one scenario (`?scenario=` required): the live evolution generation (max archive-cell `evo_version`), the populated cell count, and the top measured confidence promoted from this scenario. Backs the matchup `· Evo N` badge. Deliberately exposes NO attack tradecraft (unlike `/smith/evolutions`). Short-cached. All authenticated users. MNE-953.","tags":["Dojo"],"parameters":[{"name":"scenario","in":"query","required":true,"schema":{"type":"string"},"description":"The scenario slug to read the profile for."}],"responses":{"200":{"description":"The scenario's Agent Smith matchup profile.","content":{"application/json":{"schema":{"type":"object","required":["scenario","evo","technique_count","top_confidence"],"properties":{"scenario":{"type":"string"},"evo":{"type":"integer","description":"Max archive-cell evo_version (0 if none)."},"technique_count":{"type":"integer"},"top_confidence":{"type":"number","nullable":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/smith/promotion-runs":{"get":{"operationId":"getSmithPromotionRuns","summary":"Agent Smith promotion-run audit feed (admin console).","description":"Returns the raw promotion-gate audit trail (newest first) for the /admin/agent-smith Promotion-runs table: one row per candidate evaluation with the gate's per-check verdicts (novelty / efficacy(ci_pass) / scope) plus the measured efficacy, confidence, containment, the range breaches/trials, and whether it promoted (and to which technique). tactic/surface/cell_key/evo_version are flattened from the candidate; the raw attack prompt is NOT surfaced. `?scenario=` filters; `?limit=` (default 50, max 200) pages. Fail-soft → empty runs on a control-plane outage. Admin-only. MNE-1314.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"scenario","in":"query","required":false,"schema":{"type":"string"},"description":"Filter to one scenario slug. Absent → all scenarios."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"description":"Page size, default 50, clamped to 200."}],"responses":{"200":{"description":"The flattened promotion-run audit feed.","content":{"application/json":{"schema":{"type":"object","required":["runs"],"properties":{"runs":{"type":"array","items":{"type":"object","required":["id","novelty_pass","ci_pass","scope_pass","promoted"],"properties":{"id":{"type":"string"},"scenario_id":{"type":["string","null"]},"tactic":{"type":["string","null"]},"surface":{"type":["string","null"]},"cell_key":{"type":["string","null"]},"evo_version":{"type":["integer","null"]},"novelty_pass":{"type":"boolean"},"novelty_score":{"type":["number","null"]},"breaches":{"type":["integer","null"],"description":"Range breaches (the repurposed reproductions count)."},"trials":{"type":["integer","null"]},"ci_pass":{"type":"boolean","description":"Efficacy gate passed (post-MNE-951 meaning)."},"scope_pass":{"type":"boolean"},"efficacy":{"type":["number","null"]},"confidence":{"type":["number","null"]},"containment_rate":{"type":["number","null"]},"promoted":{"type":"boolean"},"technique_id":{"type":["string","null"]},"created_at":{"type":["string","null"]}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/smith/resistance":{"get":{"operationId":"getSmithResistance","summary":"Agent Smith per-scenario resistance trend (admin console).","description":"Returns a daily breach-vs-held resistance time-series for one scenario (how well agents withstood Agent Smith over the window), derived from dojo_sim_events: attempts = Smith attack turns, breached = landed breaches, held = attempts − breached, resistance = held/attempts. `?scenario=` is required; `?days=` (default 30, max 365) bounds the window. `source` is the table the series came from, or \"unavailable\" on a fail-soft empty (no fabricated numbers). Admin-only. MNE-1313.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"scenario","in":"query","required":true,"schema":{"type":"string"},"description":"dojo_scenarios.id to chart resistance for."},{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":365,"default":30},"description":"Look-back window in days, default 30, clamped to 365."}],"responses":{"200":{"description":"The daily resistance series (possibly empty).","content":{"application/json":{"schema":{"type":"object","required":["scenario","source","buckets"],"properties":{"scenario":{"type":"string"},"source":{"type":"string","description":"Source table, or \"unavailable\" on a fail-soft empty."},"buckets":{"type":"array","items":{"type":"object","required":["date","attempts","held","breached","resistance"],"properties":{"date":{"type":"string","description":"UTC day, YYYY-MM-DD."},"attempts":{"type":"integer"},"held":{"type":"integer"},"breached":{"type":"integer"},"resistance":{"type":"number","description":"held / attempts, in [0,1]."}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/smith/review-queue":{"get":{"operationId":"getSmithReviewQueue","summary":"List Agent Smith review-queue candidates with provenance (admin console).","description":"Returns every experimental candidate (QD-evolved + human-as-smith harvested) joined with its provenance — the latest promotion-gate run's novelty_score + CI-replay (k of N), and the real captured breach example. Provenance fields are null when nothing is recorded (honesty contract — no fabricated provenance). Best-effort harvests freshly-sparred human breaches first. Admin-only. MNE-817.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"The experimental candidates and their provenance.","content":{"application/json":{"schema":{"type":"object","required":["items","count"],"properties":{"count":{"type":"integer"},"items":{"type":"array","items":{"allOf":[{"type":"object","required":["id","slug","name","tactic","tactic_order","target_surface","status"],"properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"tactic":{"type":"string","enum":["pretext","authority-spoof","injection","rationalized-destruction","exfiltration"]},"tactic_order":{"type":"integer","description":"Ladder-tier ordering (1..5)."},"threat_type":{"type":"string"},"target_surface":{"type":"string","enum":["read","write"],"description":"read = leak, write = destructive."},"status":{"type":"string","enum":["experimental","test","stable","deprecated","retired","rejected"]},"severity":{"type":"string","enum":["low","medium","high","critical"]},"origin":{"type":"string","enum":["seed","evolved","human-as-smith"]},"evo_version":{"type":"integer"},"atlas_tags":{"type":"array","items":{"type":"string"}},"owasp_tags":{"type":"array","items":{"type":"string"}},"modified":{"type":"string"},"confidence":{"type":["number","null"],"description":"Wilson lower-bound confidence of the measured efficacy; null when unmeasured."},"efficacy":{"type":["number","null"],"description":"Raw measured range breach rate (breaches/trials); null when unmeasured."},"efficacy_trials":{"type":["integer","null"],"description":"Range trials behind confidence/efficacy; null when unmeasured."}}},{"type":"object","required":["novelty_score","ci_replay","example"],"properties":{"novelty_score":{"type":["number","null"],"description":"Promotion-gate novelty [0,1], or null when no run exists."},"ci_replay":{"type":["object","null"],"required":["k","n","at"],"description":"CI-replay reproductions over trials, or null.","properties":{"k":{"type":"integer","description":"Reproductions."},"n":{"type":"integer","description":"Trials."},"at":{"type":["string","null"],"format":"date-time"}}},"example":{"type":["object","null"],"required":["prompt","verdict"],"properties":{"sessionId":{"type":"string"},"agentId":{"type":"string"},"scenario":{"type":"string"},"prompt":{"type":"string","description":"The real attacker prompt."},"agentExcerpt":{"type":"string"},"verdict":{"type":"string","enum":["held","caught","leak","contagion","bent"]},"ts":{"type":"string"}}}}}]}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/smith/review/{id}/promote":{"post":{"operationId":"promoteSmithTechnique","summary":"Promote (or merge) an Agent Smith review candidate (admin console).","description":"Moves an experimental candidate to `test` or `stable`, optionally renaming/retagging it. When `merge_into` is set the candidate is a DUPLICATE: it is deprecated and a `supersedes` edge (candidate → canonical) is recorded instead of being promoted. 400 when `to_status` is missing/invalid. Admin-only. MNE-817.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The candidate technique id."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to_status"],"properties":{"to_status":{"type":"string","enum":["test","stable"],"description":"The terminal status to promote the candidate to."},"name":{"type":"string","description":"Optional rename."},"tactic":{"type":"string","enum":["pretext","authority-spoof","injection","rationalized-destruction","exfiltration"],"description":"Optional re-tactic."},"atlas_tags":{"type":"array","items":{"type":"string"}},"owasp_tags":{"type":"array","items":{"type":"string"}},"merge_into":{"type":"string","description":"When set, the candidate is a duplicate of this canonical technique id: deprecate + record a supersedes edge instead of promoting."}}}}}},"responses":{"200":{"description":"The candidate's new status (promoted, or deprecated when merged).","content":{"application/json":{"schema":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string"},"status":{"type":"string","enum":["experimental","test","stable","deprecated","retired","rejected"]},"merged_into":{"type":"string","description":"The canonical technique id, present only on a merge."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/smith/review/{id}/reject":{"post":{"operationId":"rejectSmithTechnique","summary":"Reject an Agent Smith review candidate with a reason (admin console).","description":"Sets the candidate's status to `rejected` and stores the required reason. 400 when the reason is missing or empty. Admin-only. MNE-817.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The candidate technique id."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reason"],"properties":{"reason":{"type":"string","minLength":1,"description":"Why the candidate was rejected (required, non-empty)."}}}}}},"responses":{"200":{"description":"The candidate's rejected status.","content":{"application/json":{"schema":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string"},"status":{"type":"string","enum":["rejected"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/smith/techniques":{"get":{"operationId":"listSmithTechniques","summary":"List Agent Smith catalog techniques (admin console).","description":"Returns the global Agent Smith technique catalog as faceted summary rows for the /admin/agent-smith Library tab. Supports eq. filters on tactic, threat_type, target_surface, status, severity, and origin. `tactic_order` is server-computed from the ladder-tier ordering. Admin-only (Mnemom staff / org owner-admin) — internal red-team tradecraft. MNE-813.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"tactic","in":"query","required":false,"schema":{"type":"string","enum":["pretext","authority-spoof","injection","rationalized-destruction","exfiltration"]},"description":"Filter by escalation tactic."},{"name":"threat_type","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by canonical threat type."},{"name":"target_surface","in":"query","required":false,"schema":{"type":"string","enum":["read","write"]},"description":"Filter by attack surface (read = leak, write = destructive)."},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["experimental","test","stable","deprecated","retired","rejected"]},"description":"Filter by lifecycle status."},{"name":"severity","in":"query","required":false,"schema":{"type":"string","enum":["low","medium","high","critical"]},"description":"Filter by severity."},{"name":"origin","in":"query","required":false,"schema":{"type":"string","enum":["seed","evolved","human-as-smith"]},"description":"Filter by how the technique entered the catalog."}],"responses":{"200":{"description":"The faceted technique summary list.","content":{"application/json":{"schema":{"type":"object","required":["techniques"],"properties":{"techniques":{"type":"array","items":{"type":"object","required":["id","slug","name","tactic","tactic_order","target_surface","status"],"properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"tactic":{"type":"string","enum":["pretext","authority-spoof","injection","rationalized-destruction","exfiltration"]},"tactic_order":{"type":"integer","description":"Ladder-tier ordering (1..5)."},"threat_type":{"type":"string"},"target_surface":{"type":"string","enum":["read","write"],"description":"read = leak, write = destructive."},"status":{"type":"string","enum":["experimental","test","stable","deprecated","retired","rejected"]},"severity":{"type":"string","enum":["low","medium","high","critical"]},"origin":{"type":"string","enum":["seed","evolved","human-as-smith"]},"evo_version":{"type":"integer"},"atlas_tags":{"type":"array","items":{"type":"string"}},"owasp_tags":{"type":"array","items":{"type":"string"}},"modified":{"type":"string"},"confidence":{"type":["number","null"],"description":"Wilson lower-bound confidence of the measured efficacy; null when unmeasured."},"efficacy":{"type":["number","null"],"description":"Raw measured range breach rate (breaches/trials); null when unmeasured."},"efficacy_trials":{"type":["integer","null"],"description":"Range trials behind confidence/efficacy; null when unmeasured."}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/smith/techniques/{id}":{"get":{"operationId":"getSmithTechnique","summary":"Get one Agent Smith technique by id or slug (admin console).","description":"Returns one catalog technique's full detail — description, strategy, templates, real observed examples, known defenses, preconditions, ATLAS/OWASP tags, lineage, provenance — for the /admin/agent-smith Library Sigma card. Resolves by id OR slug. Admin-only. MNE-813.","tags":["Dojo"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Technique id (e.g. 'SMT-0001') or slug."}],"responses":{"200":{"description":"The technique detail.","content":{"application/json":{"schema":{"allOf":[{"type":"object","required":["id","slug","name","tactic","tactic_order","target_surface","status"],"properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"tactic":{"type":"string","enum":["pretext","authority-spoof","injection","rationalized-destruction","exfiltration"]},"tactic_order":{"type":"integer","description":"Ladder-tier ordering (1..5)."},"threat_type":{"type":"string"},"target_surface":{"type":"string","enum":["read","write"],"description":"read = leak, write = destructive."},"status":{"type":"string","enum":["experimental","test","stable","deprecated","retired","rejected"]},"severity":{"type":"string","enum":["low","medium","high","critical"]},"origin":{"type":"string","enum":["seed","evolved","human-as-smith"]},"evo_version":{"type":"integer"},"atlas_tags":{"type":"array","items":{"type":"string"}},"owasp_tags":{"type":"array","items":{"type":"string"}},"modified":{"type":"string"},"confidence":{"type":["number","null"],"description":"Wilson lower-bound confidence of the measured efficacy; null when unmeasured."},"efficacy":{"type":["number","null"],"description":"Raw measured range breach rate (breaches/trials); null when unmeasured."},"efficacy_trials":{"type":["integer","null"],"description":"Range trials behind confidence/efficacy; null when unmeasured."}}},{"type":"object","required":["description","strategy"],"properties":{"description":{"type":"string"},"strategy":{"type":"string"},"templates":{"type":"array","items":{"type":"string"}},"examples":{"type":"array","items":{"type":["object","null"],"required":["prompt","verdict"],"properties":{"sessionId":{"type":"string"},"agentId":{"type":"string"},"scenario":{"type":"string"},"prompt":{"type":"string","description":"The real attacker prompt."},"agentExcerpt":{"type":"string"},"verdict":{"type":"string","enum":["held","caught","leak","contagion","bent"]},"ts":{"type":"string"}}}},"known_defenses":{"type":"array","items":{"type":"string"}},"preconditions":{"type":"array","items":{"type":"string"}},"references":{"type":"array","items":{"type":"string"}},"first_seen":{"type":"string"},"author":{"type":"string"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/ssm/{agent_id}":{"get":{"operationId":"getSSM","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"summary":"Get traces with semantic similarity scores","tags":["Integrity"],"parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"minimum":1,"maximum":100}}],"responses":{"200":{"description":"Traces with similarity scores","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"trace_count":{"type":"integer"},"traces":{"type":"array","items":{"type":"object"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/ssm/{agent_id}/timeline":{"get":{"operationId":"getSSMTimeline","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"summary":"Get similarity timeline data","tags":["Integrity"],"parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","schema":{"type":"integer","default":7,"minimum":1,"maximum":30}}],"responses":{"200":{"description":"Similarity timeline","content":{"application/json":{"schema":{"type":"object","properties":{"agent_id":{"type":"string"},"days":{"type":"integer"},"timeline":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","format":"date"},"trace_count":{"type":"integer"},"avg_similarity":{"type":"number"},"values_used":{"type":"object","additionalProperties":{"type":"integer"}}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams":{"post":{"operationId":"createTeam","summary":"Create a team","description":"Create a new team with at least 2 agent members. Team names must be unique within the organization.","tags":["Teams"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["org_id","name","agent_ids"],"properties":{"org_id":{"type":"string","description":"Organization that owns this team"},"name":{"type":"string","maxLength":100,"description":"Display name"},"description":{"type":"string","description":"Optional description"},"agent_ids":{"type":"array","items":{"type":"string"},"minItems":2,"maxItems":50,"description":"Agent IDs to add as initial members"},"metadata":{"type":"object","additionalProperties":true,"description":"Freeform metadata"}}}}}},"responses":{"201":{"description":"Team created","content":{"application/json":{"schema":{"type":"object","properties":{"team":{"$ref":"#/components/schemas/Team"},"members":{"type":"array","items":{"$ref":"#/components/schemas/TeamMember"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/teams/fault-lines":{"post":{"operationId":"analyzeTeamFaultLines","summary":"Analyze team fault lines","description":"Analyze alignment fault lines across a team of agents. Identifies capabilities, values, or constraints that some agents declare but others miss, creating potential alignment gaps. Returns a fleet-wide score with individual fault line details and resolution hints.","tags":["Intelligence"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["team_id"],"properties":{"team_id":{"type":"string","description":"Team identifier to analyze"},"agent_ids":{"type":"array","items":{"type":"string"},"description":"Optional subset of agent IDs to analyze. If omitted, all team members are analyzed."},"dimensions":{"type":"array","items":{"type":"string","enum":["capabilities","values","constraints","tools","policies"]},"description":"Dimensions to analyze for fault lines"}}}}}},"responses":{"200":{"description":"Fault line analysis result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FaultLineAnalysis"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/forecast":{"post":{"operationId":"forecastTeamRisks","summary":"Forecast team risks","description":"Forecast potential risks and failure modes for a team based on current alignment state, historical trends, and known fault lines. Returns ranked failure modes with probability estimates, impact assessments, and mitigation suggestions.","tags":["Intelligence"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["fault_line_analysis_id"],"properties":{"fault_line_analysis_id":{"type":"string","description":"Identifier of a prior fault-line analysis to forecast against. Required."},"team_id":{"type":"string","description":"Optional team identifier. When provided without an explicit `task_context`, the team name is used to derive one."},"task_context":{"type":"object","additionalProperties":true,"description":"Task the forecast is scoped to. Required unless derivable from `team_id`.","required":["description","action_type"],"properties":{"description":{"type":"string"},"action_type":{"type":"string"},"tools":{"type":"array","items":{"type":"string"}},"duration_hours":{"type":"number"}}},"risk_tolerance":{"type":"string","enum":["conservative","moderate","aggressive"],"default":"moderate","description":"Risk tolerance for the forecast. Defaults to `moderate`."}}}}}},"responses":{"200":{"description":"Risk forecast result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RiskForecast"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/recommend-policy":{"post":{"operationId":"recommendTeamPolicy","summary":"Generate policy recommendation","description":"Generate a recommended CLPI policy for a team based on current agent capabilities, alignment cards, historical violations, and known fault lines. The recommendation aims to close coverage gaps while minimizing disruption to existing workflows.","tags":["Intelligence"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["forecast_id"],"properties":{"forecast_id":{"type":"string","description":"Identifier of the risk forecast to base the recommendation on. Required."},"constraints":{"type":"object","additionalProperties":true,"description":"Optional recommendation constraints.","properties":{"enforcement_mode":{"type":"string","enum":["warn","enforce"]},"allow_unmapped_tools":{"type":"boolean"},"preserve_existing_policy":{"type":"boolean"}}}}}}}},"responses":{"200":{"description":"Policy recommendation","content":{"application/json":{"schema":{"type":"object","properties":{"recommended_policy":{"$ref":"#/components/schemas/Policy"},"rationale":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"reason":{"type":"string"},"confidence":{"type":"number","minimum":0,"maximum":1}}}},"expected_coverage":{"type":"number","minimum":0,"maximum":1},"fault_lines_addressed":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/reputation/batch":{"post":{"operationId":"batchTeamReputation","x-proxied":"REPUTATION_SERVICE","summary":"Batch team-reputation lookup (auth required)","tags":["Team Reputation"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["team_ids"],"properties":{"team_ids":{"type":"array","items":{"type":"string"},"maxItems":50}}}}}},"responses":{"200":{"description":"Scores.","content":{"application/json":{"schema":{"type":"object","properties":{"scores":{"type":"array","items":{"$ref":"#/components/schemas/TeamReputationScore"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/reputation/compare":{"get":{"operationId":"compareTeamReputation","x-proxied":"REPUTATION_SERVICE","summary":"Compare 2–10 teams' reputation scores","tags":["Team Reputation"],"security":[],"parameters":[{"name":"ids","in":"query","required":true,"schema":{"type":"string"},"description":"Comma-separated team ids (2–10)."}],"responses":{"200":{"description":"Comparison.","content":{"application/json":{"schema":{"type":"object","properties":{"teams":{"type":"array","items":{"$ref":"#/components/schemas/TeamReputationScore"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/reputation/search":{"get":{"operationId":"searchTeamReputationDirectory","x-proxied":"REPUTATION_SERVICE","summary":"Search the public team-reputation directory","tags":["Team Reputation"],"security":[],"parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string"}},{"name":"grade","in":"query","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"Directory page.","content":{"application/json":{"schema":{"type":"object","properties":{"teams":{"type":"array","items":{"$ref":"#/components/schemas/TeamReputationScore"}},"total":{"type":"integer"},"page":{"type":"integer"},"per_page":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/{team_id}":{"get":{"operationId":"getTeam","summary":"Get team by ID","description":"Retrieve a team and its current members.","tags":["Teams"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"200":{"description":"Team details with members","content":{"application/json":{"schema":{"type":"object","properties":{"team":{"$ref":"#/components/schemas/Team"},"members":{"type":"array","items":{"$ref":"#/components/schemas/TeamMember"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"patch":{"operationId":"updateTeam","summary":"Update team","description":"Update a team's name, description, or metadata.","tags":["Teams"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"description":"Display name"},"description":{"type":["string","null"],"description":"Optional description"},"metadata":{"type":"object","additionalProperties":true,"description":"Freeform metadata"}}}}}},"responses":{"200":{"description":"Updated team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Team"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"delete":{"operationId":"archiveTeam","summary":"Archive team","description":"Archive a team. Archived teams are soft-deleted and can be listed with status=archived.","tags":["Teams"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"200":{"description":"Team archived","content":{"application/json":{"schema":{"type":"object","properties":{"archived":{"type":"boolean"},"team_id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/teams/{team_id}/admins":{"get":{"operationId":"listTeamAdmins","summary":"List team-admin grants","description":"Returns users with team-admin role on this team.","tags":["Teams"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"200":{"description":"Team-admin grants.","content":{"application/json":{"schema":{"type":"object","required":["admins"],"properties":{"admins":{"type":"array","items":{"$ref":"#/components/schemas/TeamAdmin"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"post":{"operationId":"grantTeamAdmin","summary":"Grant team-admin role to a user","description":"Authorized: org_admin / org_owner.","tags":["Teams"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["user_id"],"properties":{"user_id":{"type":"string","format":"uuid","description":"UUID of the user to grant the team-admin role to (must be a member of the team's org)."}}}}}},"responses":{"201":{"description":"Grant created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamAdmin"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/{team_id}/admins/{user_id}":{"delete":{"operationId":"revokeTeamAdmin","summary":"Revoke a team-admin grant","description":"Authorized: org_admin / org_owner.","tags":["Teams"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the user whose team-admin grant to revoke."}],"responses":{"200":{"description":"Revoked (or idempotent no-op if already revoked).","content":{"application/json":{"schema":{"type":"object","required":["team_id","user_id","revoked"],"properties":{"team_id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"revoked":{"type":"boolean","description":"`true` when the grant was revoked by this request; `false` on an idempotent no-op."},"revoked_at":{"type":"string","format":"date-time","description":"Timestamp of revocation. Present only when `revoked: true`."},"revoked_by":{"type":"string","format":"uuid","description":"Actor who revoked the grant. Present only when `revoked: true`."},"idempotent_noop":{"type":"boolean","description":"`true` when there was no active grant to revoke. `revoked` is `false` in this case."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/{team_id}/alignment-template":{"get":{"operationId":"getTeamAlignmentTemplateLegacy","summary":"DEPRECATED — use GET /v1/alignment/team/{team_id}.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/alignment/team/{team_id}`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Card Templates"],"security":[],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"putTeamAlignmentTemplateLegacy","summary":"DEPRECATED — use PUT /v1/alignment/team/{team_id}.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/alignment/team/{team_id}`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Card Templates"],"security":[],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"delete":{"operationId":"deleteTeamAlignmentTemplateLegacy","summary":"DEPRECATED — use DELETE /v1/alignment/team/{team_id}.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/alignment/team/{team_id}`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Card Templates"],"security":[],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/{team_id}/alignment-template/preview-compose":{"post":{"operationId":"postTeamAlignmentTemplatePreviewComposeLegacy","summary":"DEPRECATED — use POST /v1/alignment/team/{team_id}/preview-compose.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/alignment/team/{team_id}/preview-compose`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Card Templates"],"security":[],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/{team_id}/avatar":{"put":{"operationId":"putTeamAvatar","summary":"Upload team avatar","description":"Replace a team's avatar image. Requires the authenticated principal to hold `owner` or `admin` role on the team's parent org.","tags":["Teams"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"Avatar image. Validated for MIME type and size before upload."}}}}}},"responses":{"200":{"description":"Avatar uploaded; persistent URL returned","content":{"application/json":{"schema":{"type":"object","required":["avatar_url"],"properties":{"avatar_url":{"type":"string","format":"uri","description":"Public URL of the uploaded avatar (CDN-served).","example":"https://cdn.mnemom.ai/avatars/agents/mnm-7f3b9e2a/abc123.png"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"}}}},"/teams/{team_id}/badge.svg":{"get":{"operationId":"getTeamBadge","x-proxied":"REPUTATION_SERVICE","summary":"Get embeddable team reputation badge","description":"Public endpoint. Returns an SVG badge displaying the team's reputation score or grade. Returns a 'Not Rated' badge for unknown teams.","tags":["Team Reputation"],"security":[],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"variant","in":"query","schema":{"type":"string","enum":["score","grade","score_grade","score_trend","score_tier","compact"],"default":"grade"},"description":"Badge variant"},{"name":"style","in":"query","schema":{"type":"string","enum":["light","dark"],"default":"light"},"description":"Badge color scheme"}],"responses":{"200":{"description":"SVG badge image","headers":{"Cache-Control":{"schema":{"type":"string"},"description":"public, max-age=3600"}},"content":{"image/svg+xml":{"schema":{"type":"string"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/{team_id}/card":{"get":{"operationId":"getTeamCard","summary":"Get team alignment card","description":"Retrieve the active alignment card for a team, or null if no card is set.","tags":["Teams"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"200":{"description":"Team alignment card, or null card_json/card_source when no card is set","content":{"application/json":{"schema":{"type":"object","properties":{"card_id":{"type":"string"},"id":{"type":"string"},"team_id":{"type":"string"},"card_json":{"type":["object","null"]},"card_source":{"type":["string","null"],"enum":["manual","auto_derived","hybrid",null]},"issued_at":{"type":"string","format":"date-time"},"is_active":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"put":{"operationId":"setTeamCard","summary":"Set team alignment card","description":"Manually set an alignment card for a team. The card must include principal, values, autonomy_envelope, and audit_commitment sections.","tags":["Teams"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["principal","values","autonomy_envelope","audit_commitment"],"properties":{"principal":{"type":"object","description":"Principal section of the alignment card"},"values":{"type":"object","required":["declared"],"properties":{"declared":{"type":"array","items":{"type":"string"}}},"description":"Values section with declared value strings"},"autonomy_envelope":{"type":"object","description":"Autonomy envelope section"},"audit_commitment":{"type":"object","description":"Audit commitment section"}}}}}},"responses":{"200":{"description":"Card set","content":{"application/json":{"schema":{"type":"object","properties":{"card_id":{"type":"string"},"team_id":{"type":"string"},"card_source":{"type":"string","enum":["manual"]},"issued_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/teams/{team_id}/card/derive":{"post":{"operationId":"deriveTeamCard","summary":"Derive team alignment card from members","description":"Automatically derive a team alignment card from the individual cards of team members. Requires at least 2 members with active alignment cards.","tags":["Teams"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"200":{"description":"Derived card","content":{"application/json":{"schema":{"type":"object","properties":{"derived_card":{"type":"object"},"card_source":{"type":"string","enum":["auto_derived"]},"member_count":{"type":"integer"},"members_with_cards":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/teams/{team_id}/card/history":{"get":{"operationId":"getTeamCardHistory","summary":"Get team card history","description":"Retrieve the history of alignment cards for a team.","tags":["Teams"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"200":{"description":"Card history","content":{"application/json":{"schema":{"type":"object","properties":{"cards":{"type":"array","items":{"type":"object","properties":{"card_id":{"type":"string"},"card_source":{"type":"string","enum":["manual","auto_derived","hybrid"]},"issued_at":{"type":"string","format":"date-time"},"is_active":{"type":"boolean"}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/teams/{team_id}/coherence-history":{"get":{"operationId":"getTeamCoherenceHistory","summary":"Get governance-median coherence history for a team","description":"Internal service-to-service endpoint for the mnemom-reputation cron. Returns the governance-median coherence history for a team. Authentication is via the `X-Internal-Key` header validated against the `INTERNAL_API_KEY` server secret; this is not a standard security scheme, so `security` is empty and the header is declared as a required parameter.","tags":["Teams"],"security":[],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"X-Internal-Key","in":"header","required":true,"description":"Internal service-to-service shared secret. Must match the server's `INTERNAL_API_KEY` value.","schema":{"type":"string"}}],"responses":{"200":{"description":"Governance-median coherence history for the team.","content":{"application/json":{"schema":{"type":"object","required":["team_id","governance_median_history","note"],"additionalProperties":false,"properties":{"team_id":{"type":"string","description":"The team identifier echoed from the path."},"governance_median_history":{"type":"array","description":"Time-ordered samples of the governance-median coherence value for the team.","items":{"type":"object","required":["value","at"],"additionalProperties":false,"properties":{"value":{"type":"number","description":"Governance-median coherence value at the sample timestamp."},"at":{"type":"string","format":"date-time","description":"Sample timestamp (ISO-8601 UTC)."}}}},"note":{"type":"string","description":"Human-readable note describing the history payload (e.g., data-source caveats)."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/{team_id}/effective-posture":{"get":{"operationId":"getTeamEffectivePosture","summary":"Get the team's currently-effective composed posture","description":"Returns the alignment + protection composition currently in effect for the team (assigned posture's body merged with the team's templates and agent exemptions).","tags":["Postures"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"200":{"description":"Effective posture.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamEffectivePosture"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/{team_id}/governance/signals":{"get":{"operationId":"listTeamGovernanceSignals","summary":"List governance signals for a team","description":"Returns governance signals scoped to the given team. Authorized to any member of the team's org.","tags":["Governance"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"source","in":"query","required":false,"schema":{"$ref":"#/components/schemas/GovernanceSignalSource"},"description":"Filter by source detector."},{"name":"severity","in":"query","required":false,"schema":{"$ref":"#/components/schemas/GovernanceSignalSeverity"},"description":"Filter by severity."},{"name":"status","in":"query","required":false,"schema":{"$ref":"#/components/schemas/GovernanceSignalStatus"},"description":"Filter by workflow status."},{"name":"pattern_type","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by pattern_type within the source's taxonomy."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"description":"Maximum number of signals to return, most recent first (1–200, default 50)."}],"responses":{"200":{"description":"Governance signals listing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GovernanceSignalsListResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/{team_id}/members":{"post":{"operationId":"addTeamMembers","summary":"Add members to team","description":"Add one or more agents to a team. Teams have a maximum of 50 members.","tags":["Teams"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["agent_ids"],"properties":{"agent_ids":{"type":"array","items":{"type":"string"},"minItems":1,"description":"Agent IDs to add"}}}}}},"responses":{"200":{"description":"Members added","content":{"application/json":{"schema":{"type":"object","properties":{"added":{"type":"array","items":{"type":"string"}},"already_members":{"type":"array","items":{"type":"string"}},"members":{"type":"array","items":{"$ref":"#/components/schemas/TeamMember"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"get":{"operationId":"getTeamMembers","summary":"List a team's current members","description":"Returns the current roster of agents on a team, along with each agent's join timestamp and individual reputation score (when available).","tags":["Teams"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"200":{"description":"Team member list.","content":{"application/json":{"schema":{"type":"object","properties":{"team_id":{"type":"string"},"members":{"type":"array","items":{"$ref":"#/components/schemas/TeamMember"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/{team_id}/members/{agent_id}":{"delete":{"operationId":"removeTeamMember","summary":"Remove member from team","description":"Remove an agent from a team. Teams must retain a minimum of 2 members.","tags":["Teams"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"$ref":"#/components/parameters/AgentId"}],"responses":{"200":{"description":"Member removed","content":{"application/json":{"schema":{"type":"object","properties":{"removed":{"type":"boolean"},"agent_id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/teams/{team_id}/my-role":{"get":{"operationId":"getTeamMyRole","summary":"Get the caller's effective role on this team","description":"Returns the caller's role on this team for UI gating. Computed via the same logic as `requireTeamRole` (ADR-046) and `getTeamRole`. Values: `super_admin` (Mnemom staff cookie), `org_owner` / `org_admin` (when the caller has that role on the team's org), `team_admin` (an active `team_admin_grants` row for the caller), `org_member` / `org_viewer` / `org_auditor` (read-only org membership), or `null` (no role). Surfaces that don't load a template-sources envelope (team roster, identity card, admins tab) use this to gate edit affordances from the same single source of truth as the editors. See ADR-053.","tags":["Teams"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"200":{"description":"Caller's effective role on the team.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMyRoleResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/{team_id}/og-image":{"get":{"operationId":"getTeamReputationOgImage","x-proxied":"REPUTATION_SERVICE","summary":"Open Graph share-card image for a team","tags":["Team Reputation"],"security":[],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"200":{"description":"Share-card image.","content":{"image/png":{"schema":{"type":"string","format":"binary"}},"text/html":{"schema":{"type":"string"}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/{team_id}/protection-template":{"get":{"operationId":"getTeamProtectionTemplateLegacy","summary":"DEPRECATED — use GET /v1/protection/team/{team_id}.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/protection/team/{team_id}`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Card Templates"],"security":[],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"put":{"operationId":"putTeamProtectionTemplateLegacy","summary":"DEPRECATED — use PUT /v1/protection/team/{team_id}.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/protection/team/{team_id}`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Card Templates"],"security":[],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"delete":{"operationId":"deleteTeamProtectionTemplateLegacy","summary":"DEPRECATED — use DELETE /v1/protection/team/{team_id}.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/protection/team/{team_id}`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Card Templates"],"security":[],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/{team_id}/protection-template/preview-compose":{"post":{"operationId":"postTeamProtectionTemplatePreviewComposeLegacy","summary":"DEPRECATED — use POST /v1/protection/team/{team_id}/preview-compose.","description":"Permanently redirects (HTTP 308, RFC 7538) to `/v1/protection/team/{team_id}/preview-compose`. Method and body are preserved across the redirect. Sunset: `Fri, 15 Jan 2027 00:00:00 GMT` — after that the legacy path returns 410 Gone. See [docs.mnemom.ai/concepts/cards-as-resources](https://docs.mnemom.ai/concepts/cards-as-resources) for the canonical Resources × Scope × Verb URL surface (cards-as-primitive Phase 4 W1.2b).","deprecated":true,"tags":["Card Templates"],"security":[],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"308":{"$ref":"#/components/responses/PermanentRedirect"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/{team_id}/reputation":{"get":{"operationId":"getTeamReputation","x-proxied":"REPUTATION_SERVICE","summary":"Get team reputation score","description":"Retrieve the current reputation score for a team, including component breakdown and A2A trust extension.","tags":["Team Reputation"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"200":{"description":"Team reputation score","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamReputationScore"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/{team_id}/reputation/history":{"get":{"operationId":"getTeamReputationHistory","x-proxied":"REPUTATION_SERVICE","summary":"Get team reputation history","description":"Retrieve weekly reputation score snapshots for a team.","tags":["Team Reputation"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"200":{"description":"Reputation history snapshots","content":{"application/json":{"schema":{"type":"object","properties":{"snapshots":{"type":"array","items":{"$ref":"#/components/schemas/TeamReputationSnapshot"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/{team_id}/reputation/verify":{"get":{"operationId":"verifyTeamReputation","x-proxied":"REPUTATION_SERVICE","summary":"Verify team reputation cryptographically","description":"Public endpoint. Returns the team's reputation score with a cryptographic proof hash for independent verification.","tags":["Team Reputation"],"security":[],"parameters":[{"$ref":"#/components/parameters/TeamId"}],"responses":{"200":{"description":"Reputation with verification proof","content":{"application/json":{"schema":{"type":"object","properties":{"team_id":{"type":"string"},"score":{"type":"number"},"grade":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"verification":{"type":["object","null"],"properties":{"proof_hash":{"type":"string"},"computed_at":{"type":"string","format":"date-time"},"total_assessments":{"type":"integer"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/{team_id}/roster-history":{"get":{"operationId":"getTeamRosterHistory","summary":"Get team roster history","description":"Retrieve the history of member additions and removals for a team.","tags":["Teams"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Page number"},{"name":"per_page","in":"query","schema":{"type":"integer","default":50,"maximum":200},"description":"Results per page (max 200)"}],"responses":{"200":{"description":"Roster change history","content":{"application/json":{"schema":{"type":"object","properties":{"changes":{"type":"array","items":{"$ref":"#/components/schemas/TeamRosterChange"}},"total":{"type":"integer"},"page":{"type":"integer"},"per_page":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/teams/{team_id}/sideband-advisories":{"get":{"operationId":"listTeamSidebandAdvisories","summary":"List historical sideband advisories for a team (legacy)","description":"Sunsetting; see governance_signals.","tags":["Sideband"],"deprecated":true,"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","delivered","consumed","expired"]}}],"responses":{"200":{"description":"Sideband advisories listing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SidebandAdvisoryListResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/teams/{team_id}/sideband-coverage":{"get":{"operationId":"getTeamSidebandCoverage","summary":"Sideband finding coverage rollup for a team","description":"Per-source counts over a window. Operator-facing.","tags":["Sideband"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/TeamId"},{"name":"hours","in":"query","schema":{"type":"integer","minimum":1,"maximum":720,"default":24},"description":"Accepted for forward-compatibility but currently ignored: the handler aggregates a fixed 30-day window (see the `window_days` field in the response). A supplied value is validated (1–720) but does not change the window."}],"responses":{"200":{"description":"Coverage rollup.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SidebandCoverageReport"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/tools":{"get":{"operationId":"listTools","summary":"List registered tools","description":"Returns the active tools registry with optional filters. Reads accept any authenticated principal. Use `include_deprecated=true` to surface soft-deleted rows.","tags":["Tools"],"security":[],"parameters":[{"name":"class","in":"query","required":false,"schema":{"type":"string","enum":["read","internal_write","consequential_internal_write","consequential_external_write","comms_internal","comms_external","engineering_attestation","governance_write"]},"description":"Filter by action class."},{"name":"domain","in":"query","required":false,"schema":{"type":"string","enum":["financial","engineering","intelligence","growth","operations","governance","comms","identity","security"]},"description":"Filter by operational domain."},{"name":"source_connector","in":"query","required":false,"schema":{"type":"string","maxLength":128},"description":"Filter by source connector name."},{"name":"include_deprecated","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Include soft-deleted rows (deprecated_at IS NOT NULL)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Maximum rows to return; capped at 100."}],"responses":{"200":{"description":"Tools registry listing.","content":{"application/json":{"schema":{"type":"object","required":["data","count"],"properties":{"data":{"type":"array","items":{"type":"object","required":["name","class","domain","version","created_at","updated_at"],"properties":{"name":{"type":"string","pattern":"^([a-z][a-z0-9_]{1,127}|org:[a-z0-9-]{3,64}:[a-z][a-z0-9_]{1,127})$","description":"Globally unique tool name. Convention: `<connector>_<verb>_<noun>` (e.g. `campfire_create_chart_account`). Org-scoped tools use the reserved `org:<id>:` prefix."},"display_name":{"type":["string","null"]},"description":{"type":["string","null"]},"class":{"type":"string","enum":["read","internal_write","consequential_internal_write","consequential_external_write","comms_internal","comms_external","engineering_attestation","governance_write"],"description":"8-entry action class taxonomy per mnemom-contracts/tool-manifest/v1.yaml. V7 gateway hooks bind on this for class-scoped enforcement."},"domain":{"type":"string","enum":["financial","engineering","intelligence","growth","operations","governance","comms","identity","security"],"description":"9-entry domain taxonomy. Used by domain-scoped value declarations like policy_attentiveness(domain: financial)."},"schema":{"type":["object","null"],"description":"OpenAPI fragment / JSON Schema for the tool parameters. Populated when the tool is imported via OpenAPI spec."},"source_connector":{"type":["string","null"]},"deprecated_at":{"type":["string","null"],"format":"date-time"},"content_hash":{"type":["string","null"],"pattern":"^sha256:[a-f0-9]{64}$"},"version":{"type":"integer","minimum":1},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}},"count":{"type":"integer","minimum":0}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"}}},"post":{"operationId":"registerTool","summary":"Register a new tool","description":"Inserts a new tool row. Platform-admin only. Idempotency-Key is required. The composer sets content_hash + version=1; subsequent PATCH calls bump version only when content_hash changes.","tags":["Tools"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"Per-mutation idempotency key (RFC draft-ietf-httpapi-idempotency-key-header)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","class","domain"],"properties":{"name":{"type":"string","pattern":"^([a-z][a-z0-9_]{1,127}|org:[a-z0-9-]{3,64}:[a-z][a-z0-9_]{1,127})$","description":"Globally unique tool name. Convention: `<connector>_<verb>_<noun>` (e.g. `campfire_create_chart_account`). Org-scoped tools use the reserved `org:<id>:` prefix."},"class":{"type":"string","enum":["read","internal_write","consequential_internal_write","consequential_external_write","comms_internal","comms_external","engineering_attestation","governance_write"],"description":"8-entry action class taxonomy per mnemom-contracts/tool-manifest/v1.yaml. V7 gateway hooks bind on this for class-scoped enforcement."},"domain":{"type":"string","enum":["financial","engineering","intelligence","growth","operations","governance","comms","identity","security"],"description":"9-entry domain taxonomy. Used by domain-scoped value declarations like policy_attentiveness(domain: financial)."},"description":{"type":["string","null"]},"display_name":{"type":["string","null"]},"schema":{"type":["object","null"],"description":"OpenAPI fragment / JSON Schema for the tool parameters. Populated when the tool is imported via OpenAPI spec."},"source_connector":{"type":["string","null"]}}}}}},"responses":{"201":{"description":"Tool registered.","headers":{"ETag":{"schema":{"type":"string"},"description":"sha256:<64-hex> over the canonical tool definition."},"X-Tool-Version":{"schema":{"type":"string"},"description":"Monotonic version (starts at 1)."},"X-Mnemom-Schema":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["name","class","domain","version","created_at","updated_at"],"properties":{"name":{"type":"string","pattern":"^([a-z][a-z0-9_]{1,127}|org:[a-z0-9-]{3,64}:[a-z][a-z0-9_]{1,127})$","description":"Globally unique tool name. Convention: `<connector>_<verb>_<noun>` (e.g. `campfire_create_chart_account`). Org-scoped tools use the reserved `org:<id>:` prefix."},"display_name":{"type":["string","null"]},"description":{"type":["string","null"]},"class":{"type":"string","enum":["read","internal_write","consequential_internal_write","consequential_external_write","comms_internal","comms_external","engineering_attestation","governance_write"],"description":"8-entry action class taxonomy per mnemom-contracts/tool-manifest/v1.yaml. V7 gateway hooks bind on this for class-scoped enforcement."},"domain":{"type":"string","enum":["financial","engineering","intelligence","growth","operations","governance","comms","identity","security"],"description":"9-entry domain taxonomy. Used by domain-scoped value declarations like policy_attentiveness(domain: financial)."},"schema":{"type":["object","null"],"description":"OpenAPI fragment / JSON Schema for the tool parameters. Populated when the tool is imported via OpenAPI spec."},"source_connector":{"type":["string","null"]},"deprecated_at":{"type":["string","null"],"format":"date-time"},"content_hash":{"type":["string","null"],"pattern":"^sha256:[a-f0-9]{64}$"},"version":{"type":"integer","minimum":1},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/tools/import":{"post":{"operationId":"importTools","summary":"Preview an import of tool definitions from an OpenAPI spec or connector YAML manifest.","description":"Parses the spec, extracts tool definitions, and optionally calls the LLM to infer class+domain. **Never auto-commits** — the caller iterates the `imported[]` array and writes each tool individually via `POST /v1/tools`. Platform-admin only. SSRF-defended (localhost / link-local / RFC-1918 blocked).","tags":["tools"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"CookieAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["format","source"],"properties":{"format":{"type":"string","enum":["openapi","connector_yaml"]},"source":{"type":"string","enum":["inline","url"]},"content":{"type":"string","description":"Raw spec text. Required when `source=inline`."},"url":{"type":"string","description":"Public URL to fetch the spec. Required when `source=url`."},"infer_class_domain":{"type":"boolean","description":"When true (default), calls the LLM to infer class + domain per tool."}}}}}},"responses":{"200":{"description":"Preview of the imported tool definitions.","content":{"application/json":{"schema":{"type":"object","required":["ok","imported","inferred_class_domain","conflicts","commit_url","preview_token"],"properties":{"ok":{"type":"boolean","const":true},"imported":{"type":"array","items":{"type":"object","additionalProperties":true}},"inferred_class_domain":{"type":"object","additionalProperties":true},"conflicts":{"type":"array","items":{"type":"object","additionalProperties":true}},"commit_url":{"type":"string"},"preview_token":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/RequestEntityTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"}}}},"/tools/{name}":{"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","pattern":"^([a-z][a-z0-9_]{1,127}|org:[a-z0-9-]{3,64}:[a-z][a-z0-9_]{1,127})$"}}],"get":{"operationId":"getTool","summary":"Get a tool by name","description":"Returns the tool detail with ETag + X-Tool-Version. Supports 304 on If-None-Match.","tags":["Tools"],"security":[],"parameters":[{"name":"If-None-Match","in":"header","required":false,"schema":{"type":"string"},"description":"ETag returned from a prior GET; the server replies 304 when the tool is unchanged."}],"responses":{"200":{"description":"Tool detail.","headers":{"ETag":{"schema":{"type":"string"}},"X-Tool-Version":{"schema":{"type":"string"}},"X-Mnemom-Schema":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["name","class","domain","version","created_at","updated_at"],"properties":{"name":{"type":"string","pattern":"^([a-z][a-z0-9_]{1,127}|org:[a-z0-9-]{3,64}:[a-z][a-z0-9_]{1,127})$","description":"Globally unique tool name. Convention: `<connector>_<verb>_<noun>` (e.g. `campfire_create_chart_account`). Org-scoped tools use the reserved `org:<id>:` prefix."},"display_name":{"type":["string","null"]},"description":{"type":["string","null"]},"class":{"type":"string","enum":["read","internal_write","consequential_internal_write","consequential_external_write","comms_internal","comms_external","engineering_attestation","governance_write"],"description":"8-entry action class taxonomy per mnemom-contracts/tool-manifest/v1.yaml. V7 gateway hooks bind on this for class-scoped enforcement."},"domain":{"type":"string","enum":["financial","engineering","intelligence","growth","operations","governance","comms","identity","security"],"description":"9-entry domain taxonomy. Used by domain-scoped value declarations like policy_attentiveness(domain: financial)."},"schema":{"type":["object","null"],"description":"OpenAPI fragment / JSON Schema for the tool parameters. Populated when the tool is imported via OpenAPI spec."},"source_connector":{"type":["string","null"]},"deprecated_at":{"type":["string","null"],"format":"date-time"},"content_hash":{"type":["string","null"],"pattern":"^sha256:[a-f0-9]{64}$"},"version":{"type":"integer","minimum":1},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}}}},"304":{"description":"Not modified — the supplied If-None-Match matches the current content_hash.","headers":{"ETag":{"schema":{"type":"string"}},"X-Tool-Version":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","maxProperties":0}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"patch":{"operationId":"updateTool","summary":"Update an existing tool","description":"Updates one or more user-editable fields. Platform-admin only. Idempotency-Key required. Version bumps only when content_hash changes. Immutable fields (name, version, content_hash, deprecated_at) are rejected with structured errors.","tags":["Tools"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","minProperties":1,"additionalProperties":false,"properties":{"class":{"type":"string","enum":["read","internal_write","consequential_internal_write","consequential_external_write","comms_internal","comms_external","engineering_attestation","governance_write"],"description":"8-entry action class taxonomy per mnemom-contracts/tool-manifest/v1.yaml. V7 gateway hooks bind on this for class-scoped enforcement."},"domain":{"type":"string","enum":["financial","engineering","intelligence","growth","operations","governance","comms","identity","security"],"description":"9-entry domain taxonomy. Used by domain-scoped value declarations like policy_attentiveness(domain: financial)."},"description":{"type":["string","null"]},"display_name":{"type":["string","null"]},"schema":{"type":["object","null"],"description":"OpenAPI fragment / JSON Schema for the tool parameters. Populated when the tool is imported via OpenAPI spec."},"source_connector":{"type":["string","null"]}}}}}},"responses":{"200":{"description":"Tool updated.","headers":{"ETag":{"schema":{"type":"string"}},"X-Tool-Version":{"schema":{"type":"string"}},"X-Mnemom-Schema":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["name","class","domain","version","created_at","updated_at"],"properties":{"name":{"type":"string","pattern":"^([a-z][a-z0-9_]{1,127}|org:[a-z0-9-]{3,64}:[a-z][a-z0-9_]{1,127})$","description":"Globally unique tool name. Convention: `<connector>_<verb>_<noun>` (e.g. `campfire_create_chart_account`). Org-scoped tools use the reserved `org:<id>:` prefix."},"display_name":{"type":["string","null"]},"description":{"type":["string","null"]},"class":{"type":"string","enum":["read","internal_write","consequential_internal_write","consequential_external_write","comms_internal","comms_external","engineering_attestation","governance_write"],"description":"8-entry action class taxonomy per mnemom-contracts/tool-manifest/v1.yaml. V7 gateway hooks bind on this for class-scoped enforcement."},"domain":{"type":"string","enum":["financial","engineering","intelligence","growth","operations","governance","comms","identity","security"],"description":"9-entry domain taxonomy. Used by domain-scoped value declarations like policy_attentiveness(domain: financial)."},"schema":{"type":["object","null"],"description":"OpenAPI fragment / JSON Schema for the tool parameters. Populated when the tool is imported via OpenAPI spec."},"source_connector":{"type":["string","null"]},"deprecated_at":{"type":["string","null"],"format":"date-time"},"content_hash":{"type":["string","null"],"pattern":"^sha256:[a-f0-9]{64}$"},"version":{"type":"integer","minimum":1},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/tools/{name}/deprecate":{"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","pattern":"^([a-z][a-z0-9_]{1,127}|org:[a-z0-9-]{3,64}:[a-z][a-z0-9_]{1,127})$"}}],"post":{"operationId":"deprecateTool","summary":"Soft-delete a tool","description":"Sets deprecated_at to the current time. Idempotent: re-deprecating an already-deprecated tool returns the existing row without an UPDATE. Platform-admin only.","tags":["Tools"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":255}}],"responses":{"200":{"description":"Tool marked deprecated (or already deprecated).","content":{"application/json":{"schema":{"type":"object","required":["name","class","domain","version","created_at","updated_at"],"properties":{"name":{"type":"string","pattern":"^([a-z][a-z0-9_]{1,127}|org:[a-z0-9-]{3,64}:[a-z][a-z0-9_]{1,127})$","description":"Globally unique tool name. Convention: `<connector>_<verb>_<noun>` (e.g. `campfire_create_chart_account`). Org-scoped tools use the reserved `org:<id>:` prefix."},"display_name":{"type":["string","null"]},"description":{"type":["string","null"]},"class":{"type":"string","enum":["read","internal_write","consequential_internal_write","consequential_external_write","comms_internal","comms_external","engineering_attestation","governance_write"],"description":"8-entry action class taxonomy per mnemom-contracts/tool-manifest/v1.yaml. V7 gateway hooks bind on this for class-scoped enforcement."},"domain":{"type":"string","enum":["financial","engineering","intelligence","growth","operations","governance","comms","identity","security"],"description":"9-entry domain taxonomy. Used by domain-scoped value declarations like policy_attentiveness(domain: financial)."},"schema":{"type":["object","null"],"description":"OpenAPI fragment / JSON Schema for the tool parameters. Populated when the tool is imported via OpenAPI spec."},"source_connector":{"type":["string","null"]},"deprecated_at":{"type":["string","null"],"format":"date-time"},"content_hash":{"type":["string","null"],"pattern":"^sha256:[a-f0-9]{64}$"},"version":{"type":"integer","minimum":1},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/traces":{"get":{"operationId":"queryTraces","summary":"Query traces with filters","tags":["Traces"],"security":[{},{"ApiKeyAuth":[]},{"BearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"agent_id","in":"query","schema":{"type":"string"},"description":"Agent identifier whose traces to return (e.g. smolt-abc123). Required — requests without it are rejected to prevent cross-agent listing."},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"minimum":1,"maximum":1000},"description":"Maximum number of traces to return, most recent first (1–1000, default 50)."},{"name":"offset","in":"query","schema":{"type":"integer","default":0,"minimum":0},"description":"Number of traces to skip from the start of the result set, for pagination (default 0)."}],"responses":{"200":{"description":"Filtered list of traces","content":{"application/json":{"schema":{"type":"object","properties":{"traces":{"type":"array","items":{"$ref":"#/components/schemas/APTrace"}},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/traces/{trace_id}":{"get":{"operationId":"getTrace","summary":"Get single trace by ID","tags":["Traces"],"security":[{},{"ApiKeyAuth":[]},{"BearerAuth":[]},{"CookieAuth":[]}],"parameters":[{"name":"trace_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Trace details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/APTrace"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/transactions":{"get":{"operationId":"listTransactions","summary":"List transactions","description":"Returns a paginated list of guarded transactions. Optionally filter by agent. Each transaction is annotated with a computed `status` field (`active` or `expired`) derived from `expires_at`.","tags":["Intelligence"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"agent_id","in":"query","required":false,"schema":{"type":"string"},"description":"Filter transactions by agent ID"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"minimum":1,"maximum":100},"description":"Maximum number of results to return"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"minimum":0},"description":"Number of results to skip"}],"responses":{"200":{"description":"Paginated list of transactions","content":{"application/json":{"schema":{"type":"object","properties":{"transactions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"agent_id":{"type":"string"},"policy":{"type":"object"},"conscience_values":{"type":"array","items":{}},"expires_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["active","expired"],"description":"Computed from expires_at"}}}},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"post":{"operationId":"createTransaction","summary":"Create transaction with guardrails","description":"Create a new guarded transaction. The transaction wraps one or more agent actions with CLPI policy guardrails, ensuring all tool invocations are evaluated against the effective policy before execution. Returns the transaction ID and initial evaluation status.","tags":["Intelligence"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["transaction_id","agent_id","policy","expires_at"],"properties":{"transaction_id":{"type":"string","description":"Client-supplied unique transaction identifier. A duplicate returns 409."},"agent_id":{"type":"string","description":"Agent performing the transaction. Must reference an existing agent."},"policy":{"type":"object","additionalProperties":true,"description":"CLPI policy governing the transaction."},"expires_at":{"type":"string","format":"date-time","description":"Transaction expiry. Must be in the future."},"conscience_values":{"type":"array","items":{},"description":"Optional conscience values attached to the transaction."}}}}}},"responses":{"200":{"description":"Transaction created","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"transaction_id":{"type":"string"},"agent_id":{"type":"string"},"expires_at":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["active","expired"],"description":"Computed lifecycle status derived from `expires_at` — `active` on creation."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/transactions/{id}":{"get":{"operationId":"getTransaction","summary":"Get transaction details","description":"Retrieve the details of a guarded transaction including its current status, policy evaluation result, and action outcomes.","tags":["Intelligence"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Transaction identifier"}],"responses":{"200":{"description":"Transaction details","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"agent_id":{"type":"string"},"status":{"type":"string","enum":["pending","approved","blocked","escalated","completed","failed"]},"actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"status":{"type":"string"},"result":{}}}},"evaluation":{"$ref":"#/components/schemas/PolicyEvaluationResult"},"created_at":{"type":"string","format":"date-time"},"completed_at":{"type":["string","null"],"format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"delete":{"operationId":"deleteTransaction","summary":"Delete transaction","description":"Delete a guarded transaction. Only transactions in pending or completed status can be deleted. Active transactions must be completed or cancelled first.","tags":["Intelligence"],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Transaction identifier"}],"responses":{"200":{"description":"Transaction deleted","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"},"id":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/transparency/log/{agent_id}":{"get":{"operationId":"getTransparencyLogEntryAt","security":[],"summary":"Point-in-time canonical posture lookup.","description":"Returns the transparency-log row whose `composed_at` is the greatest at-or-before the `at` query parameter, plus a freshly-computed Merkle inclusion proof. `card_kind` defaults to `alignment`. cards-as-primitive Phase 5 A2.","tags":["Transparency"],"parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"at","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"description":"ISO-8601 UTC timestamp."},{"name":"card_kind","in":"query","required":false,"schema":{"type":"string","enum":["alignment","protection"]},"description":"Defaults to `alignment`."}],"responses":{"200":{"description":"Log entry + inclusion proof.","content":{"application/json":{"schema":{"type":"object","required":["entry","inclusion_proof"],"properties":{"entry":{"type":"object","required":["log_index","agent_id","card_kind","content_hash","version","composed_at","signed_attestation","signing_key_id","merkle_leaf_hash","tree_size_after","integrated_time"],"properties":{"log_index":{"type":"integer","minimum":1},"agent_id":{"type":"string"},"card_kind":{"type":"string","enum":["alignment","protection"]},"content_hash":{"type":"string","pattern":"^sha256:[0-9a-f]{64}$"},"version":{"type":"integer","minimum":1},"composed_at":{"type":"string","format":"date-time"},"signed_attestation":{"type":"string","description":"JWS Compact serialization signed by Mnemom over the canonical identity tuple."},"signing_key_id":{"type":"string"},"merkle_leaf_hash":{"type":"string","pattern":"^[0-9a-f]{64}$"},"tree_size_after":{"type":"integer","minimum":1},"integrated_time":{"type":"string","format":"date-time"}}},"inclusion_proof":{"type":"object","required":["leaf_hash","log_index","tree_size","hashes"],"properties":{"leaf_hash":{"type":"string","pattern":"^[0-9a-f]{64}$"},"log_index":{"type":"integer","minimum":1},"tree_size":{"type":"integer","minimum":1},"hashes":{"type":"array","items":{"type":"object","required":["sibling","position"],"properties":{"sibling":{"type":"string","pattern":"^[0-9a-f]{64}$"},"position":{"type":"string","enum":["left","right"]}}}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/transparency/log/{agent_id}/{log_index}":{"get":{"operationId":"getTransparencyLogEntryByIndex","security":[],"summary":"Direct log entry by index, with Merkle inclusion proof.","description":"Returns the row at `log_index` (if it belongs to `agent_id`) plus a freshly-computed inclusion proof. cards-as-primitive Phase 5 A2.","tags":["Transparency"],"parameters":[{"name":"agent_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"log_index","in":"path","required":true,"schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"Log entry + inclusion proof.","content":{"application/json":{"schema":{"type":"object","required":["entry","inclusion_proof"],"properties":{"entry":{"type":"object","required":["log_index","agent_id","card_kind","content_hash","version","composed_at","signed_attestation","signing_key_id","merkle_leaf_hash","tree_size_after","integrated_time"],"properties":{"log_index":{"type":"integer","minimum":1},"agent_id":{"type":"string"},"card_kind":{"type":"string","enum":["alignment","protection"]},"content_hash":{"type":"string","pattern":"^sha256:[0-9a-f]{64}$"},"version":{"type":"integer","minimum":1},"composed_at":{"type":"string","format":"date-time"},"signed_attestation":{"type":"string","description":"JWS Compact serialization signed by Mnemom over the canonical identity tuple."},"signing_key_id":{"type":"string"},"merkle_leaf_hash":{"type":"string","pattern":"^[0-9a-f]{64}$"},"tree_size_after":{"type":"integer","minimum":1},"integrated_time":{"type":"string","format":"date-time"}}},"inclusion_proof":{"type":"object","required":["leaf_hash","log_index","tree_size","hashes"],"properties":{"leaf_hash":{"type":"string","pattern":"^[0-9a-f]{64}$"},"log_index":{"type":"integer","minimum":1},"tree_size":{"type":"integer","minimum":1},"hashes":{"type":"array","items":{"type":"object","required":["sibling","position"],"properties":{"sibling":{"type":"string","pattern":"^[0-9a-f]{64}$"},"position":{"type":"string","enum":["left","right"]}}}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/transparency/root":{"get":{"operationId":"getTransparencyRoot","security":[],"summary":"Signed current Merkle root for the canonical-card transparency log.","description":"Returns the current root + tree_size + published_at, signed by the active AAP signing key. Distinct `typ` from per-card attestations (`AAP-TransparencyRoot/v1`). Cacheable for 30 seconds; consumers refresh when they want a fresh root. cards-as-primitive Phase 5 A2.","tags":["Transparency"],"responses":{"200":{"description":"Signed root, or an empty-state payload when the log has no entries.","content":{"application/json":{"schema":{"oneOf":[{"type":"object","required":["typ","tree_size","root_hash","published_at","signing_key_id","signature"],"properties":{"typ":{"type":"string","const":"AAP-TransparencyRoot/v1","description":"Domain separator distinguishing a signed root from a per-card attestation."},"tree_size":{"type":"integer","minimum":0},"root_hash":{"type":"string","pattern":"^[0-9a-f]{64}$"},"published_at":{"type":"string","format":"date-time"},"signing_key_id":{"type":"string"},"signature":{"type":"string","description":"Base64url Ed25519 signature over canonical_json(commitment), where commitment is this object MINUS `signature` — i.e. {typ, tree_size, root_hash, published_at, signing_key_id}. Verify by dropping `signature`, canonicalising the rest (sorted keys, no whitespace), and checking against the JWKS key for signing_key_id."}}},{"type":"object","required":["tree_size"],"properties":{"tree_size":{"const":0},"message":{"type":"string"}}}]}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/trust/advisories":{"get":{"operationId":"listTrustAdvisories","summary":"List published security advisories","description":"Returns the published advisories sorted by `published_at` desc. No authentication required — the surface is public trust messaging. Pagination via `limit` (default 20, max 100) and `offset`.","tags":["Trust"],"security":[],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Published advisories.","content":{"application/json":{"schema":{"type":"object","required":["advisories","limit","offset"],"properties":{"advisories":{"type":"array","items":{"type":"object","required":["id","slug","title","summary","body_markdown","severity","status","published_at","archived_at","post_mortem_for_campaign_id","synthetic","created_by","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","description":"URL-safe slug used as the customer-facing detail path."},"title":{"type":"string"},"summary":{"type":"string"},"body_markdown":{"type":"string"},"severity":{"type":"string","enum":["info","low","medium","high","critical"]},"status":{"type":"string","enum":["draft","published","archived"]},"published_at":{"type":["string","null"],"format":"date-time"},"archived_at":{"type":["string","null"],"format":"date-time"},"post_mortem_for_campaign_id":{"type":["string","null"],"format":"uuid"},"synthetic":{"type":"boolean"},"created_by":{"type":"string","format":"uuid"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"$ref":"#/components/responses/BadGateway"}}}},"/trust/advisories/{slug}":{"get":{"operationId":"getTrustAdvisoryBySlug","summary":"Fetch a published advisory by slug","description":"Returns the canonical advisory record for `{slug}`. Drafts and archived rows are not exposed on this surface — the CMS admin endpoints serve those.","tags":["Trust"],"security":[],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Advisory record.","content":{"application/json":{"schema":{"type":"object","required":["id","slug","title","summary","body_markdown","severity","status","published_at","archived_at","post_mortem_for_campaign_id","synthetic","created_by","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","description":"URL-safe slug used as the customer-facing detail path."},"title":{"type":"string"},"summary":{"type":"string"},"body_markdown":{"type":"string"},"severity":{"type":"string","enum":["info","low","medium","high","critical"]},"status":{"type":"string","enum":["draft","published","archived"]},"published_at":{"type":["string","null"],"format":"date-time"},"archived_at":{"type":["string","null"],"format":"date-time"},"post_mortem_for_campaign_id":{"type":["string","null"],"format":"uuid"},"synthetic":{"type":"boolean"},"created_by":{"type":"string","format":"uuid"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/trust/iocs":{"get":{"operationId":"listTrustIocs","summary":"STIX 2.1 Indicator-of-Compromise feed","description":"Public IoC feed returned as a STIX 2.1 Bundle. Per-indicator SDOs carry a Mnemom `extensions` block with internal type/TLP labelling. Rate-limited at the gateway and best-effort in-handler (1 req/min/IP). Pagination via `after=<ISO8601>` (resume from the last seen `last_seen_at`).","tags":["Trust"],"security":[],"parameters":[{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["substrate_fingerprint","sha256","domain","url","technique_id"]}},{"name":"after","in":"query","required":false,"description":"Cursor — ISO-8601 timestamp; rows with `last_seen_at < after` are returned.","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":1000,"default":100}}],"responses":{"200":{"description":"STIX 2.1 Bundle (possibly empty at GA — see calm-at-GA contract).","content":{"application/json":{"schema":{"type":"object","required":["type","id","objects"],"properties":{"type":{"const":"bundle"},"id":{"type":"string","description":"STIX 2.1 bundle identifier (UUID-suffixed)."},"objects":{"type":"array","description":"STIX 2.1 indicator SDOs. Each carries a Mnemom extension with the internal indicator type + TLP + linkage to a related advisory.","items":{"type":"object"}},"next_after":{"type":"string","format":"date-time","description":"Mnemom-extension pagination cursor. Present iff the response was capped at `limit`. Pass as `?after=` to fetch the next page."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/verify":{"post":{"operationId":"verifyCertificate","summary":"Verify certificate","description":"Verify an IntegrityCertificate. Performs Ed25519 signature verification, chain hash verification, Merkle inclusion proof verification, input commitment check, and optional STARK proof verification. Public endpoint, no authentication required.","tags":["Verification"],"security":[{}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["certificate"],"properties":{"certificate":{"$ref":"#/components/schemas/IntegrityCertificate"}}}}}},"responses":{"200":{"description":"Verification result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyCertificateResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}}}}