Repository navigation
Expand file tree
/
Copy path_openapi.json
More file actions
1 lines (1 loc) · 235 KB
/
Copy path_openapi.json
File metadata and controls
1 lines (1 loc) · 235 KB
1
{"openapi":"3.1.0","info":{"title":"Mnemoverse Core","description":"\n## Persistent Cognitive Memory for AI Agents\n\nWrite memories, query with semantic + episodic search, learn from outcomes via valence,\nand compress with sleep consolidation.\n\n### Quick Start\n- `POST /api/v1/memory/write` -- store an insight\n- `POST /api/v1/memory/read` -- recall relevant memories\n- `POST /api/v1/memory/feedback` -- teach the system what worked\n- `POST /api/v1/memory/consolidate` -- compress similar memories\n- `GET /api/v1/memory/stats` -- see memory state\n- `WS /api/v1/memory/stream` -- real-time updates (WebSocket)\n ","contact":{"name":"Mnemoverse","url":"https://github.com/mnemoverse"},"license":{"name":"MIT"},"version":"1.0.0"},"paths":{"/api/v1/memory/write":{"post":{"tags":["memory"],"summary":"Write Memory","description":"Store a new memory atom.\n\nContent is embedded, filtered by importance, then stored with Hebbian links.\n\nWith `supersedes`, the write instead replaces the listed atoms: the successor\nis stored and every target is marked as superseded by it, in one transaction\n— all of it or none of it. The importance/novelty REJECTION is skipped for\nsuch a write (a successor resembles its predecessor by construction) while\nthe score is still computed and returned.","operationId":"write_memory_api_v1_memory_write_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteRequestSchema"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteResponseSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/memory/write_batch":{"post":{"tags":["memory"],"summary":"Write Batch","description":"Store multiple memory atoms in one request. Each atom is processed sequentially.\n\n`supersedes` is refused here (422) — see `_reject_supersedes_in_batch`.","operationId":"write_batch_api_v1_memory_write_batch_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteBatchRequestSchema"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteBatchResponseSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Engine not initialized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/memory/read":{"post":{"tags":["memory"],"summary":"Read Memory","description":"Query memory.\n\nEpisodic exact match (if fingerprint), then semantic search and Hebbian expansion.","operationId":"read_memory_api_v1_memory_read_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadRequestSchema"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadResponseSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/memory/graph":{"post":{"tags":["memory"],"summary":"Read Graph","description":"Bounded read of the concept-association graph around `seeds` (core#630).\n\nDistinct from `/memory/read`'s `expanded_concepts` (names only, discarded\nweights): this returns the actual `hebbian_edges` rows — weight, valence,\ncount — for a caller-supplied neighbourhood, never the whole org's graph\n(`PostgresStorage.load_hebbian_edges` stays reserved for the single-tenant\nWS viz snapshot it was built for). Same org resolution and auth/scope as\n`/memory/read` — a read-only op, `require_write=False`.\n\nAn unknown seed (or one whose edges all fall below `min_weight`) simply\ncontributes nothing: an all-unknown `seeds` list is a 200 empty graph, not\na 404 — same \"absence is not an error\" contract as `/memory/recent`.\n\n`req.domain` reaches `_resolve_target_org` exactly like `/memory/read`'s\ndoes: an `xroom:<room_id>` value resolves to that room's OWN storage\nbucket (after the membership/scope check) — a real change of which org's\nedges get read, not a filter within one org. Any other value is inert\n(`hebbian_edges` has no `domain` column), same as passing none.","operationId":"read_graph_api_v1_memory_graph_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphRequestSchema"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphResponseSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/memory/recent":{"post":{"tags":["memory"],"summary":"Recent Memory","description":"Queryless newest-first feed (#404 R5) — backs MCP ``memory_list_recent``.\n\nA keyset walk over ``(created_at DESC, id DESC)``, complete by\nconstruction: the temporal complement of /memory/read's semantic gate.\nAn empty feed is ``200 {\"items\": [], \"next_cursor\": null}`` and NEVER a\n404 — the shipped MCP client reads a bare 404 as \"endpoint not deployed\"\nand hides the feature behind a fallback hint.","operationId":"recent_memory_api_v1_memory_recent_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecentRequestSchema"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecentResponseSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/memory/feedback":{"post":{"tags":["memory"],"summary":"Feedback","description":"Report outcome for atoms (success/failure). Updates valence and Hebbian weights.","operationId":"feedback_api_v1_memory_feedback_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackRequestSchema"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackResponseSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/memory/consolidate":{"post":{"tags":["memory"],"summary":"Consolidate","description":"Run soft consolidation behind the explicit single-worker safety gate.","operationId":"consolidate_api_v1_memory_consolidate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsolidateRequestSchema"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsolidationResponseSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Consolidation unavailable or an operator safety gate is unsatisfied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"409":{"description":"Consolidation conflict; retry the request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/memory/rooms":{"get":{"tags":["memory"],"summary":"List Rooms For Agent","description":"Discover the rooms the AUTHENTICATED account can use: rooms it OWNS plus rooms it\nhas JOINED, each with its ready-to-use ``xroom:<room_id>`` address and the caller's\nrole — so a fresh agent session can RE-FIND its rooms instead of only being able to\ncreate/join them. Like create/join, the caller org is derived from the key's claims\n(``_get_org_id``), NEVER from the request — the same tenancy boundary. A fresh room\nseeds its owner as a member of itself, so an owned room also comes back from the\nmember lookup; owner rows are added first so it surfaces ONCE, as ``owner``.","operationId":"list_rooms_for_agent_api_v1_memory_rooms_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/RoomListItemSchema"},"type":"array","title":"Response List Rooms For Agent Api V1 Memory Rooms Get"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Caller org not identified","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Rooms require the database backend","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}}}},"post":{"tags":["memory"],"summary":"Create Room For Agent","description":"Create a room owned by the AUTHENTICATED account (Rooms Wave 2).\n\nUnlike the portal-plane ``/rooms`` routes (which require ``X-Admin-Key`` + a\nverified session), this endpoint lives on the tenant ``router`` and derives\nthe owner from ``request.state.claims`` — the org that the auth middleware\n(DB-backed ``mk_live_`` key / JWT) populated. So an agent holding only its\n``mk_live_`` key can provision its own room. The owner is taken from the\nkey's claims (``_get_org_id``), NEVER the request body (the schema also\nforbids a body-supplied ``owner_org_id``) — the same anti-self-grant\ninvariant the portal path enforces from the session.\n\nNote: this path is NOT in the middleware's portal-prefix bypass list\n(``/admin``/``/rooms``/``/projects``), so tenant-key auth runs here as normal.\nA fresh room seeds its owner as a ``read_write`` member (see\n``RoomStore.create_room``), so the owner can immediately read/write it via\nthe ``xroom:<room_id>`` address; inviting OTHER accounts is a separate step.","operationId":"create_room_for_agent_api_v1_memory_rooms_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRoomRequestSchema"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomCreatedSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Caller org not identified","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Rooms require the database backend","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"409":{"description":"Room name already exists for this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/memory/rooms/{room_id}/invites":{"post":{"tags":["memory"],"summary":"Create Room Invite","description":"Mint a shareable one-time invite code for a room you own (Rooms Wave 2b).\n\nThe role is fixed at mint (``scope``), never chosen by whoever redeems — the\ncode IS the grant (ADR-019 §5.1). Only the code's hash is stored; the raw\ncode is returned ONCE, here, inside a ready-to-forward ``share_message``.","operationId":"create_room_invite_api_v1_memory_rooms__room_id__invites_post","parameters":[{"name":"room_id","in":"path","required":true,"schema":{"type":"string","title":"Room Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateInviteRequestSchema"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteCreatedSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Caller org not identified","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"You do not own this room","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Room not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["memory"],"summary":"List Room Invites","description":"List a room's invites (owner-only). Audit fields only — never the raw code\nor its hash. Lets the owner see status (used / expired / revoked).","operationId":"list_room_invites_api_v1_memory_rooms__room_id__invites_get","parameters":[{"name":"room_id","in":"path","required":true,"schema":{"type":"string","title":"Room Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/InviteInfoSchema"},"title":"Response List Room Invites Api V1 Memory Rooms Room Id Invites Get"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Caller org not identified","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"You do not own this room","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Room not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/memory/rooms/join":{"post":{"tags":["memory"],"summary":"Join Room","description":"Redeem an invite code — you become a member of its room with the invite's\nrole. The joiner is YOUR authenticated org (from the key), never the body;\nonly the code is supplied. Idempotent: if you are already a member you get a\nno-op success (``already_member: true``), no use is consumed.","operationId":"join_room_api_v1_memory_rooms_join_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinRoomRequestSchema"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinedRoomSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Caller org not identified","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Invite code not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"409":{"description":"Invite expired/revoked/used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/memory/stats":{"get":{"tags":["memory"],"summary":"Stats","description":"Get memory statistics (atom counts, Hebbian edges, domains, etc.).","operationId":"stats_api_v1_memory_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatsResponseSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}}}}},"/api/v1/memory/reset":{"delete":{"tags":["memory"],"summary":"Reset Memory","description":"Wipe all atoms, links, fingerprints. Requires ALLOW_RESET=true.","operationId":"reset_memory_api_v1_memory_reset_delete","responses":{"200":{"description":"Memory cleared.","content":{"application/json":{"schema":{}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Reset not allowed (ALLOW_RESET=false)."},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Engine not initialized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}}}}},"/api/v1/memory/atoms/{atom_id}":{"delete":{"tags":["memory"],"summary":"Delete Atom","description":"Delete a single atom by ID. Hebbian edges are left untouched.\n\nDeleting an atom removes that atom's row and nothing else. In\nparticular it does NOT sweep Hebbian edges: `hebbian_edges` has no\nforeign key to `atoms` (endpoints are plain concept strings), so no\nedge dangles when an atom dies, and the associations learned from\nretrieval (`co_activate`) are cross-atom by construction — they are\nnot derivable from any single atom's `concepts` list. The\npost-delete sweep that used to run here deleted exactly those\nlearned edges and kept only the redundant, atom-derivable ones; it\nwas removed 2026-08-20. See ADR-012 errata.\n\nSecret-atoms (the caller's Vault) are immutable via this endpoint\n(Design 13): `storage.delete_atoms` silently skips them, so a 0-row\ndelete is disambiguated below — a real secret-atom returns 403\ninstead of the ordinary idempotent `{\"deleted\": 0}`.\n\n**Deleting an atom that sits in a supersession chain is permitted and\nLOUD.** Delete is administrative and destructive by design, and refusing\nit would leave a tenant unable to remove their own data — so instead the\nresponse says what it broke: `superseded_predecessors_left_hidden` names\nthe atoms that are now marked superseded with nothing pointing at them —\npermanently so, once read-side filtering (D2) makes that marking hide them —\nand `history_destroyed` says the revision chain lost a link.","operationId":"delete_atom_api_v1_memory_atoms__atom_id__delete","parameters":[{"name":"atom_id","in":"path","required":true,"schema":{"type":"string","title":"Atom Id"}}],"responses":{"200":{"description":"Atom deleted.","content":{"application/json":{"schema":{}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Engine not initialized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["memory-v1"],"summary":"Get Atom","description":"Point read: retrieve full atom detail by ID (for debug/tracing).","operationId":"get_atom_api_v1_memory_atoms__atom_id__get","parameters":[{"name":"atom_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Atom Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AtomDetailSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/memory/domain/{domain}":{"delete":{"tags":["memory"],"summary":"Delete Domain","description":"Delete all atoms in a domain. Hebbian edges are left untouched.\n\nTenant-scoped: only deletes atoms in the calling org's scope.\nHebbian edges are not swept — see `delete_atom` above for why there\nis no such thing as an orphan edge here. Wiping one domain therefore\nleaves every association learned over other domains' atoms intact.\n\nSecret-atoms (the caller's Vault) are immutable via this endpoint\n(Design 13): they are filtered out before delete, never wiped, and\nthe count excluded is reported as `skipped_secrets`.\n\nLike `delete_atom`, a wipe that breaks supersession chains says so — as\n`superseded_predecessors_left_hidden_count` (an int; `delete_atom` returns\nthe ids themselves, hence the different name for the different shape),\nbecause a domain can hold arbitrarily many. A predecessor living INSIDE the\nwiped domain is deleted alongside its successor and is therefore not \"left\nhidden\"; only predecessors in other domains are.","operationId":"delete_domain_api_v1_memory_domain__domain__delete","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}}],"responses":{"200":{"description":"Domain cleared.","content":{"application/json":{"schema":{}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Engine not initialized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/memory/domains":{"get":{"tags":["memory"],"summary":"List Domains","description":"List all memory domains for the current tenant.","operationId":"list_domains_api_v1_memory_domains_get","responses":{"200":{"description":"List of domains.","content":{"application/json":{"schema":{}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Engine not initialized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}}}}},"/api/v1/health":{"get":{"tags":["health"],"summary":"Health","description":"Liveness probe: is the process alive? Fast, no DB check.","operationId":"health_api_v1_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponseSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}}}}},"/api/v1/ready":{"get":{"tags":["health"],"summary":"Ready","description":"Readiness probe: is the service ready to serve traffic? Checks engine + DB.","operationId":"ready_api_v1_ready_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponseSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}}}}},"/api/v1/health/ready":{"get":{"tags":["memory-v1"],"summary":"Health Ready","description":"Deep readiness check.\n\n``ready`` = database AND engine (the hard dependencies) → HTTP 503 when\nfalse, so an orchestrator healthcheck (Railway) refuses to promote a build\nwhose startup failed (FAILURE-SURFACE P0-4: the old contract was HTTP 200\nwith ``ready: false`` in the body, which promoted broken builds).\n\n``checks.warm`` is reported to every caller: True when the warm-up is\ndisabled, its readiness gate\n(`Settings.concept_expander_warm_ready_gate_seconds`, 0 = off by default)\nis 0, THIS process's warm run has finished, or the gate's time cap has\nelapsed. It turns ``ready`` false, and the answer into a 503, ONLY for the\norchestrator's deploy healthcheck (`_is_deploy_healthcheck`: Railway\nprobes from `healthcheck.railway.app`, at the start of a deployment only),\nbecause holding traffic promotion is the gate's one purpose. A process\nrestarted after a crash takes traffic with no healthcheck at all, so every\nother reader is asking about a process that is already serving and gets\n``ready: true`` with ``checks.warm: false``. The wait is bounded by the cap\nin every case, including a warm run that never starts. See\n`_resolve_warm_check`.\n\n``checks.embedding`` is a LIVE vendor call (cached 60 s — see\n``_probe_embedding``). It does NOT gate ``ready``: a dead embedding vendor\nyields HTTP 200 with ``degraded: true`` so the fix for a vendor outage can\nstill be deployed *during* the outage, and external probes alert on\n``degraded`` instead. Probes must assert ``ready && !degraded``.","operationId":"health_ready_api_v1_health_ready_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadyResponseSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Not ready: database or engine is down, or the (bounded) concept-expander warm-up gate has not yet opened (same body, `ready: false`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadyResponseSchema"}}}}}}},"/api/v1/memory/write-batch":{"post":{"tags":["memory-v1"],"summary":"Write Batch","description":"Batch write up to 100 memory atoms.\n\n## Idempotency\n\nSupports the Stripe-style `Idempotency-Key` header. Clients that retry\nthe same logical write after a network failure (including the 2026-04-13\nCloudflare 524 / ghost-write scenario) can pass the same key and get\nback the exact response the server cached on the first successful\nprocessing, rather than double-writing atoms. The cache TTL is 24 hours\n(see migrations/versions/004_idempotency.py).\n\nThe key is scoped per operation and per organization by\n`_scoped_idempotency_key` so two tenants cannot collide on the same\nraw UUID. The org fragment is a SHA-256 hash prefix, not the raw\norg_id, to make the key delimiter-safe regardless of what characters\nthe upstream auth layer produces.\n\n### ⚠️ Sequential retries only\n\nThis implementation protects **sequential** retries (client waits for\nthe first request to return or time out, then retries with the same\nkey). **Concurrent** retries are NOT serialized: if two retries of\nthe same key land while the first processing is still in flight,\nboth will observe a cache miss and both will call `engine.write()`.\nIn practice MCP clients retry with exponential backoff so this race\nis rare, but if the dashboards surface it as a real signal we will\nadd a processing-sentinel row inserted with `ON CONFLICT DO NOTHING`\nat the top of the handler (tracked as Step 2c.1 in the observability\nsprint plan). Documented so a future reader does not assume the\ncurrent code is fully race-safe.\n\n### Failure modes\n\n* Missing or empty header → no caching, behaves as before.\n* Header > 240 chars → 400 VALIDATION_ERROR (table column is 255).\n* Cache lookup DB error → falls through to normal processing (we\n prefer a duplicate write over a hard failure on the retry path).\n* Cache store DB error → the response is still returned to the\n client; we log the cache failure and move on so the successful\n write is not lost.","operationId":"write_batch_api_v1_memory_write_batch_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteBatchRequestSchema"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteBatchResponseSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/memory/read-batch":{"post":{"tags":["memory-v1"],"summary":"Read Batch","description":"Batch read up to 50 queries.","operationId":"read_batch_api_v1_memory_read_batch_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadBatchRequestSchema"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadBatchResponseSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/memory/query":{"post":{"tags":["memory-v1"],"summary":"Query Memory","description":"Advanced query: multi-domain, metadata filters, same response shape as /memory/read.","operationId":"query_memory_api_v1_memory_query_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryRequestSchema"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadResponseSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/memory/atoms/{atom_id}/chain":{"get":{"tags":["memory-v1"],"summary":"Get Atom Chain","description":"Every revision reachable from this one by supersession links.\n\n`include_history` on a read grants ELIGIBILITY: history competes under the\nsame ranking, `min_relevance` and `top_k` as everything else, so a read can\nlegitimately return part of a chain and no read can promise all of it. This\nendpoint is the handle that does promise all of it — hand it any revision,\nget the whole chain.\n\nThe walk goes BOTH ways: up through `superseded_by` to the live tip, and\ndown through `supersedes` — which is a LIST, because one successor may\nconsolidate several predecessors (D3 §1), so starting from one consumed\nrevision still reveals its siblings.\n\nIt hydrates through `get_atom`, the point read, which resolves any revision\nregardless of the read-side filter (contract §7). A chain is therefore\navailable whether or not that filter is enabled: it is a fact about the\ndata, not a behaviour of the filter.\n\nRevisions come back in topological order — a predecessor never follows\nsomething that replaced it — with `created_at` deciding only between\nbranches the links leave unordered. See `_chain_order`; ordering by time\nalone is wrong on any host whose clock is coarser than its write rate.\n\nFailure modes are answers, not errors. A pointer that resolves to nothing —\nthe successor was destroyed by the loud delete handle (#518), or belongs to\nanother tenant — is reported in `dangling`; running out of point-read budget\nsets `truncated`. That budget counts every resolution, missed ones included,\nso `revisions` can stop short of `CHAIN_MAX_NODES` when the chain is full of\nholes — `truncated` is the signal, never the length. An unknown or foreign\nstarting id is a 404, indistinguishable from each other by design (the same\nanti-oracle rule the plain GET follows).","operationId":"get_atom_chain_api_v1_memory_atoms__atom_id__chain_get","parameters":[{"name":"atom_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Atom Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AtomChainSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/memory/atoms/by-external-ref":{"post":{"tags":["memory-v1"],"summary":"Get Atom By External Ref","description":"Resolve atom by external reference (for idempotent integration).","operationId":"get_atom_by_external_ref_api_v1_memory_atoms_by_external_ref_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalRefRequestSchema"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AtomDetailSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/memory/export":{"get":{"tags":["memory-v1"],"summary":"Export Memories","description":"Stream all memories for the calling org as JSONL.\n\nUniversal data portability: every user can take their memories with\nthem at any time, in every subscription state. Used to fulfill the\nrefund-policy promise that downgraded users have 30 days to export\nbefore atom-limit grace expires.\n\n- Auth: standard tenant API key (X-Api-Key)\n- Format: newline-delimited JSON, one atom per line\n- Streaming: server-side cursor, no in-memory buffering — works for\n Free (10K) through Team (5M) without OOM\n- Embeddings excluded (large, model-specific, derivable from content)\n\nReads NEVER blocked guarantee applies — export works in active,\npast_due, over_limit, suspended states.","operationId":"export_memories_api_v1_memory_export_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}}}}},"/api/v1/vault/secrets":{"get":{"tags":["vault"],"summary":"List Secrets","description":"Discovery: list the caller's secrets as VALUE-FREE metadata (alias, context,\ncreated_at, concepts) so an agent can FIND a secret by alias WITHOUT ever seeing a\nvalue. The tenant comes from the VERIFIED claims and scopes the query (org A can\nnever enumerate org B's secrets). A secret-atom with no reachable ``secret:{alias}``\nexternal_ref (e.g. stored directly, not via this route) is SKIPPED — its alias could\nnot be used via the by-alias route anyway, so surfacing it would only mislead.","operationId":"list_secrets_api_v1_vault_secrets_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSecretsResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}}}},"post":{"tags":["vault"],"summary":"Create Secret","description":"Store a secret-atom: the context is embedded + woven into the graph (findable\nby purpose); the envelope-encrypted value goes to the use-only column.","operationId":"create_secret_api_v1_vault_secrets_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSecretRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSecretResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/vault/secrets/by-alias/{alias}":{"get":{"tags":["vault"],"summary":"Fetch Sealed By Alias","description":"The use-path: return ONLY the sealed value for the caller's secret by alias.\nNever returns content — the value and the context are never handed back together.","operationId":"fetch_sealed_by_alias_api_v1_vault_secrets_by_alias__alias__get","parameters":[{"name":"alias","in":"path","required":true,"schema":{"type":"string","title":"Alias"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SealedSecretResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/keys":{"post":{"tags":["admin"],"summary":"Create Key","description":"Create a new per-tenant API key. The full key is returned only once.","operationId":"create_key_api_v1_admin_keys_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["admin"],"summary":"List Keys","description":"List API keys (masked — full key is never returned).\n\nOptional filters:\n- org_id: filter by organization\n- active_only: only return active keys","operationId":"list_keys_api_v1_admin_keys_get","parameters":[{"name":"org_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Id"}},{"name":"active_only","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Active Only"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/KeyInfo"},"title":"Response List Keys Api V1 Admin Keys Get"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/keys/self-serve":{"post":{"tags":["admin"],"summary":"Create Self Serve Key","description":"Mint a key into the authenticated user's OWN user_<sub> tenant. Two proofs: X-Admin-Key\n(caller = portal, via _require_admin) AND a valid forwarded user session (via _verify_session_sub).\nThe org is DERIVED from the session, never from the body — so this path may target the reserved\nuser_ namespace that POST /admin/keys forbids, without weakening that guard.","operationId":"create_self_serve_key_api_v1_admin_keys_self_serve_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelfServeKeyRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/keys/connector":{"post":{"tags":["admin"],"summary":"Create Connector Key","description":"Get-or-create the per-user API key the remote MCP server (RS) uses to call\ncore on behalf of a connector user. TWO proofs (like ``/keys/self-serve``): the\n``X-Admin-Key`` (caller = the trusted RS) AND the user's OIDC access token\nforwarded as ``X-Connector-Token`` (verified against the AS JWKS). The org is\nDERIVED from the verified ``sub`` (``user_<sub>``), never from the body — so this\npath may target the reserved ``user_`` namespace WITHOUT weakening the\n``POST /admin/keys`` guard.\n\nRevokes any prior active connector key for this (user, client_label) and mints a\nfresh one (the raw key is only knowable at creation; the RS caches it). Invariant:\nat most one ACTIVE connector key per (user, client_label) — different clients\n(claude, chatgpt, ...) hold their own keys simultaneously; the NULL group (older\nRS builds) is matched via IS NOT DISTINCT FROM. All keys are tagged\n``name=\"__connector__\"`` so they never collide with the user's own portal keys.\n\nTier and limits come from the ORG SUBSCRIPTION, not the body: enforcement\n(``DailyQuotaMiddleware`` in ``usage.py``) reads limits from the KEY row, so\nconnector traffic must carry the org plan rather than hardcoded free defaults.\nKeys rotate hourly, so later plan changes self-heal within an hour. The body's\ntier/limit fields are IGNORED (wire compat with older RS builds only).","operationId":"create_connector_key_api_v1_admin_keys_connector_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorKeyRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/keys/{key_id}":{"delete":{"tags":["admin"],"summary":"Revoke Key","description":"Revoke an API key (soft-delete: sets is_active=false).","operationId":"revoke_key_api_v1_admin_keys__key_id__delete","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"title":"Response Revoke Key Api V1 Admin Keys Key Id Delete"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/org/{org_id}":{"delete":{"tags":["admin"],"summary":"Delete Org Cascade","description":"Cascade-delete every resource belonging to a single tenant.\n\nCloses Issue #265: until this endpoint existed, the only way to undo a\nbench / demo / QA / preview run was per-domain ``DELETE\n/memory/domain/{domain}`` calls, which left orphan Hebbian edges,\nfingerprints, and api_keys behind — exactly the asymmetry that let the\novernight benchmark loop dump ~200 atoms into the founder's prod org\nwith no clean recovery path.\n\nWhat gets deleted (single atomic transaction in\n``PostgresStorage.cascade_delete_org``):\n\n1. atoms — every row WHERE ``organization_id = $1``\n2. hebbian_edges — every row WHERE ``organization_id = $1``\n (by-org direct DELETE, not orphan-cleanup: atomic transaction\n means no concurrent INSERT into atoms can re-create a\n supporting row mid-cascade)\n3. episodic_fingerprints — whole tenant slice WHERE ``organization_id = $1``\n4. api_keys — soft-delete (``UPDATE is_active=FALSE``) so the audit\n trail (created_at / last_used_at / tier history) survives for\n compliance. Hard-delete is the wrong default — it loses\n billing-relevant provenance and any post-mortem signal about\n who used what.\n5. org_subscriptions — the billing row (Stripe ids + contact-email\n PII), so a recreated org doesn't inherit a stale tier and no\n orphaned PII is left behind.\n6. usage_daily — the per-org usage history.\n\nAfter the transaction commits, the subscription cache is invalidated and the\norg's in-memory per-org engine state (Hebbian graph, concept index, episodic\nfingerprints) is evicted, so a recreated org reusing the same id starts truly\nclean — no \"ghost-tenant\" via cached tier or in-memory slots.\n\nGuards (defense-in-depth):\n\n* ``_require_admin`` — X-Admin-Key matches ADMIN_API_KEY setting.\n Constant-time compare via ``secrets.compare_digest``.\n* ``_validate_deletable_org`` — rejects the reserved ``user_`` OIDC\n namespace so a leaked ADMIN_API_KEY cannot wipe a real user's tenant,\n while still allowing ``room_``/``proj_`` bucket cleanup (the mint guard,\n by contrast, rejects ALL system prefixes).\n* default-sentinel guard — also refuses ``settings.default_org`` so a\n fat-finger cannot TRUNCATE a whole single-tenant deployment.\n* Storage runs inside ``_scoped(organization_id)`` which opens a\n single ``conn.transaction()`` and sets the tenant GUC so\n Postgres RLS (migration 013) authorises every statement under\n the non-superuser ``mnemo_app`` role; the explicit\n ``WHERE organization_id = $1`` clauses are the second layer.\n\nIdempotency: a second call against the same ``org_id`` returns all-zero\ncounts ``{atoms, hebbian_edges, fingerprints, keys_revoked,\norg_subscriptions, usage_daily, org_settings, org_settings_audit}`` — every\ndelete is a no-op once the tenant is empty. Safe to retry on transport\nfailure.\n\nReturns: ``{organization_id, deleted: {atoms, hebbian_edges, fingerprints,\nkeys_revoked, org_subscriptions, usage_daily, org_settings,\norg_settings_audit}}``.\n\nRaises:\n HTTPException(400): organization_id has user_ prefix or invalid shape.\n HTTPException(401): X-Admin-Key missing or wrong.\n HTTPException(503): admin key not configured or DB pool unavailable.","operationId":"delete_org_cascade_api_v1_admin_org__org_id__delete","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteOrgResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/org/{org_id}/tier":{"put":{"tags":["admin"],"summary":"Update Org Tier","description":"Update tier for all active keys belonging to an organization.","operationId":"update_org_tier_api_v1_admin_org__org_id__tier_put","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTierRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Update Org Tier Api V1 Admin Org Org Id Tier Put"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/org/{org_id}/usage":{"get":{"tags":["admin"],"summary":"Org Usage","description":"Get daily usage for an organization (last N days).","operationId":"org_usage_api_v1_admin_org__org_id__usage_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","default":7,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgUsageResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/aggregate/usage":{"get":{"tags":["admin"],"summary":"Aggregate Usage","description":"Platform-wide usage aggregated across ALL organizations for the\nlast N days (default 7).\n\nPowers the portal admin dashboard's \"platform usage\" card. v1 is\noperational-only: reads/writes/feedbacks/queries, distinct active\nkeys, distinct organizations, and the top 10 orgs by query volume.\n\nResponse notes for consumers: the top-level totals cover ALL\norganizations, whereas `top_orgs_by_queries` is only the TOP 10 — do\nNOT sum it to derive the platform total (use `total_queries`). The\n`daily` array is ordered newest-first by date and omits days with no\nactivity (gaps mean zero), so its length may be < `days`.\n\n`days` is validated to `[1, 90]` at the FastAPI layer via `Query`\n(HTTP 422 before any DB work). The window itself is computed in\nPostgres as `CURRENT_DATE - make_interval(days => $1)` with the day\ncount bound as a parameter — never string-interpolated. The only\ninterpolated token in any of these queries is `{schema}`, which is a\nvalidated SQL identifier from settings (`validate_sql_identifier`),\nnot request input.","operationId":"aggregate_usage_api_v1_admin_aggregate_usage_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":7,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AggregateUsageResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/aggregate/accounts":{"get":{"tags":["admin"],"summary":"Aggregate Accounts","description":"Live account-level aggregates over personal (``user_``) orgs.\n\nMirrors the portal sweep's definitions so a live tile and last night's\nrollup describe the same population:\n\n* ``orgs_with_atoms`` / ``atoms_total`` — accounts holding at least one\n memory, and the platform total (sweep: ``atoms > 0`` / ``SUM(atoms)``).\n These two are read through the storage layer's maintenance route, NOT\n this handler's pool: ``atoms`` is under FORCE RLS (013) plus 027's\n RESTRICTIVE room policies, and a pooled count with no tenant context\n answers a silent zero — which is precisely what this endpoint shipped to\n the console on 2026-08-10. They are NULL, with a reason, whenever that\n route cannot answer. The default-off ``ADMIN_ATOMS_AGGREGATES_ENABLED``\n kill switch also returns NULL without calling storage; neither path ever\n produces a fallback zero.\n* ``orgs_with_active_key`` — accounts with a live key (``active_keys > 0``).\n* ``orgs_called_30d`` — accounts with any read or write inside the\n window; feedbacks deliberately NOT counted, matching the sweep's\n ``reads_30d + writes_30d > 0``.\n* ``paying_org_ids`` — non-free tiers as a list (see block comment: the\n grant carve-out is the portal's to apply). ``status`` is deliberately\n not filtered — the sweep's per-org read doesn't filter it either, and\n the two surfaces must not disagree about who counts.\n\n``days`` is bound as a SQL parameter; the only interpolated token is the\nvalidated ``{schema}`` identifier — same guarantees as\n``aggregate/usage`` above.","operationId":"aggregate_accounts_api_v1_admin_aggregate_accounts_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":30,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AggregateAccountsResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/org/{org_id}/subscription":{"get":{"tags":["admin"],"summary":"Get Org Subscription","description":"Return current subscription state for an organization.\nAuto-creates a `free` subscription if none exists.","operationId":"get_org_subscription_api_v1_admin_org__org_id__subscription_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["admin"],"summary":"Update Org Subscription","description":"Update subscription state. Stripe webhooks call this with `event` hints.\n\nOrder of operations:\n1. Apply event-driven transitions (payment_failed, etc.)\n2. Apply tier changes (if `tier` provided)\n3. Set Stripe IDs (if provided)\n4. Set requested_tier (deferred downgrade)\n5. Set raw status (rare; for manual admin override)","operationId":"update_org_subscription_api_v1_admin_org__org_id__subscription_put","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSubscriptionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/org/{org_id}/subscription/check-limits":{"post":{"tags":["admin"],"summary":"Check Subscription Limits","description":"Recompute over_limit status by checking current atom count vs tier limit.\nUsed after downgrades or as a periodic cron job.","operationId":"check_subscription_limits_api_v1_admin_org__org_id__subscription_check_limits_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/org/{org_id}/plan-entitlements":{"get":{"tags":["admin"],"summary":"Get Org Plan Entitlements","description":"Return the durable entitlement ledger, including expired/ended rows.","operationId":"get_org_plan_entitlements_api_v1_admin_org__org_id__plan_entitlements_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PlanEntitlementResponse"},"title":"Response Get Org Plan Entitlements Api V1 Admin Org Org Id Plan Entitlements Get"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/org/{org_id}/plan-entitlements/{entitlement_id}":{"put":{"tags":["admin"],"summary":"Put Org Plan Entitlement","description":"Idempotently create/extend access without rewriting billing state.","operationId":"put_org_plan_entitlement_api_v1_admin_org__org_id__plan_entitlements__entitlement_id__put","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}},{"name":"entitlement_id","in":"path","required":true,"schema":{"type":"string","title":"Entitlement Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivatePlanEntitlementRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanEntitlementMutationResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"409":{"description":"Manual-review entitlement conflict (see PlanEntitlementConflict codes).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanEntitlementConflictResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/org/{org_id}/plan-entitlements/{entitlement_id}/end":{"post":{"tags":["admin"],"summary":"End Org Plan Entitlement","description":"Terminal idempotent end; writes a tombstone if activation has not arrived.","operationId":"end_org_plan_entitlement_api_v1_admin_org__org_id__plan_entitlements__entitlement_id__end_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}},{"name":"entitlement_id","in":"path","required":true,"schema":{"type":"string","title":"Entitlement Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndPlanEntitlementRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanEntitlementMutationResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"409":{"description":"Manual-review entitlement conflict (see PlanEntitlementConflict codes).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanEntitlementConflictResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/org/{org_id}/llm-provider":{"put":{"tags":["admin"],"summary":"Set Org Llm Provider","description":"Set or clear the per-org LLM provider override.","operationId":"set_org_llm_provider_api_v1_admin_org__org_id__llm_provider_put","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetLLMProviderRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LLMProviderResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/org/{org_id}/embedding-model":{"put":{"tags":["admin"],"summary":"Set Org Embedding Model","description":"Set or clear the per-org embedding-model pin.\n\nMirrors ``set_org_llm_provider``: an ``UPDATE org_subscriptions ... RETURNING``\n+ invalidation of the engine's in-memory per-org embedding cache so the pin\ntakes effect for the very next request ON THIS WORKER (other workers pick it\nup after their next restart — same accepted multi-worker tradeoff as the LLM\npref cache).\n\n🔴 ADR-021 M2 — per-org embedding dispatch (M1.5) + coexisting-dimension storage\n(M2) are LIVE. The engine resolves the org's OWN ``EmbeddingService`` per request\n(``_resolve_org_embedding_service``), and M2 added the per-dim storage columns\n(``_EMBEDDING_DIM_COLUMNS`` — the SSOT for which dims are storeable). A pin is\neffective once its produced vector has a column to land in — ``effective =\n(pin.dim == global.dim) OR (a routing column exists for pin.dim)``:\n * same-dim pin → ``effective=true`` (existing atoms migrate via\n ``scripts/reembed_atoms.py``; no re-embed needed for new writes);\n * STOREABLE cross-dim pin (e.g. text-embedding-3-small@1536 after migration 022\n added ``embedding_1536``) → ``effective=true`` — new vectors land in the\n matching per-dim column, cross-dim isolated from the global corpus;\n * UNSTOREABLE cross-dim pin (a dim with no routing column yet, e.g. 3072) →\n ``effective=false`` — recorded as the re-embed target once a column is added.\nWe RECORD the pin either way (so an operator-driven re-embed has its target).\nReturning the row (record) is more useful than a hard 409 (reject): the pin is\nthe persisted target the dispatch + re-embed read.\n\n🔴 Cache-race serialization (MUST-FIX): the DB UPDATE and the in-memory cache\nmutation are held under a per-org ``asyncio.Lock`` so a concurrent PUT for the\nSAME org cannot interleave between commit and cache-update and leave the cache\nreflecting the losing write.","operationId":"set_org_embedding_model_api_v1_admin_org__org_id__embedding_model_put","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetEmbeddingModelRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingModelResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/org/{org_id}/settings":{"get":{"tags":["admin"],"summary":"Get Org Settings Endpoint","description":"The organisation's per-org flags: the stored override (null = unset),\nthe resolved effective value, and which tier of the resolution order\ndecided it. ``history`` is the last twenty audit rows, newest first.\n\n``effective`` describes enforced behaviour, not intent. ``effective.\nsupersede_read_filter`` is what the storage read gate applies;\n``effective.auto_consolidation`` is what the engine's write-triggered\nconsolidation applies - both trigger sites in ``MemoryEngine._write_inner``\nresolve it through ``_peeked_auto_consolidation``, the same pure function\nthis response uses, so a row saying ``false`` suppresses the pass while the\nfleet flag is on rather than merely being reported here. (Admin-triggered\nconsolidation is an explicit operator action and is out of its scope.)\nWriting ``auto_consolidation: true`` is still refused by the PUT until\nphase 4, so a row can only narrow the fleet default today.\n\nThe row and its history are read in ONE transaction\n(``get_org_settings_with_history``), so the two halves of this response are\none snapshot: a PUT landing mid-request cannot produce ``settings`` from\nbefore the change beside a ``history`` that already lists it.\n\nA ``room_*`` bucket is refused with a typed 400 - see\n``_refuse_room_bucket``; a malformed or oversize id with a typed 400 -\nsee ``_validate_settings_org``.","operationId":"get_org_settings_endpoint_api_v1_admin_org__org_id__settings_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgSettingsResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["admin"],"summary":"Put Org Settings Endpoint","description":"Set (or clear, with an explicit ``null``) either per-org flag.\n\nIdempotent: a request that changes nothing returns ``changed: []`` and\nwrites no audit row - enforced by ``storage.upsert_org_settings`` itself;\nthis route only decides WHICH keys count as \"the caller asked to change\nthis\" (``model_fields_set``) before handing them down, and invalidates\nthe resolver's cached entry for this organisation after a real change so\nthe very next request on this worker sees it. A change to\n``supersede_read_filter`` additionally drops this organisation's concept\nindex (``engine.drop_org_concept_index``), which the resolver\ninvalidation alone would leave at the pre-flip filter state permanently.\n\nPropagation: the change is live immediately on THIS instance, and within\n``ORG_SETTINGS_TTL_SECONDS`` (default 60 s) on every other API instance -\ninvalidation is per-worker, and other workers converge when their cached\nentry expires (core#601 decision R6). There is no fleet-wide invalidation\nand none is needed at this TTL. The concept index converges on the same\nschedule: each worker's next flags refresh compares the resolved value\nagainst the one its index was built under and drops it on a difference\n(``MemoryEngine._note_supersede_state``).\n\nA ``room_*`` bucket is refused with a typed 400 - see\n``_refuse_room_bucket``. ``supersede_read_filter: true`` on a database\nwhose pgvector is older than 0.8 is refused with 409\n``{\"reason\": \"pgvector_iterative_scan_unavailable\"}`` - see the comment at\nthe check itself.\nA malformed or oversize ``org_id`` is refused with a typed 400 - see\n``_validate_settings_org``.","operationId":"put_org_settings_endpoint_api_v1_admin_org__org_id__settings_put","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgSettingsPutRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgSettingsPutResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/llm/providers":{"get":{"tags":["admin"],"summary":"List Llm Providers","description":"Diagnostic: list all LLM providers registered at startup.","operationId":"list_llm_providers_api_v1_admin_llm_providers_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Llm Providers Api V1 Admin Llm Providers Get"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}}}}},"/api/v1/admin/jobs/expire-grace":{"post":{"tags":["admin"],"summary":"Job Expire Grace","description":"Periodic job: scan org_subscriptions for rows past their grace_until.\n\nTwo cases:\n - past_due with grace expired → promoted to suspended (writes blocked)\n - over_limit with grace expired → no status change, but reported for\n observability (write block already happens lazily via SubscriptionGuard)\n\nIdempotent: re-running the job is a no-op for already-suspended rows\nbecause transition_grace_expired only acts on past_due.\n\nDesigned to be called every ~hour by GitHub Actions or Railway cron.","operationId":"job_expire_grace_api_v1_admin_jobs_expire_grace_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraceExpirationResult"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}}}}},"/api/v1/admin/org/{org_id}/stats":{"get":{"tags":["admin"],"summary":"Org Stats","description":"Get memory statistics for a specific organization.","operationId":"org_stats_api_v1_admin_org__org_id__stats_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgStatsResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/org/{org_id}/memories":{"get":{"tags":["admin"],"summary":"Org Memories","description":"Get recent memories for a specific organization.\n\nDirect storage path — does NOT go through `engine.read()` or the\nretrieval pipeline. Previously this endpoint built a\n`ReadRequest(query=\"*\", top_k=50)` and ran the whole classify +\nIRCOT + concept-expansion stack just to surface 10 recent rows\nfor the admin dashboard. That was the only admin endpoint\ntransiting the retrieval engine, and under pool starvation it\nbecame the dominant blast-radius source for the 2026-04-13\nincident (Issue #112).\n\nThe refactored path calls `storage.get_recent_atoms(org_id, limit)`\ndirectly — a single indexed SELECT with P0.1's pool-timeout\nprotection. Response time drops from seconds (or minutes on a\nstarved pool) to single-digit milliseconds.\n\n`limit` is validated to `[1, 50]` at the FastAPI layer via `Query`.\nPreviously `limit` was a bare `int = 10` with only a runtime\n`min(limit, 50)` clamp — a client sending `limit=0` or `limit=-1`\nwould reach Postgres with `LIMIT -1`, which the server treats as\n\"no limit\" on some versions and as a query error on others. Either\nway a misleading response (or a pool-held slow query on a large\ntenant). `Query(ge=1, le=50)` rejects the out-of-range value as\nHTTP 422 before any DB work happens.","operationId":"org_memories_api_v1_admin_org__org_id__memories_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":10,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgMemoriesResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/enterprise/leads":{"post":{"tags":["admin"],"summary":"Create Enterprise Lead","description":"Persist an enterprise sales inquiry. Idempotent only by id (no\nnatural dedup key — the same person may submit twice intentionally).","operationId":"create_enterprise_lead_api_v1_admin_enterprise_leads_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnterpriseLeadRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnterpriseLead"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["admin"],"summary":"List Enterprise Leads","description":"List enterprise leads, newest first. Optional `status_filter` to\nshow only e.g. `new` for the daily review queue.","operationId":"list_enterprise_leads_api_v1_admin_enterprise_leads_get","parameters":[{"name":"status_filter","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status Filter"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnterpriseLead"},"title":"Response List Enterprise Leads Api V1 Admin Enterprise Leads Get"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/ops/status":{"get":{"tags":["admin"],"summary":"Ops Status","description":"Ops dashboard status: build identity, embedding identity vs registry, and\nthe fleet-wide vectorless-atom counters (FAILURE-SURFACE-2026-08-26 P0-1).\n\n* ``embedding_identity`` is the SAME truth ``/health/ready`` reports —\n ``engine._resolve_global_embedding_stamp()``, the actual producing service.\n* ``embedding_registry_active`` is the ``embedding_versions`` active row, read\n on the request pool (the table carries no RLS; boot reads it the same way).\n* The atom counters go through ``storage.admin_ops_atom_counts()`` — the\n BYPASSRLS maintenance route, guarded by ``row_security_active`` on the\n same connection — and are gated by the existing\n ``ADMIN_ATOMS_AGGREGATES_ENABLED`` switch, whose config validation already\n forces a distinct maintenance DSN under multi-tenant auth. Flag off → the\n counters are null with a reason, never zero.\n\nFailures: a database error on any read answers 503 (``MnemoError``,\nretryable) — the dashboard must see \"unknown\", not a 500 and not a number.\nA refused maintenance route (SQLSTATE ``MN001``) is a 503 that names\n``MAINTENANCE_DATABASE_URL``; a pool timeout propagates to the dedicated\n``asyncio.TimeoutError`` handler exactly as in ``aggregate_accounts``.","operationId":"ops_status_api_v1_admin_ops_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpsStatusSchema"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}}}}},"/api/v1/projects":{"get":{"tags":["projects"],"summary":"List Projects","description":"List the authenticated account's own active projects.","operationId":"list_projects_api_v1_projects_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ProjectInfo"},"type":"array","title":"Response List Projects Api V1 Projects Get"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}}}},"post":{"tags":["projects"],"summary":"Create Project","description":"Create a project OWNED by the authenticated account (owner derived from the\nsession, never the body). The portal gatekeeper enforces the per-tier project\ncount before calling this.","operationId":"create_project_api_v1_projects_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectInfo"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}/keys":{"post":{"tags":["projects"],"summary":"Mint Project Key","description":"Mint an API key into a project the authenticated user OWNS. Proofs:\nX-Admin-Key (portal) + a live session, PLUS an ownership check. The key's\norganization_id is the project's storage_org_id; project_id is stamped.","operationId":"mint_project_key_api_v1_projects__project_id__keys_post","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectKeyRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/projects/{project_id}":{"get":{"tags":["projects"],"summary":"Get Project Endpoint","description":"Fetch one of the account's own projects (404 if missing, 403 if not owned).","operationId":"get_project_endpoint_api_v1_projects__project_id__get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectInfo"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["projects"],"summary":"Archive Project Endpoint","description":"Soft-archive an owned project (D4: user-level delete = archive; the bucket's\nDATA is wiped separately by the admin cascade-delete, never by the user).\nIdempotent — archiving an already-archived project returns its archived state.\nHard-delete stays admin-only.","operationId":"archive_project_endpoint_api_v1_projects__project_id__delete","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectInfo"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/rooms":{"get":{"tags":["rooms"],"summary":"List Rooms","description":"List the authenticated account's own active rooms (rooms it owns).","operationId":"list_rooms_api_v1_rooms_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/RoomInfo"},"type":"array","title":"Response List Rooms Api V1 Rooms Get"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}}}},"post":{"tags":["rooms"],"summary":"Create Room","description":"Create a room OWNED by the authenticated account (owner from session).","operationId":"create_room_api_v1_rooms_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRoomRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomInfo"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/rooms/joined":{"get":{"tags":["rooms"],"summary":"List Joined Rooms","description":"List rooms the authenticated account is an active MEMBER of (not owner).","operationId":"list_joined_rooms_api_v1_rooms_joined_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/JoinedRoomInfo"},"type":"array","title":"Response List Joined Rooms Api V1 Rooms Joined Get"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}}}}},"/api/v1/rooms/join":{"post":{"tags":["rooms"],"summary":"Join Room By Code","description":"Redeem a one-time share code and join its room as the authenticated account.\n\nThe joiner is ALWAYS the verified session account (``user_<sub>``), NEVER the\nrequest body — the same anti-spoof invariant as the data-plane\n``/memory/rooms/join``, exposed here on the session-auth management plane so the\nconsole ``/join`` landing can redeem for a signed-in user. The code IS the grant\n(role baked in at mint), so there is no owner gate — anyone signed in with a\nvalid code may join. Idempotent: an account already a member returns\n``already_member=true`` without consuming a use. ``reason`` maps to HTTP status:\nnot_found -> 404; used/expired/revoked -> 409.","operationId":"join_room_by_code_api_v1_rooms_join_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinByCodeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinedByCodeInfo"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/rooms/{room_id}":{"get":{"tags":["rooms"],"summary":"Get Room Endpoint","description":"Fetch one of the account's own rooms (404 if missing, 403 if not owned).","operationId":"get_room_endpoint_api_v1_rooms__room_id__get","parameters":[{"name":"room_id","in":"path","required":true,"schema":{"type":"string","title":"Room Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomInfo"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["rooms"],"summary":"Archive Room Endpoint","description":"Soft-archive an owned room (the bucket's DATA is wiped separately by the\nadmin cascade-delete, never by the user). Idempotent.","operationId":"archive_room_endpoint_api_v1_rooms__room_id__delete","parameters":[{"name":"room_id","in":"path","required":true,"schema":{"type":"string","title":"Room Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomInfo"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/rooms/{room_id}/members":{"post":{"tags":["rooms"],"summary":"Invite Member","description":"Grant another account access to an owned room (owner-gated). The grant is\nstamped ``granted_by`` = the session account — the anti self-grant boundary.","operationId":"invite_member_api_v1_rooms__room_id__members_post","parameters":[{"name":"room_id","in":"path","required":true,"schema":{"type":"string","title":"Room Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteMemberRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberInfo"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["rooms"],"summary":"List Members","description":"List the active members of an owned room (owner-gated).","operationId":"list_members_api_v1_rooms__room_id__members_get","parameters":[{"name":"room_id","in":"path","required":true,"schema":{"type":"string","title":"Room Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MemberInfo"},"title":"Response List Members Api V1 Rooms Room Id Members Get"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/rooms/{room_id}/members/{member_org_id}":{"delete":{"tags":["rooms"],"summary":"Revoke Member","description":"Revoke a member from an owned room (owner-gated, forward-only). Idempotent —\nrevoking an already-inactive grant returns ``revoked=false``.","operationId":"revoke_member_api_v1_rooms__room_id__members__member_org_id__delete","parameters":[{"name":"room_id","in":"path","required":true,"schema":{"type":"string","title":"Room Id"}},{"name":"member_org_id","in":"path","required":true,"schema":{"type":"string","title":"Member Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevokeResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"503":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ActivatePlanEntitlementRequest":{"properties":{"source":{"type":"string","maxLength":64,"minLength":1,"title":"Source"},"tier":{"type":"string","title":"Tier"},"starts_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Starts At"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"base_plan_policy":{"type":"string","enum":["free_only","adopt_unlinked_team"],"title":"Base Plan Policy","default":"free_only"}},"type":"object","required":["source","tier","expires_at"],"title":"ActivatePlanEntitlementRequest"},"AggregateAccountsResponse":{"properties":{"orgs_with_atoms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Orgs With Atoms"},"atoms_total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Atoms Total"},"atoms_unavailable_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Atoms Unavailable Reason"},"orgs_with_active_key":{"type":"integer","title":"Orgs With Active Key"},"orgs_called_30d":{"type":"integer","title":"Orgs Called 30D"},"paying_org_ids":{"items":{"type":"string"},"type":"array","title":"Paying Org Ids"},"paying_truncated":{"type":"boolean","title":"Paying Truncated"},"computed_at":{"type":"string","title":"Computed At"}},"type":"object","required":["orgs_with_atoms","atoms_total","orgs_with_active_key","orgs_called_30d","paying_org_ids","paying_truncated","computed_at"],"title":"AggregateAccountsResponse"},"AggregateTopOrg":{"properties":{"org_id":{"type":"string","title":"Org Id"},"total_queries":{"type":"integer","title":"Total Queries"},"reads":{"type":"integer","title":"Reads"},"writes":{"type":"integer","title":"Writes"},"feedbacks":{"type":"integer","title":"Feedbacks"}},"type":"object","required":["org_id","total_queries","reads","writes","feedbacks"],"title":"AggregateTopOrg"},"AggregateUsageDay":{"properties":{"date":{"type":"string","title":"Date"},"reads":{"type":"integer","title":"Reads"},"writes":{"type":"integer","title":"Writes"},"feedbacks":{"type":"integer","title":"Feedbacks"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["date","reads","writes","feedbacks","total"],"title":"AggregateUsageDay"},"AggregateUsagePeriod":{"properties":{"start_date":{"type":"string","title":"Start Date"},"end_date":{"type":"string","title":"End Date"},"days":{"type":"integer","title":"Days"}},"type":"object","required":["start_date","end_date","days"],"title":"AggregateUsagePeriod"},"AggregateUsageResponse":{"properties":{"period":{"$ref":"#/components/schemas/AggregateUsagePeriod"},"total_reads":{"type":"integer","title":"Total Reads"},"total_writes":{"type":"integer","title":"Total Writes"},"total_feedbacks":{"type":"integer","title":"Total Feedbacks"},"total_queries":{"type":"integer","title":"Total Queries"},"daily":{"items":{"$ref":"#/components/schemas/AggregateUsageDay"},"type":"array","title":"Daily"},"distinct_active_keys":{"type":"integer","title":"Distinct Active Keys"},"distinct_organizations":{"type":"integer","title":"Distinct Organizations"},"top_orgs_by_queries":{"items":{"$ref":"#/components/schemas/AggregateTopOrg"},"type":"array","title":"Top Orgs By Queries"}},"type":"object","required":["period","total_reads","total_writes","total_feedbacks","total_queries","daily","distinct_active_keys","distinct_organizations","top_orgs_by_queries"],"title":"AggregateUsageResponse"},"AtomChainSchema":{"properties":{"atom_id":{"type":"string","format":"uuid","title":"Atom Id","description":"The revision the walk started from."},"revisions":{"items":{"$ref":"#/components/schemas/ChainRevisionSchema"},"type":"array","title":"Revisions","description":"Every revision found, roots to head. Ordered topologically along the supersedes links — a predecessor never follows something that replaced it; creation time decides only between branches the links leave genuinely unordered (e.g. two predecessors consolidated by one successor)."},"dangling":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Dangling","description":"Chain pointers that resolved to nothing — the referenced revision was destroyed by the loud delete handle, or belongs to another tenant. Reported as breaks in the chain rather than raised: the caller already holds these ids, they came off rows the caller can read."},"truncated":{"type":"boolean","title":"Truncated","description":"True when the walk exhausted its lookup budget and stopped early, so `revisions` is a prefix of the chain rather than all of it. The budget counts EVERY lookup — resolved revisions and dangling-pointer misses alike — so a heavily-damaged chain can set this with far fewer than 64 revisions returned; do not infer chain length from it. A cap that truncated silently would let a caller believe they hold the whole history.","default":false}},"type":"object","required":["atom_id","revisions"],"title":"AtomChainSchema","description":"Every revision reachable from one atom by supersession links.\n\n`include_history` grants ELIGIBILITY under ranking — it never promised a\ncomplete chain, and the read schemas say so. This is the handle that does\npromise one. It hydrates through the point read, which resolves any\nrevision regardless of the read-side filter, so a chain is available whether\nor not that filter is enabled: it is a fact about the data."},"AtomDetailSchema":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Atom UUID."},"content":{"type":"string","title":"Content","description":"Stored text content."},"concepts":{"items":{"type":"string"},"type":"array","title":"Concepts","description":"Associated concepts."},"atom_type":{"type":"string","title":"Atom Type","description":"episode, prototype, or singleton."},"created_at":{"type":"string","title":"Created At","description":"ISO 8601 creation timestamp."},"last_accessed_at":{"type":"string","title":"Last Accessed At","description":"ISO 8601 last access timestamp."},"access_count":{"type":"integer","title":"Access Count","description":"Number of times accessed."},"importance":{"type":"number","title":"Importance","description":"Importance score [0, 1]."},"valence":{"type":"number","title":"Valence","description":"Outcome valence [-1, 1]."},"outcome_count":{"type":"integer","title":"Outcome Count","description":"Number of feedback events."},"is_protected":{"type":"boolean","title":"Is Protected","description":"Von Restorff singleton flag."},"domain":{"type":"string","title":"Domain","description":"Domain namespace."},"external_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"External Ref","description":"External reference."},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata","description":"Arbitrary metadata."},"supersedes":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Supersedes","description":"Ids of the atoms this atom replaced. Empty for an unversioned atom."},"superseded_by":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Superseded By","description":"Id of the atom that replaced this one, or null while this is the live tip. A non-null value means this atom is marked superseded; it will be excluded from default reads once read-side filtering (D2) ships, and stays readable here by id either way."}},"type":"object","required":["id","content","concepts","atom_type","created_at","last_accessed_at","access_count","importance","valence","outcome_count","is_protected","domain"],"title":"AtomDetailSchema","description":"Full atom detail (for point reads and debug)."},"ChainRevisionSchema":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Atom UUID of this revision."},"content":{"type":"string","title":"Content","description":"Stored text content of this revision."},"domain":{"type":"string","title":"Domain","description":"Domain the revision is stored in (may differ per revision)."},"concepts":{"items":{"type":"string"},"type":"array","title":"Concepts","description":"Associated concepts."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"UTC creation instant, ISO-8601."},"supersedes":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Supersedes","description":"Ids this revision replaced. OMITTED when it replaced nothing."},"superseded_by":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Superseded By","description":"Id of the revision that replaced this one. OMITTED for the head."},"is_head":{"type":"boolean","title":"Is Head","description":"True for the live tip — the revision no other revision has replaced. False for every historical revision, and false for a revision whose successor was destroyed (its id then appears in `dangling`): a broken chain has no head, and claiming one would rewrite history."}},"type":"object","required":["id","content","domain","created_at","is_head"],"title":"ChainRevisionSchema","description":"One revision inside a supersession chain."},"ConnectorKeyRequest":{"properties":{"tier":{"type":"string","title":"Tier","description":"IGNORED — key inherits the org subscription.","default":"free"},"rate_limit_per_min":{"type":"integer","title":"Rate Limit Per Min","description":"IGNORED — inherited.","default":60},"atom_limit":{"type":"integer","title":"Atom Limit","description":"IGNORED — inherited.","default":10000},"daily_query_limit":{"type":"integer","title":"Daily Query Limit","description":"IGNORED — inherited.","default":1000},"client_label":{"anyOf":[{"type":"string","pattern":"^[a-z0-9_-]{1,32}$"},{"type":"null"}],"title":"Client Label","description":"RS-computed client classification (e.g. 'claude', 'chatgpt'). One logical connection per (user, client_label); NULL = legacy/unknown client."}},"type":"object","title":"ConnectorKeyRequest","description":"Body for ``POST /admin/keys/connector``.\n\nNOTE: ``tier`` / ``rate_limit_per_min`` / ``atom_limit`` / ``daily_query_limit``\nare now IGNORED — kept only for wire compatibility with older RS builds. The\nminted key inherits the org subscription instead (see ``create_connector_key``).\nUnknown extra body fields are ignored too (Pydantic default), so newer RS\nbuilds can add fields without 422-ing older cores."},"ConsolidateRequestSchema":{"properties":{"domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Domain","description":"Domain to consolidate (null = general)."}},"type":"object","title":"ConsolidateRequestSchema","description":"Request body for guarded soft sleep consolidation.","examples":[{"domain":"arc"},{}]},"ConsolidationResponseSchema":{"properties":{"domain":{"type":"string","title":"Domain","description":"Domain that was consolidated."},"atoms_before":{"type":"integer","title":"Atoms Before","description":"Number of atoms before consolidation."},"atoms_after":{"type":"integer","title":"Atoms After","description":"Logical survivors after clustering; not physical row count in soft mode."},"prototypes_created":{"type":"integer","title":"Prototypes Created","description":"Number of new prototype atoms created."},"singletons_protected":{"type":"integer","title":"Singletons Protected","description":"Number of Von Restorff-protected singletons."},"compression_ratio":{"type":"number","title":"Compression Ratio","description":"Logical survivor ratio atoms_after/atoms_before (0..1)."},"duration_ms":{"type":"number","title":"Duration Ms","description":"Consolidation duration in milliseconds."}},"type":"object","required":["domain","atoms_before","atoms_after","prototypes_created","singletons_protected","compression_ratio","duration_ms"],"title":"ConsolidationResponseSchema","description":"Response after running consolidation."},"CreateEnterpriseLeadRequest":{"properties":{"name":{"type":"string","maxLength":200,"minLength":1,"title":"Name"},"email":{"type":"string","maxLength":320,"minLength":3,"title":"Email"},"company":{"type":"string","maxLength":200,"minLength":1,"title":"Company"},"use_case":{"type":"string","maxLength":5000,"minLength":10,"title":"Use Case"},"expected_volume":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Expected Volume"},"session_email":{"anyOf":[{"type":"string","maxLength":320},{"type":"null"}],"title":"Session Email","description":"Email of the logged-in dashboard user submitting the form (may differ from `email`)."},"source":{"type":"string","maxLength":64,"title":"Source","default":"dashboard_form"}},"type":"object","required":["name","email","company","use_case"],"title":"CreateEnterpriseLeadRequest"},"CreateInviteRequestSchema":{"properties":{"scope":{"type":"string","title":"Scope","description":"Role baked into the invite: 'read' or 'read_write'.","default":"read_write"},"expires_in_days":{"type":"integer","maximum":90.0,"minimum":1.0,"title":"Expires In Days","description":"Days until the code expires (default 7).","default":7},"max_uses":{"type":"integer","maximum":1000.0,"minimum":1.0,"title":"Max Uses","description":"How many accounts may redeem it (default 1).","default":1}},"additionalProperties":false,"type":"object","title":"CreateInviteRequestSchema","description":"Body for minting a room invite (Rooms Wave 2b). The role is fixed HERE, at\nmint — the redeemer never chooses it. No target account: the invite is a\nbearer code anyone can redeem into their OWN membership."},"CreateKeyRequest":{"properties":{"name":{"type":"string","title":"Name","description":"Human-readable key name."},"organization_id":{"type":"string","title":"Organization Id","description":"Organization ID this key belongs to."},"tier":{"type":"string","title":"Tier","description":"Pricing tier: free, pro, enterprise.","default":"free"},"rate_limit_per_min":{"type":"integer","title":"Rate Limit Per Min","description":"Requests per minute.","default":60},"atom_limit":{"type":"integer","title":"Atom Limit","description":"Max atoms stored.","default":10000},"daily_query_limit":{"type":"integer","title":"Daily Query Limit","description":"Max queries per day.","default":1000}},"type":"object","required":["name","organization_id"],"title":"CreateKeyRequest"},"CreateKeyResponse":{"properties":{"id":{"type":"string","title":"Id"},"key":{"type":"string","title":"Key","description":"Full API key — returned only once."},"key_prefix":{"type":"string","title":"Key Prefix"},"organization_id":{"type":"string","title":"Organization Id"},"tier":{"type":"string","title":"Tier"}},"type":"object","required":["id","key","key_prefix","organization_id","tier"],"title":"CreateKeyResponse"},"CreateProjectRequest":{"properties":{"name":{"type":"string","title":"Name","description":"Project name (unique within the account)."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["name"],"title":"CreateProjectRequest"},"CreateRoomRequest":{"properties":{"name":{"type":"string","title":"Name","description":"Room name (unique within the owner account)."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["name"],"title":"CreateRoomRequest"},"CreateRoomRequestSchema":{"properties":{"name":{"type":"string","maxLength":200,"minLength":1,"title":"Name","description":"Room name (unique within your account)."},"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Description","description":"Optional human description."}},"additionalProperties":false,"type":"object","required":["name"],"title":"CreateRoomRequestSchema","description":"Body for an agent creating a room with its own tenant key (Rooms Wave 2).\n\nDeliberately has NO ``owner_org_id`` — the owner is derived from the\nauthenticated key's claims, never the request body (anti-self-grant, the\nsame invariant the portal path enforces from the session). ``extra=\"forbid\"``\nrejects a smuggled ``owner_org_id`` outright."},"CreateSecretRequest":{"properties":{"alias":{"type":"string","maxLength":200,"minLength":1,"pattern":"^[A-Za-z0-9._-]+$","title":"Alias","description":"Human alias, unique per org. Path-safe chars only (A-Z a-z 0-9 . _ -)."},"context":{"type":"string","maxLength":10000,"title":"Context","description":"In-clear routing/usage context — embedded + searchable memory."},"sealed_secret_b64":{"type":"string","maxLength":262144,"title":"Sealed Secret B64","description":"Base64 of the envelope-encrypted value bytes."},"concepts":{"items":{"type":"string"},"type":"array","title":"Concepts"},"domain":{"type":"string","title":"Domain","default":"secrets"},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata"}},"type":"object","required":["alias","context","sealed_secret_b64"],"title":"CreateSecretRequest"},"CreateSecretResponse":{"properties":{"atom_id":{"type":"string","title":"Atom Id"},"alias":{"type":"string","title":"Alias"}},"type":"object","required":["atom_id","alias"],"title":"CreateSecretResponse"},"DeleteOrgResponse":{"properties":{"organization_id":{"type":"string","title":"Organization Id"},"deleted":{"additionalProperties":{"type":"integer"},"type":"object","title":"Deleted","description":"Cascade delete counts per resource. {atoms, hebbian_edges, fingerprints, keys_revoked, org_subscriptions, usage_daily, org_settings, org_settings_audit}."}},"type":"object","required":["organization_id","deleted"],"title":"DeleteOrgResponse"},"EmbeddingIdentitySchema":{"properties":{"model":{"type":"string","title":"Model","description":"Model id of the actual producing global EmbeddingService."},"dim":{"type":"integer","title":"Dim","description":"Effective output dimension (post-Matryoshka truncation)."}},"type":"object","required":["model","dim"],"title":"EmbeddingIdentitySchema","description":"Resolved GLOBAL embedding identity — the server-truth for provenance stamping.\n\nExposes ONLY the model id and effective dimension (model names are not\nsecrets); never api_url, key material, or backend internals."},"EmbeddingModelResponse":{"properties":{"organization_id":{"type":"string","title":"Organization Id"},"embedding_model_default":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Embedding Model Default"},"embedding_dim_default":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Embedding Dim Default"},"embedding_backend_default":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Embedding Backend Default"},"effective":{"type":"boolean","title":"Effective","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"}},"type":"object","required":["organization_id","embedding_model_default","embedding_dim_default","embedding_backend_default"],"title":"EmbeddingModelResponse"},"EmbeddingRegistryActiveSchema":{"properties":{"model_name":{"type":"string","title":"Model Name","description":"Registry model id of the active row."},"dim":{"type":"integer","title":"Dim","description":"Registry dimension of the active row."},"backend":{"type":"string","title":"Backend","description":"Registry backend of the active row: api | local | mock."}},"type":"object","required":["model_name","dim","backend"],"title":"EmbeddingRegistryActiveSchema","description":"The ACTIVE row of the ``embedding_versions`` registry (fleet-level SSOT).\n\nSame three columns migration 018 keys the table on; never ``api_url``."},"EndPlanEntitlementRequest":{"properties":{"source":{"type":"string","maxLength":64,"minLength":1,"title":"Source"},"tier":{"type":"string","title":"Tier"},"reason":{"type":"string","maxLength":64,"minLength":1,"title":"Reason"},"ended_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ended At"}},"type":"object","required":["source","tier","reason"],"title":"EndPlanEntitlementRequest"},"EnterpriseLead":{"properties":{"id":{"type":"string","title":"Id"},"created_at":{"type":"string","title":"Created At"},"name":{"type":"string","title":"Name"},"email":{"type":"string","title":"Email"},"company":{"type":"string","title":"Company"},"use_case":{"type":"string","title":"Use Case"},"expected_volume":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expected Volume"},"session_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Session Email"},"source":{"type":"string","title":"Source"},"status":{"type":"string","title":"Status"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["id","created_at","name","email","company","use_case","expected_volume","session_email","source","status","notes"],"title":"EnterpriseLead"},"ErrorResponseSchema":{"properties":{"code":{"type":"string","title":"Code","description":"Machine-readable error code (e.g. VALIDATION_ERROR)."},"message":{"type":"string","title":"Message","description":"Human-readable error description."},"requestId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requestid","description":"Correlation ID from X-Request-Id header."},"retryable":{"type":"boolean","title":"Retryable","description":"True if the client should retry the request.","default":false},"details":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Details","description":"Optional structured details."}},"type":"object","required":["code","message"],"title":"ErrorResponseSchema","description":"Unified JSON error response body (for OpenAPI docs)."},"ExternalRefRequestSchema":{"properties":{"external_ref":{"type":"string","maxLength":255,"minLength":1,"title":"External Ref","description":"External reference to resolve."}},"type":"object","required":["external_ref"],"title":"ExternalRefRequestSchema","description":"Resolve atom by external reference."},"FeedbackRequestSchema":{"properties":{"atom_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Atom Ids","description":"UUIDs of atoms to update with this outcome."},"outcome":{"type":"number","maximum":1.0,"minimum":-1.0,"title":"Outcome","description":"Outcome signal: -1 (failure) to +1 (success)."},"concepts":{"items":{"type":"string"},"type":"array","title":"Concepts","description":"Concepts to reinforce (Hebbian) with this outcome."},"query_concepts":{"items":{"type":"string"},"type":"array","title":"Query Concepts","description":"Concepts from the original query (from read result query_concepts). Enables feedback-driven co-activation: links query concepts with used atom concepts, modulated by outcome signal (stigmergy)."},"domain":{"type":"string","title":"Domain","description":"Domain for the feedback.","default":"general"}},"type":"object","required":["atom_ids","outcome"],"title":"FeedbackRequestSchema","description":"Request body for reporting outcome (success/failure) for atoms.","examples":[{"atom_ids":["550e8400-e29b-41d4-a716-446655440000"],"concepts":["rotation","symmetry"],"domain":"arc","outcome":0.8}]},"FeedbackResponseSchema":{"properties":{"updated_count":{"type":"integer","title":"Updated Count","description":"Number of atoms whose valence was updated. SYNC mode (feedback_async=False): the real count of atoms that actually existed and were updated (missing atom_ids are skipped). ASYNC mode (feedback_async=True): a best-effort ACCEPTED-count estimate — the number of atom_ids submitted — since the authoritative count isn't known until the background worker runs."},"avg_valence":{"type":"number","title":"Avg Valence","description":"Average valence of updated atoms after the update. SYNC mode: the real post-update average. ASYNC mode: always 0 in the enqueue ack (the value is computed later on the worker, not returned here)."},"coactivation_edges":{"type":"integer","title":"Coactivation Edges","description":"Number of Hebbian edges created/updated by feedback-driven co-activation. SYNC mode: the real edge count. ASYNC mode: always 0 in the enqueue ack (computed later on the worker).","default":0},"feedback_time_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Feedback Time Ms","description":"Server wall time of the feedback pipeline in ms (TRACING_SPEC §4). Optional in the schema for client back-compat but always populated by the route."}},"type":"object","required":["updated_count","avg_valence"],"title":"FeedbackResponseSchema","description":"Response after applying feedback."},"GraceExpirationResult":{"properties":{"scanned":{"type":"integer","title":"Scanned","description":"Rows past their grace_until"},"promoted":{"type":"integer","title":"Promoted","description":"past_due → suspended transitions written"},"over_limit_expired":{"type":"integer","title":"Over Limit Expired","description":"over_limit rows whose grace expired (writes now blocked lazily)"}},"type":"object","required":["scanned","promoted","over_limit_expired"],"title":"GraceExpirationResult"},"GraphEdgeSchema":{"properties":{"source":{"type":"string","title":"Source","description":"Source concept (storage order, not learn order)."},"target":{"type":"string","title":"Target","description":"Target concept (storage order, not learn order)."},"weight":{"type":"number","title":"Weight","description":"Co-activation strength, [0, max_weight]."},"valence":{"type":"number","title":"Valence","description":"Outcome polarity, [-1, +1]."},"count":{"type":"integer","title":"Count","description":"Co-activation count."},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"UTC instant this edge was last reinforced."}},"type":"object","required":["source","target","weight","valence","count","updated_at"],"title":"GraphEdgeSchema","description":"One association edge, as stored in `mnemo.hebbian_edges`.\n\nUndirected by construction: `sync_hebbian_edges` persists exactly one row\nper unordered concept pair (`hebbian.py` dedupes on `(min(a,b), max(a,b))`\nbefore flush), so `source`/`target` reflect storage order, not the order\nconcepts were learned in. core#630's open question (\"directed pairs or\ncollapsed to one undirected edge per pair?\") is answered by this existing\ninvariant — there is only ever one row per pair to report."},"GraphNodeSchema":{"properties":{"concept":{"type":"string","title":"Concept","description":"The concept name."},"degree":{"type":"integer","title":"Degree","description":"Number of returned edges touching this concept — a property of THIS response's edge set, not the concept's total degree across the org's whole graph (which `limit`/`truncated` may cut short)."}},"type":"object","required":["concept","degree"],"title":"GraphNodeSchema","description":"One concept in the returned association graph."},"GraphRequestSchema":{"properties":{"seeds":{"items":{"type":"string"},"type":"array","maxItems":20,"minItems":1,"title":"Seeds","description":"Concept names to center the graph on. 1-20 items, each at most 200 characters (the `VARCHAR(200)` width of hebbian_edges.source_concept/target_concept — a longer string can never match a stored concept)."},"depth":{"type":"integer","maximum":3.0,"minimum":1.0,"title":"Depth","description":"Hop count from the seeds. depth=1 returns only edges touching a seed directly; depth=2/3 walk further, one hop per level. Each hop is independently bounded server-side by a per-hop row cap (see `truncated`). When `min_weight` is null AND this REQUESTED depth is >= 2, EVERY hop of the walk — including the first, hop 0 — floors the edge weight at 0.05 (reported back as `min_weight_applied`), so an unfiltered multi-hop walk from a hub concept cannot fan out across an org's whole graph before `limit` ever applies, and a depth=2 request cannot return a direct seed edge the floor would otherwise have excluded one hop later. An EXPLICIT `min_weight` (including `0.0`) is honoured at every hop instead, with no server override.","default":1},"domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Domain","description":"Same mechanism as /memory/read, not a filter over one org's edges: an `xroom:<room_id>` value resolves (after the membership/scope check) to that ROOM's own storage bucket, so the graph is read from the room's `hebbian_edges` rows instead of the caller's own — this is NOT inert. Any other value (or null) IS inert: `hebbian_edges` has no `domain` column, so a plain domain string does not narrow which edges/atoms count — it has the same effect as omitting the field entirely."},"min_weight":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Min Weight","description":"Drop edges below this weight. null = no caller-supplied floor at depth 1; when the REQUESTED depth is >= 2, the server applies its own floor (0.05, see `depth`) at every hop of the walk, including hop 0 — reported back as `min_weight_applied`. An EXPLICIT value (including `0.0`) is honoured at EVERY hop with no server override, so `min_weight=0.0` at depth>=2 really does return every edge down to weight 0."},"limit":{"type":"integer","maximum":500.0,"minimum":1.0,"title":"Limit","description":"Maximum number of edges to return. Mirrors ReadRequestSchema.top_k's bounds.","default":100}},"additionalProperties":false,"type":"object","required":["seeds"],"title":"GraphRequestSchema","description":"Request body for the bounded concept-association-graph read.\n\nNew endpoint, no back-compat surface yet, so `extra=\"forbid\"` rejects an\nunknown field outright rather than silently dropping it (unlike\n`ReadRequestSchema`, which predates that convention and cannot adopt it\nnow without breaking older clients — see the note on `include_history`).","examples":[{"depth":1,"limit":100,"seeds":["rotation","symmetry"]}]},"GraphResponseSchema":{"properties":{"nodes":{"items":{"$ref":"#/components/schemas/GraphNodeSchema"},"type":"array","title":"Nodes","description":"Concepts touched by `edges` below. A seed with no surviving edge (unknown concept, or every edge fell below `min_weight`) is NOT listed — nodes are derived from the returned edges, not echoed from the request."},"edges":{"items":{"$ref":"#/components/schemas/GraphEdgeSchema"},"type":"array","title":"Edges","description":"Association edges found within `depth` hops."},"truncated":{"type":"boolean","title":"Truncated","description":"True when either a per-hop server-side cap or the request's `limit` cut the walk short — the graph may hold more edges than are reported here."},"min_weight_applied":{"type":"number","title":"Min Weight Applied","description":"The weight floor actually used at EVERY hop of the walk. Equal to the request's `min_weight` when it was set (an explicit value, including `0.0`, is never overridden); equal to the server floor 0.05 when the request left `min_weight` null and the REQUESTED `depth` was >= 2 (applied from hop 0 onward, not just hop 1 onward); equal to `0.0` when it was null and `depth == 1`."}},"type":"object","required":["nodes","edges","truncated","min_weight_applied"],"title":"GraphResponseSchema","description":"Response from the bounded concept-association-graph read.","example":{"edges":[{"count":3,"source":"rotation","target":"symmetry","updated_at":"2026-09-24T00:00:00Z","valence":0.1,"weight":0.8}],"min_weight_applied":0.0,"nodes":[{"concept":"rotation","degree":1},{"concept":"symmetry","degree":1}],"truncated":false}},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthResponseSchema":{"properties":{"status":{"type":"string","title":"Status","description":"ok, degraded, or error."},"database":{"type":"boolean","title":"Database","description":"True if database connection is healthy."},"version":{"type":"string","title":"Version","description":"Application version string."}},"type":"object","required":["status","database","version"],"title":"HealthResponseSchema","description":"Health check response."},"InviteCreatedSchema":{"properties":{"invite_id":{"type":"string","title":"Invite Id","description":"Audit id of the invite (inv_<ulid>)."},"code":{"type":"string","title":"Code","description":"The shareable one-time code (mnvr_...). Shown once."},"room_address":{"type":"string","title":"Room Address","description":"The room's domain address: xroom:<room_id>."},"scope":{"type":"string","title":"Scope","description":"Role the redeemer will get."},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At","description":"ISO 8601 expiry, or null."},"join_url":{"type":"string","title":"Join Url","description":"Landing URL a human can open to join."},"share_message":{"type":"string","title":"Share Message","description":"Ready-to-forward invite text."}},"type":"object","required":["invite_id","code","room_address","scope","expires_at","join_url","share_message"],"title":"InviteCreatedSchema","description":"Response when an invite is minted — the ONLY time the raw code is returned.\n``share_message`` is a ready-to-forward text (agents/humans paste it into any\nchat)."},"InviteInfoSchema":{"properties":{"invite_id":{"type":"string","title":"Invite Id","description":"Audit id."},"scope":{"type":"string","title":"Scope","description":"Role granted on redeem."},"max_uses":{"type":"integer","title":"Max Uses","description":"Allowed redemptions."},"uses":{"type":"integer","title":"Uses","description":"Redemptions so far."},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At","description":"ISO 8601 expiry, or null."},"revoked_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revoked At","description":"ISO 8601 revoke time, or null (active)."},"created_at":{"type":"string","title":"Created At","description":"ISO 8601 mint time."}},"type":"object","required":["invite_id","scope","max_uses","uses","expires_at","revoked_at","created_at"],"title":"InviteInfoSchema","description":"One invite in an owner's list — audit fields only, never the code/hash."},"InviteMemberRequest":{"properties":{"member_org_id":{"type":"string","title":"Member Org Id","description":"The invited account's org id (e.g. user_<sub>)."},"scope":{"type":"string","title":"Scope","description":"'read' or 'read_write'.","default":"read_write"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"Optional TTL; null = revocable, no expiry."}},"type":"object","required":["member_org_id"],"title":"InviteMemberRequest"},"JoinByCodeRequest":{"properties":{"code":{"type":"string","title":"Code","description":"One-time share code (starts with 'mnvr_')."}},"type":"object","required":["code"],"title":"JoinByCodeRequest"},"JoinRoomRequestSchema":{"properties":{"code":{"type":"string","maxLength":200,"minLength":1,"title":"Code","description":"The invite code (mnvr_...)."}},"additionalProperties":false,"type":"object","required":["code"],"title":"JoinRoomRequestSchema","description":"Body for redeeming an invite code — the joiner becomes a member of the\ninvite's room with the invite's role. The joiner is derived from the caller's\nkey, never the body; only the code is supplied."},"JoinedByCodeInfo":{"properties":{"room_id":{"type":"string","title":"Room Id"},"name":{"type":"string","title":"Name"},"scope":{"type":"string","title":"Scope"},"already_member":{"type":"boolean","title":"Already Member"}},"type":"object","required":["room_id","name","scope","already_member"],"title":"JoinedByCodeInfo"},"JoinedRoomInfo":{"properties":{"room_id":{"type":"string","title":"Room Id"},"name":{"type":"string","title":"Name"},"owner_org_id":{"type":"string","title":"Owner Org Id"},"scope":{"type":"string","title":"Scope"}},"type":"object","required":["room_id","name","owner_org_id","scope"],"title":"JoinedRoomInfo"},"JoinedRoomSchema":{"properties":{"room_id":{"type":"string","title":"Room Id","description":"The room's public id."},"address":{"type":"string","title":"Address","description":"Ready-to-use domain address: xroom:<room_id>."},"name":{"type":"string","title":"Name","description":"The room name."},"scope":{"type":"string","title":"Scope","description":"Your role in the room."},"already_member":{"type":"boolean","title":"Already Member","description":"True if you were already a member (no-op)."},"next_steps":{"type":"string","title":"Next Steps","description":"How to use the room now."}},"type":"object","required":["room_id","address","name","scope","already_member","next_steps"],"title":"JoinedRoomSchema","description":"Response after redeeming — the room is now usable at ``address``."},"KeyInfo":{"properties":{"id":{"type":"string","title":"Id"},"key_prefix":{"type":"string","title":"Key Prefix"},"name":{"type":"string","title":"Name"},"organization_id":{"type":"string","title":"Organization Id"},"tier":{"type":"string","title":"Tier"},"rate_limit_per_min":{"type":"integer","title":"Rate Limit Per Min"},"atom_limit":{"type":"integer","title":"Atom Limit"},"daily_query_limit":{"type":"integer","title":"Daily Query Limit"},"is_active":{"type":"boolean","title":"Is Active"},"created_at":{"type":"string","title":"Created At"},"last_used_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Used At"},"client_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Label"}},"type":"object","required":["id","key_prefix","name","organization_id","tier","rate_limit_per_min","atom_limit","daily_query_limit","is_active","created_at","last_used_at"],"title":"KeyInfo"},"LLMProviderResponse":{"properties":{"organization_id":{"type":"string","title":"Organization Id"},"llm_provider_default":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Llm Provider Default"},"effective_provider":{"type":"string","title":"Effective Provider"}},"type":"object","required":["organization_id","llm_provider_default","effective_provider"],"title":"LLMProviderResponse"},"ListSecretsResponse":{"properties":{"secrets":{"items":{"$ref":"#/components/schemas/SecretSummary"},"type":"array","title":"Secrets"}},"type":"object","required":["secrets"],"title":"ListSecretsResponse"},"MemberInfo":{"properties":{"member_org_id":{"type":"string","title":"Member Org Id"},"scope":{"type":"string","title":"Scope"}},"type":"object","required":["member_org_id","scope"],"title":"MemberInfo"},"MemoryItemSchema":{"properties":{"atom_id":{"type":"string","format":"uuid","title":"Atom Id","description":"Unique identifier of the atom."},"content":{"type":"string","title":"Content","description":"Stored text content of the memory."},"relevance":{"type":"number","title":"Relevance","description":"Final score after valence modulation: score * (1 + alpha * v)."},"similarity":{"type":"number","title":"Similarity","description":"Raw cosine similarity from pgvector search."},"valence":{"type":"number","title":"Valence","description":"Outcome polarity [-1, +1]: positive = successful, negative = failed."},"importance":{"type":"number","title":"Importance","description":"Importance score in [0, 1] from L4 gate."},"source":{"type":"string","title":"Source","description":"Retrieval stage that found this item. Production reads return semantic, concept_scoped (found under a concept extracted from the query) and hebbian_retrieval (missed by the direct stages and reached through learned associations, via a concept the query did not name); episodic marks an exact fingerprint match. Other stage names can appear: treat an unknown value as one more stage."},"concepts":{"items":{"type":"string"},"type":"array","title":"Concepts","description":"Concepts associated with this atom."},"domain":{"type":"string","title":"Domain","description":"Domain/namespace of the atom."},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata","description":"Arbitrary key-value metadata."},"provenance":{"anyOf":[{"$ref":"#/components/schemas/ProvenanceSchema"},{"type":"null"}],"description":"Server-stamped authorship (CN-001). Present only when the atom has recorded authorship; OMITTED entirely for legacy/unauthored atoms (mirrors the timings-omission pattern), so the default payload is unchanged for existing clients."},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"UTC creation instant of the atom, ISO-8601 (#404 R1). OMITTED for legacy atoms that predate timestamping — same omission pattern as `provenance`, so their payload shape is unchanged."},"supersedes":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Supersedes","description":"Ids of the revisions this item replaced. OMITTED when this item replaced nothing."},"superseded_by":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Superseded By","description":"Id of the revision that replaced this one. OMITTED while this item is the live tip. Present means the item is history — reported as a fact of the data regardless of server settings: while the read-side supersession filter is off, ordinary reads still return replaced revisions and this field is how you tell. Once the filter is on, history reaches a read only via `include_history`. The id names the IMMEDIATE successor as of the moment of replacement and carries no FK — if that successor was later destroyed, a GET on it is a documented 404, and `GET /memory/atoms/{id}/chain` reports the break rather than failing."}},"type":"object","required":["atom_id","content","relevance","similarity","valence","importance","source","concepts","domain"],"title":"MemoryItemSchema","description":"Single memory item returned from a read query."},"MetadataFilterSchema":{"properties":{"key":{"type":"string","maxLength":64,"pattern":"^[a-zA-Z_][a-zA-Z0-9_]*$","title":"Key","description":"Metadata key to filter on."},"op":{"type":"string","pattern":"^(eq|contains|in)$","title":"Op","description":"Operator: eq, contains, in.","default":"eq"},"value":{"title":"Value","description":"Value to compare against."}},"type":"object","required":["key","value"],"title":"MetadataFilterSchema","description":"Single metadata filter condition."},"OpsAtomsByModelSchema":{"properties":{"model":{"type":"string","title":"Model","description":"Stamped embedding_model, or the literal '<null>' for unstamped atoms."},"dim":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Dim","description":"Stamped embedding_dim; null when unstamped."},"count":{"type":"integer","title":"Count","description":"Atoms in this bucket (fleet-wide, every org)."}},"type":"object","required":["model","dim","count"],"title":"OpsAtomsByModelSchema","description":"One ``(embedding_model, embedding_dim)`` bucket of the atoms table."},"OpsAxiomSchema":{"properties":{"batches_rejected":{"type":"integer","title":"Batches Rejected","description":"Batches Axiom 400'd for the field-limit that salvage could not recover."},"batches_salvaged":{"type":"integer","title":"Batches Salvaged","description":"Batches Axiom 400'd for the field-limit that salvage DID recover."},"events_dropped":{"type":"integer","title":"Events Dropped","description":"Total events lost across every dropped (not salvaged) batch."},"last_rejected_field":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Rejected Field","description":"Field named in the most recent field-limit 400; null if none seen yet."},"last_rejected_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Rejected At","description":"ISO-8601 UTC timestamp of that field-limit 400; null if none seen yet. Never advanced by an unparseable 400; see last_unparseable_at."},"last_unparseable_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Unparseable At","description":"ISO-8601 UTC timestamp of the most recent 400 that was NOT a field-limit rejection (its body did not name a field); null if none seen yet. Independent of last_rejected_at."}},"type":"object","required":["batches_rejected","batches_salvaged","events_dropped","last_rejected_field","last_rejected_at","last_unparseable_at"],"title":"OpsAxiomSchema","description":"Axiom log-shipper rejection counters (`mnemo.api.axiom.AxiomShipper`).\n\nA batch that gets Axiom's field-limit 400 either recovers through the\nbounded salvage pass (`batches_salvaged`) or is dropped whole\n(`batches_rejected`, `events_dropped`). `last_rejected_field` /\n`last_rejected_at` name the most recent field-limit 400 seen, salvaged\nor not: the operator hint for when it's time to regenerate\n`KNOWN_COLUMNS` (`scripts/fetch_axiom_columns.py --write`).\n`last_unparseable_at` is independent of that pair: an unparseable 400\n(not a field-limit rejection at all) never touches\n`last_rejected_field`/`last_rejected_at`, so those two always describe\nthe same event and never pair an old field with an unrelated newer\ntimestamp."},"OpsDbPoolSchema":{"properties":{"pool_size":{"type":"integer","title":"Pool Size","description":"Connections currently open in the request pool."},"pool_free":{"type":"integer","title":"Pool Free","description":"Of those, connections idle right now."}},"type":"object","required":["pool_size","pool_free"],"title":"OpsDbPoolSchema","description":"Request-pool occupancy, read from asyncpg without touching the database."},"OpsStatusSchema":{"properties":{"git_sha":{"type":"string","title":"Git Sha","description":"Git commit SHA of the running build ('unknown' locally)."},"version":{"type":"string","title":"Version","description":"Application version string."},"uptime_s":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Uptime S","description":"Seconds since this process finished startup; null if the mark is missing."},"embedding_identity":{"$ref":"#/components/schemas/EmbeddingIdentitySchema","description":"Resolved GLOBAL embedding identity of THIS server — the same source /health/ready reports (the actual producing EmbeddingService)."},"embedding_registry_active":{"anyOf":[{"$ref":"#/components/schemas/EmbeddingRegistryActiveSchema"},{"type":"null"}],"description":"Active embedding_versions row; null when the registry has no active row."},"registry_matches_identity":{"type":"boolean","title":"Registry Matches Identity","description":"True iff the registry's active (model_name, dim) equals the live embedding_identity. False when the registry has no active row."},"atoms_total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Atoms Total","description":"Atoms across ALL organizations; null when the counters are unavailable."},"atoms_vectorless_total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Atoms Vectorless Total","description":"Atoms with EVERY vector column NULL (embedding IS NULL AND embedding_1536 IS NULL) — the sensor's headline number. Null when unavailable."},"atoms_vectorless_last_1h":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Atoms Vectorless Last 1H","description":"Vectorless atoms created in the last hour (created_at > now() - 1h)."},"atoms_by_model":{"items":{"$ref":"#/components/schemas/OpsAtomsByModelSchema"},"type":"array","title":"Atoms By Model","description":"Top-5 (embedding_model, embedding_dim) buckets by count; empty when unavailable."},"atoms_unavailable_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Atoms Unavailable Reason","description":"Set iff the atom counters are null: why, in one line."},"db":{"anyOf":[{"$ref":"#/components/schemas/OpsDbPoolSchema"},{"type":"null"}],"description":"Request-pool occupancy when the pool exposes it cheaply; omitted otherwise."},"axiom":{"anyOf":[{"$ref":"#/components/schemas/OpsAxiomSchema"},{"type":"null"}],"description":"Axiom log-shipper rejection counters; null when no shipper is installed."},"generated_at":{"type":"string","title":"Generated At","description":"ISO-8601 UTC timestamp of this response."}},"type":"object","required":["git_sha","version","uptime_s","embedding_identity","embedding_registry_active","registry_matches_identity","atoms_total","atoms_vectorless_total","atoms_vectorless_last_1h","generated_at"],"title":"OpsStatusSchema","description":"``GET /admin/ops/status`` — one source of truth for the ops dashboard and\nfor the \"atoms without a vector\" sensor (FAILURE-SURFACE-2026-08-26, P0-1).\n\nCounters and identities only: no atom content, no key material, no DSNs.\nThe atom counters are NULLABLE on purpose, with ``atoms_unavailable_reason``\nset whenever they are null — a fallback zero would read as \"all good\", which\nis the exact false negative the sensor exists to catch."},"OrgMemoriesResponse":{"properties":{"organization_id":{"type":"string","title":"Organization Id"},"items":{"items":{"$ref":"#/components/schemas/OrgMemoryItem"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["organization_id","items","total"],"title":"OrgMemoriesResponse"},"OrgMemoryItem":{"properties":{"atom_id":{"type":"string","title":"Atom Id"},"content":{"type":"string","title":"Content"},"concepts":{"items":{"type":"string"},"type":"array","title":"Concepts"},"domain":{"type":"string","title":"Domain"},"importance":{"type":"number","title":"Importance"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["atom_id","content","concepts","domain","importance"],"title":"OrgMemoryItem"},"OrgSettingsChangedEntry":{"properties":{"field":{"type":"string","title":"Field"},"old":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Old"},"new":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"New"}},"type":"object","required":["field","old","new"],"title":"OrgSettingsChangedEntry"},"OrgSettingsEffective":{"properties":{"supersede_read_filter":{"type":"boolean","title":"Supersede Read Filter"},"auto_consolidation":{"type":"boolean","title":"Auto Consolidation"}},"type":"object","required":["supersede_read_filter","auto_consolidation"],"title":"OrgSettingsEffective","description":"What this organisation's requests actually do, not what is stored.\n\n``supersede_read_filter`` is the value the storage read gate applies\n(``MemoryEngine._supersede_read_filter_on`` / ``_peeked_supersede``).\n\n``auto_consolidation`` is the value the engine's write-triggered\nconsolidation pass applies (``MemoryEngine._peeked_auto_consolidation``,\nconsulted at both ``_write_inner`` trigger sites): every\n``CONSOLIDATION_PERIOD``-th write in this organisation spawns a background\nconsolidation when this is true, and none when it is false. A row saying\n``false`` therefore suppresses the pass even while the fleet flag is on -\nit is an enforced opt-out, not a display value. It does NOT describe the\nadmin-triggered consolidation endpoints, which are explicit operator\nactions and run regardless."},"OrgSettingsHistoryEntry":{"properties":{"field":{"type":"string","title":"Field"},"old":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Old"},"new":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"New"},"changed_at":{"type":"string","format":"date-time","title":"Changed At"},"changed_by":{"type":"string","title":"Changed By"},"actor_kind":{"type":"string","title":"Actor Kind"}},"type":"object","required":["field","old","new","changed_at","changed_by","actor_kind"],"title":"OrgSettingsHistoryEntry"},"OrgSettingsPutRequest":{"properties":{"supersede_read_filter":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Supersede Read Filter"},"auto_consolidation":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Auto Consolidation"},"changed_by":{"type":"string","maxLength":200,"minLength":1,"title":"Changed By"},"actor_kind":{"type":"string","enum":["customer","staff"],"title":"Actor Kind"}},"type":"object","required":["changed_by","actor_kind"],"title":"OrgSettingsPutRequest","description":"Every setting key is OPTIONAL, but at least one must be present in the\nbody - the route checks ``model_fields_set``, not the resolved value, so\nan explicit ``null`` counts as \"clear the override\" (a real, actionable\nrequest) while an ABSENT key means \"leave this field alone\". A body\nnaming neither key (only ``changed_by``/``actor_kind``, or nothing at\nall) is refused with 400.\n\n``auto_consolidation: true`` is refused with 409 until design doc §5's\npreconditions are met (core#601 decision R5) - the engine does not\nhonour it yet, and recording a ``true`` value it ignores would be a lie\nin the console."},"OrgSettingsPutResponse":{"properties":{"organization_id":{"type":"string","title":"Organization Id"},"settings":{"$ref":"#/components/schemas/OrgSettingsValues"},"effective":{"$ref":"#/components/schemas/OrgSettingsEffective"},"source":{"$ref":"#/components/schemas/OrgSettingsSource"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"updated_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated By"},"history":{"items":{"$ref":"#/components/schemas/OrgSettingsHistoryEntry"},"type":"array","title":"History","description":"Last twenty org_settings_audit rows for this organisation, newest first."},"changed":{"items":{"$ref":"#/components/schemas/OrgSettingsChangedEntry"},"type":"array","title":"Changed","description":"Empty for a no-op PUT (nothing was written); one entry per field that actually changed otherwise."}},"type":"object","required":["organization_id","settings","effective","source","updated_at","updated_by","history","changed"],"title":"OrgSettingsPutResponse"},"OrgSettingsResponse":{"properties":{"organization_id":{"type":"string","title":"Organization Id"},"settings":{"$ref":"#/components/schemas/OrgSettingsValues"},"effective":{"$ref":"#/components/schemas/OrgSettingsEffective"},"source":{"$ref":"#/components/schemas/OrgSettingsSource"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"},"updated_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated By"},"history":{"items":{"$ref":"#/components/schemas/OrgSettingsHistoryEntry"},"type":"array","title":"History","description":"Last twenty org_settings_audit rows for this organisation, newest first."}},"type":"object","required":["organization_id","settings","effective","source","updated_at","updated_by","history"],"title":"OrgSettingsResponse"},"OrgSettingsSource":{"properties":{"supersede_read_filter":{"type":"string","title":"Supersede Read Filter"},"auto_consolidation":{"type":"string","title":"Auto Consolidation"}},"type":"object","required":["supersede_read_filter","auto_consolidation"],"title":"OrgSettingsSource","description":"Which tier of the resolution order decided the effective value:\n``org`` (the row decided), ``env_canary`` (global flag on, the canary\nlist named this organisation), ``global`` (global flag on, empty canary\nlist), ``default`` (nothing set, off). ``auto_consolidation`` never\nreports ``env_canary`` - design doc §5, no env-canary narrowing for it."},"OrgSettingsValues":{"properties":{"supersede_read_filter":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Supersede Read Filter"},"auto_consolidation":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Auto Consolidation"}},"type":"object","required":["supersede_read_filter","auto_consolidation"],"title":"OrgSettingsValues"},"OrgStatsResponse":{"properties":{"organization_id":{"type":"string","title":"Organization Id"},"total_atoms":{"type":"integer","title":"Total Atoms"},"episodes":{"type":"integer","title":"Episodes"},"prototypes":{"type":"integer","title":"Prototypes"},"hebbian_edges":{"type":"integer","title":"Hebbian Edges"},"domains":{"items":{"type":"string"},"type":"array","title":"Domains"},"avg_valence":{"type":"number","title":"Avg Valence"},"avg_importance":{"type":"number","title":"Avg Importance"}},"type":"object","required":["organization_id","total_atoms","episodes","prototypes","hebbian_edges","domains","avg_valence","avg_importance"],"title":"OrgStatsResponse"},"OrgUsageDay":{"properties":{"date":{"type":"string","title":"Date"},"reads":{"type":"integer","title":"Reads"},"writes":{"type":"integer","title":"Writes"},"feedbacks":{"type":"integer","title":"Feedbacks"}},"type":"object","required":["date","reads","writes","feedbacks"],"title":"OrgUsageDay"},"OrgUsageResponse":{"properties":{"organization_id":{"type":"string","title":"Organization Id"},"days":{"items":{"$ref":"#/components/schemas/OrgUsageDay"},"type":"array","title":"Days"},"total_reads":{"type":"integer","title":"Total Reads"},"total_writes":{"type":"integer","title":"Total Writes"},"total_feedbacks":{"type":"integer","title":"Total Feedbacks"},"total_queries":{"type":"integer","title":"Total Queries"},"daily_query_limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Daily Query Limit"}},"type":"object","required":["organization_id","days","total_reads","total_writes","total_feedbacks","total_queries","daily_query_limit"],"title":"OrgUsageResponse"},"PlanEntitlementConflictDetail":{"properties":{"code":{"type":"string","title":"Code"},"message":{"type":"string","title":"Message"},"manual_review":{"type":"boolean","title":"Manual Review","default":true},"key_mirrors_reconciled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Key Mirrors Reconciled","description":"Present only for entitlement_expired/entitlement_terminal conflicts."},"next_action":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Action","description":"Present only for entitlement_expired/entitlement_terminal conflicts."}},"type":"object","required":["code","message"],"title":"PlanEntitlementConflictDetail","description":"The ``detail`` object `_raise_entitlement_conflict` puts on the 409."},"PlanEntitlementConflictResponse":{"properties":{"detail":{"$ref":"#/components/schemas/PlanEntitlementConflictDetail"}},"type":"object","required":["detail"],"title":"PlanEntitlementConflictResponse","description":"Manual-review / identity conflict body for the activate and end endpoints.\n\nFastAPI's default ``HTTPException`` handler wraps the raised ``detail``\ndict under a top-level ``detail`` key; this mirrors that envelope so\n``docs/openapi.json`` documents the exact JSON `_raise_entitlement_conflict`\nreturns."},"PlanEntitlementMutationResponse":{"properties":{"mutation":{"type":"string","title":"Mutation"},"enforced":{"type":"boolean","title":"Enforced"},"entitlement":{"$ref":"#/components/schemas/PlanEntitlementResponse"},"subscription":{"$ref":"#/components/schemas/SubscriptionResponse"}},"type":"object","required":["mutation","enforced","entitlement","subscription"],"title":"PlanEntitlementMutationResponse"},"PlanEntitlementResponse":{"properties":{"entitlement_id":{"type":"string","title":"Entitlement Id"},"organization_id":{"type":"string","title":"Organization Id"},"source":{"type":"string","title":"Source"},"tier":{"type":"string","title":"Tier"},"status":{"type":"string","enum":["scheduled","active","expired","ended"],"title":"Status"},"starts_at":{"type":"string","title":"Starts At"},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At"},"ended_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ended At"},"end_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"End Reason"},"created_at":{"type":"string","title":"Created At"},"updated_at":{"type":"string","title":"Updated At"}},"type":"object","required":["entitlement_id","organization_id","source","tier","status","starts_at","expires_at","ended_at","end_reason","created_at","updated_at"],"title":"PlanEntitlementResponse"},"ProjectInfo":{"properties":{"project_id":{"type":"string","title":"Project Id"},"name":{"type":"string","title":"Name"},"storage_org_id":{"type":"string","title":"Storage Org Id"},"is_archived":{"type":"boolean","title":"Is Archived"}},"type":"object","required":["project_id","name","storage_org_id","is_archived"],"title":"ProjectInfo"},"ProjectKeyRequest":{"properties":{"name":{"type":"string","title":"Name","description":"Human-readable key name."},"tier":{"type":"string","title":"Tier","default":"free"},"rate_limit_per_min":{"type":"integer","title":"Rate Limit Per Min","default":60},"atom_limit":{"type":"integer","title":"Atom Limit","default":10000},"daily_query_limit":{"type":"integer","title":"Daily Query Limit","default":1000}},"type":"object","required":["name"],"title":"ProjectKeyRequest"},"ProvenanceSchema":{"properties":{"principal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Principal","description":"The person/principal who wrote it."},"agent":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent","description":"Stable agent identifier, if any."},"agent_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Name","description":"Human-readable agent name, if any."},"client_env":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Env","description":"Calling client environment: cursor·claude·chatgpt·chat·api·unknown."},"is_external":{"type":"boolean","title":"Is External","description":"True when the principal is external to the org.","default":false}},"type":"object","title":"ProvenanceSchema","description":"Server-stamped authorship of an atom (CN-001).\n\nReturned (as the optional `provenance` object on a read item) only when at\nleast one field is non-null; an atom with no recorded authorship omits the\nwhole object. Stamped from VERIFIED JWT claims at write time — never\nclient-supplied."},"ProvenanceWriteSchema":{"properties":{"principal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Principal","description":"Participant the supplier vouches for."},"agent":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent","description":"Stable agent identifier, if any."},"agent_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Name","description":"Human-readable agent name, if any."},"client_env":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Env","description":"Calling client environment (cursor·claude·chatgpt·chat·api·unknown); anything else normalizes to null."},"is_external":{"type":"boolean","title":"Is External","description":"True when the vouched principal is external to the org.","default":false}},"additionalProperties":false,"type":"object","title":"ProvenanceWriteSchema","description":"SUPPLIER-vouched authorship sent in a write body (CN-001b).\n\nThe reserved, optional ``author`` object a SERVICE/supplier caller may send\nto VOUCH for the participant behind a write (e.g. the supplier's own end\nuser). It is HONORED ONLY for supplier/service tokens and IGNORED (silently\ndropped) for OIDC end-users — an end-user can never set authorship (see\nroutes._get_provenance). Even for a supplier the shape is not blindly\ntrusted: the route re-normalizes every field via auth._normalize_supplier_\nauthor (client_env allow-list, length caps, is_external→bool). All fields are\noptional and loosely typed here so an odd supplier value is normalized rather\nthan 422-ing the whole write; ``extra=\"forbid\"`` still blocks unknown keys\nINSIDE the author object."},"QueryRequestSchema":{"properties":{"query":{"type":"string","maxLength":5000,"minLength":1,"title":"Query","description":"Natural language query."},"domains":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Domains","description":"Filter by multiple domains (null = all)."},"metadata_filter":{"anyOf":[{"items":{"$ref":"#/components/schemas/MetadataFilterSchema"},"type":"array"},{"type":"null"}],"title":"Metadata Filter","description":"JSONB metadata filter conditions."},"top_k":{"type":"integer","maximum":500.0,"minimum":1.0,"title":"Top K","description":"Max items to return. Cap aligned with ReadRequestSchema (500).","default":10},"min_relevance":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Min Relevance","description":"Min relevance threshold.","default":0.3},"include_associations":{"type":"boolean","title":"Include Associations","description":"Expand via Hebbian associations.","default":true},"concepts":{"items":{"type":"string"},"type":"array","title":"Concepts","description":"Concept hints."},"include_history":{"type":"boolean","title":"Include History","description":"Return superseded revisions alongside live ones; each carries `superseded_by`, and every item carries `supersedes` when it replaced something. History is returned in the domain where each revision is stored: a read scoped to the successor's domain does not include a cross-domain predecessor — use an unscoped read or `GET /memory/atoms/{id}`. History items compete under normal ranking, `min_relevance` and `top_k`/`limit` — `include_history` grants eligibility, not chain completeness; for the chain itself use `GET /memory/atoms/{id}/chain`, which spends a 64-LOOKUP budget per call (resolved revisions AND dangling-pointer misses both count) and sets `truncated` when the budget ran out — so `truncated` means the walk stopped early, not that the chain necessarily holds more than 64 revisions. One exception to the domain rule above: when a fingerprint matches a revision that has been replaced, the live tip is returned alongside it even if that tip lives in another domain — the episodic index is domain-blind, and this makes it two atoms rather than one. No effect until the read-side supersession filter is enabled (nothing is hidden before then, so nothing needs unhiding), and inert for `xroom:<room_id>` domains, whose atoms cannot be superseded at all.","default":false}},"type":"object","required":["query"],"title":"QueryRequestSchema","description":"Advanced query with multi-domain and metadata filtering."},"ReadBatchRequestSchema":{"properties":{"queries":{"items":{"$ref":"#/components/schemas/ReadRequestSchema"},"type":"array","maxItems":50,"minItems":1,"title":"Queries","description":"List of read queries (max 50)."}},"type":"object","required":["queries"],"title":"ReadBatchRequestSchema","description":"Batch read request (up to 50 queries)."},"ReadBatchResponseSchema":{"properties":{"results":{"items":{"$ref":"#/components/schemas/ReadResponseSchema"},"type":"array","title":"Results","description":"Per-query results."}},"type":"object","required":["results"],"title":"ReadBatchResponseSchema","description":"Response from batch read."},"ReadRequestSchema":{"properties":{"query":{"type":"string","maxLength":5000,"minLength":1,"title":"Query","description":"Natural language or semantic query."},"top_k":{"type":"integer","maximum":500.0,"minimum":1.0,"title":"Top K","description":"Maximum number of items to return. Cap raised from 100 to 500 for benchmark k-sweep (k=200 cells). Per-call rate-limit policy still applies; downstream cost scales linearly.","default":10},"domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Domain","description":"Optional domain filter (null = all domains)."},"min_relevance":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Min Relevance","description":"Minimum relevance score threshold.","default":0.3},"fingerprint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fingerprint","description":"Optional fingerprint for O(1) episodic exact match."},"include_associations":{"type":"boolean","title":"Include Associations","description":"Whether to expand results via Hebbian concept associations.","default":true},"concepts":{"items":{"type":"string"},"type":"array","maxItems":50,"title":"Concepts","description":"Optional concept hints to bias search. Capped at 50 to bound parallel embed fan-out in expand_concepts_via_embeddings; the auto-extract path already caps at config.max_query_concepts (10)."},"two_pass":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Two Pass","description":"Per-request override for two-pass retrieval. null = use engine config default (Settings.two_pass_enabled). Forwarded to ReadRequest.two_pass; consumed by memory_engine._gate at line 1775."},"strategy":{"anyOf":[{"type":"string","enum":["auto","precise","multi_hop","temporal","exhaustive"]},{"type":"null"}],"title":"Strategy","description":"Per-request override for retrieval strategy. null = engine default (no override). 'auto' triggers the LLM classifier → heuristic fallback (memory_engine.py:1739). Named values ('precise', 'multi_hop', 'temporal', 'exhaustive') resolve via STRATEGY_CATALOG. Anything else returns 422 from FastAPI before reaching the engine."},"include_timings":{"type":"boolean","title":"Include Timings","description":"Opt-in per-phase timing dict on the response (TRACING_SPEC §2): phase wall-times in ms (embed_query_ms, vector_search_ms, db_touch_ms, ...) plus n_embed_calls / n_vector_searches / n_db_roundtrips counters. Off by default so the response payload is unchanged for existing clients; the server-side read_completed log line carries the same dict regardless.","default":false},"order_by":{"type":"string","enum":["relevance","recency"],"title":"Order By","description":"Result ordering. 'relevance' (default) = engine ranking, unchanged. 'recency' = stable re-sort of the final assembled result by created_at DESC (items without a stored timestamp sort last); list length and channel composition are unchanged. This still passes the semantic gate — a pure newest-first feed is #404 R5, a separate endpoint.","default":"relevance"},"since":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Since","description":"Only return items created at or after this ISO-8601 instant (inclusive). Naive datetimes are interpreted as UTC. Applied as an engine post-filter on the assembled result (same placement as the authorship filters): items without a stored timestamp are excluded, and the page may return fewer than top_k when the bound excludes candidates — the queryless feed (#404 R5) is the complete view."},"until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Until","description":"Only return items created at or before this ISO-8601 instant (inclusive). Same UTC/naive, missing-timestamp, and post-filter semantics as `since`. Must be >= since when both are set (422 otherwise)."},"exclude_author":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exclude Author","description":"Drop items whose provenance.principal equals this value — the 'everyone but me' read in shared rooms (#404 R4). Complement of author_principal; the two may combine. Same post-filter semantics as `since`."},"include_history":{"type":"boolean","title":"Include History","description":"Return superseded revisions alongside live ones; each carries `superseded_by`, and every item carries `supersedes` when it replaced something. History is returned in the domain where each revision is stored: a read scoped to the successor's domain does not include a cross-domain predecessor — use an unscoped read or `GET /memory/atoms/{id}`. History items compete under normal ranking, `min_relevance` and `top_k`/`limit` — `include_history` grants eligibility, not chain completeness; for the chain itself use `GET /memory/atoms/{id}/chain`, which spends a 64-LOOKUP budget per call (resolved revisions AND dangling-pointer misses both count) and sets `truncated` when the budget ran out — so `truncated` means the walk stopped early, not that the chain necessarily holds more than 64 revisions. One exception to the domain rule above: when a fingerprint matches a revision that has been replaced, the live tip is returned alongside it even if that tip lives in another domain — the episodic index is domain-blind, and this makes it two atoms rather than one. No effect until the read-side supersession filter is enabled (nothing is hidden before then, so nothing needs unhiding), and inert for `xroom:<room_id>` domains, whose atoms cannot be superseded at all.","default":false},"author_principal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Author Principal","description":"Only return atoms written by this principal."},"author_agent":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Author Agent","description":"Only return atoms written by this agent id."},"author_client_env":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Author Client Env","description":"Only return atoms written from this client env (cursor·claude·chatgpt·chat·api·unknown)."},"author_is_external":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Author Is External","description":"Filter by authorship class: true = external only, false = internal only, null = no filter."}},"type":"object","required":["query"],"title":"ReadRequestSchema","description":"Request body for querying memory.","examples":[{"concepts":[],"domain":"arc","include_associations":true,"min_relevance":0.3,"query":"patterns involving rotation and symmetry","top_k":10}]},"ReadResponseSchema":{"properties":{"items":{"items":{"$ref":"#/components/schemas/MemoryItemSchema"},"type":"array","title":"Items","description":"List of matching memory items, ordered by relevance."},"episodic_hit":{"type":"boolean","title":"Episodic Hit","description":"True if an exact episodic (fingerprint) match was found."},"query_concepts":{"items":{"type":"string"},"type":"array","title":"Query Concepts","description":"Concepts extracted or used for the query."},"expanded_concepts":{"items":{"type":"string"},"type":"array","title":"Expanded Concepts","description":"Concepts expanded via Hebbian associations."},"search_time_ms":{"type":"number","title":"Search Time Ms","description":"Search duration in milliseconds."},"timings":{"anyOf":[{"additionalProperties":{"anyOf":[{"type":"number"},{"type":"integer"}]},"type":"object"},{"type":"null"}],"title":"Timings","description":"Per-phase wall times in ms + call counters (TRACING_SPEC §2). Present only when the request set include_timings=true; an absent phase key means the phase was skipped."}},"type":"object","required":["items","episodic_hit","query_concepts","expanded_concepts","search_time_ms"],"title":"ReadResponseSchema","description":"Response from a memory read query.","example":{"episodic_hit":false,"expanded_concepts":["rotation","symmetry","grid"],"items":[],"query_concepts":["rotation","symmetry"],"search_time_ms":12.5}},"ReadyResponseSchema":{"properties":{"ready":{"type":"boolean","title":"Ready","description":"True when the hard dependencies (database, engine) are operational. For the orchestrator's deploy healthcheck only, also false while the bounded concept-expander warm-up gate is holding - see `checks.warm`. False is served as HTTP 503. Does NOT include the embedding probe — see `degraded`."},"degraded":{"type":"boolean","title":"Degraded","description":"True when `ready` is true but the live embedding probe failed (`checks.embedding == false`). Served as HTTP 200 so a vendor outage cannot block a deploy; probes must alert on it.","default":false},"checks":{"additionalProperties":{"type":"boolean"},"type":"object","title":"Checks","description":"Per-subsystem status. `database`: live SELECT 1; `engine`: initialised; `embedding`: live embed call succeeded within the timeout (cached 60 s); `warm`: true when the concept-expander warm-up readiness gate is off (disabled, or `CONCEPT_EXPANDER_WARM_READY_GATE_SECONDS == 0`, the default), the warm-up has finished, or the gate's time cap has elapsed - false only while a gated warm-up is still inside its window (including a just-started instance whose warm run has not begun yet)."},"embedding_checked_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Embedding Checked At","description":"ISO-8601 UTC timestamp of the live embedding call behind `checks.embedding` (may be up to 60 s old — the probe is cached). None when the engine is not initialised."},"embedding_error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Embedding Error","description":"Exception CLASS name of the last failed embedding probe (e.g. 'TimeoutError', 'HTTPStatusError'), or a short reason token ('embed_fn_not_wired'). Never the message — messages may carry URLs or credentials. None when the probe succeeded or the engine is not initialised."},"version":{"type":"string","title":"Version","description":"Application version string."},"git_sha":{"type":"string","title":"Git Sha","description":"Git commit SHA of the running build (injected at image build time; 'unknown' for local/dev). The post-deploy smoke compares this against the merged commit so a frozen OLD instance cannot report false-green.","default":"unknown"},"embedding_identity":{"anyOf":[{"$ref":"#/components/schemas/EmbeddingIdentitySchema"},{"type":"null"}],"description":"Resolved GLOBAL embedding identity of THIS server — the SAME truth source the provenance stamp uses (the actual producing global EmbeddingService: model + post-Matryoshka output_dim), NOT raw env/Settings. Benchmark cells must stamp this server-truth instead of runner-assumed config (register item C1: a runner stamped its ASSUMED model while the server ran a different one). None only when the engine is not initialized."}},"type":"object","required":["ready","checks","version"],"title":"ReadyResponseSchema","description":"Deep readiness check (DB + engine + concept-expander warm-up + embedding vendor).\n\nTwo verdicts, deliberately separate (FAILURE-SURFACE 2026-08-26, P0-3/P0-4):\n\n* ``ready`` - the hard dependencies (database, engine). ``false`` is served\n as **HTTP 503**, so an orchestrator healthcheck refuses to promote a build\n whose startup failed. For the orchestrator's deploy healthcheck ONLY, a\n warm-up still inside its gate also makes ``ready`` false (see below).\n* ``degraded`` — ``ready`` but the LIVE embedding probe failed. Served as\n **HTTP 200**, so a vendor outage never blocks deploying its own fix.\n External probes must assert ``ready == true && degraded == false``.\n\n``checks.embedding`` is a real vendor call (cached 60 s server-side, probe\ntext time-bucketed to defeat the embedding LRU), not a wiring check.\n\n``checks.warm`` is reported to every caller and is bounded: with the\nwarm-up enabled and its readiness gate\n(`CONCEPT_EXPANDER_WARM_READY_GATE_SECONDS`, max 200) set positive, it is\nfalse while the current process's warm run is still inside the window. It\nmakes ``ready`` false (HTTP 503) only for a probe whose `Host` is\n`CONCEPT_EXPANDER_WARM_READY_GATE_HOST` (default\n`healthcheck.railway.app`, Railway's deploy healthcheck), so that traffic\npromotion waits for the warm-up. Every other caller keeps getting\n``ready: true``: after a crash restart the process serves traffic at once,\nand reporting it as not ready would report an outage that is not\nhappening. Never longer than the cap, and never at all with the gate\nat its default of 0 or the warm-up disabled."},"RecentItemSchema":{"properties":{"atom_id":{"type":"string","format":"uuid","title":"Atom Id","description":"Unique identifier of the atom."},"content":{"type":"string","title":"Content","description":"Stored text content of the memory."},"domain":{"type":"string","title":"Domain","description":"Domain/namespace of the atom."},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"UTC creation instant, ISO-8601."},"concepts":{"items":{"type":"string"},"type":"array","title":"Concepts","description":"Concepts associated with this atom."},"provenance":{"anyOf":[{"$ref":"#/components/schemas/ProvenanceSchema"},{"type":"null"}],"description":"Server-stamped authorship (CN-001); omitted when the atom has none — same omission pattern as read items."},"supersedes":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Supersedes","description":"Ids this entry replaced. OMITTED when it replaced nothing."},"superseded_by":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Superseded By","description":"Id of the revision that replaced this entry. OMITTED while this entry is the live tip."}},"type":"object","required":["atom_id","content","domain","created_at"],"title":"RecentItemSchema","description":"Single entry of the newest-first feed.\n\nA feed line, not a search hit: no relevance/similarity/valence — those are\nmeaningless without a query. `created_at` is always present: the feed is\nordered by it, so an atom cannot appear here without one."},"RecentRequestSchema":{"properties":{"domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Domain","description":"Optional domain filter (null = all the caller's domains). An 'xroom:<room_id>' address resolves through the same membership gate as /memory/read."},"since":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Since","description":"Only entries created at or after this ISO-8601 instant (inclusive). Naive datetimes are read as UTC — same rule as /memory/read. The caller's novelty watermark."},"until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Until","description":"Only entries created at or before this ISO-8601 instant (inclusive). Naive datetimes are read as UTC. Pair with `since` to name a closed window — 'what happened on Monday' — instead of paging back from now and discarding."},"exclude_author":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exclude Author","description":"Drop entries whose provenance principal equals this value — the 'everyone but me' read in a shared room. Mirrors the parameter of the same name on /memory/read (#404 R4)."},"limit":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Limit","description":"Page size. Newest first.","default":20},"cursor":{"anyOf":[{"type":"string","maxLength":512},{"type":"null"}],"title":"Cursor","description":"Opaque continuation cursor from a previous page's next_cursor. Malformed values fail loud (400 VALIDATION_ERROR) — a garbage cursor must never degrade into an unfiltered first page."},"include_history":{"type":"boolean","title":"Include History","description":"Return superseded revisions alongside live ones; each carries `superseded_by`, and every item carries `supersedes` when it replaced something. History is returned in the domain where each revision is stored: a read scoped to the successor's domain does not include a cross-domain predecessor — use an unscoped read or `GET /memory/atoms/{id}`. History items compete under normal ranking, `min_relevance` and `top_k`/`limit` — `include_history` grants eligibility, not chain completeness; for the chain itself use `GET /memory/atoms/{id}/chain`, which spends a 64-LOOKUP budget per call (resolved revisions AND dangling-pointer misses both count) and sets `truncated` when the budget ran out — so `truncated` means the walk stopped early, not that the chain necessarily holds more than 64 revisions. One exception to the domain rule above: when a fingerprint matches a revision that has been replaced, the live tip is returned alongside it even if that tip lives in another domain — the episodic index is domain-blind, and this makes it two atoms rather than one. No effect until the read-side supersession filter is enabled (nothing is hidden before then, so nothing needs unhiding), and inert for `xroom:<room_id>` domains, whose atoms cannot be superseded at all.","default":false}},"type":"object","title":"RecentRequestSchema","description":"Request body for the queryless newest-first feed (#404 R5, #431).\n\nBacks the MCP `memory_list_recent` tool: \"what happened lately\", complete\nby construction — a keyset walk over `created_at`, not a semantic search."},"RecentResponseSchema":{"properties":{"items":{"items":{"$ref":"#/components/schemas/RecentItemSchema"},"type":"array","title":"Items","description":"Feed entries, created_at DESC (ties broken by id DESC)."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Opaque cursor for the next (older) page; null when nothing older remains. Always matches ^[A-Za-z0-9_=-]{1,512}$ — the MCP client refuses to echo a cursor outside that shape (CN-032)."}},"type":"object","required":["items"],"title":"RecentResponseSchema","description":"Response of the newest-first feed.","example":{"items":[{"atom_id":"550e8400-e29b-41d4-a716-446655440000","concepts":["deploy","staging"],"content":"Staging moved to Fly.io — Railway config retired","created_at":"2026-08-04T09:12:00Z","domain":"general"}]}},"RevokeResponse":{"properties":{"member_org_id":{"type":"string","title":"Member Org Id"},"revoked":{"type":"boolean","title":"Revoked"}},"type":"object","required":["member_org_id","revoked"],"title":"RevokeResponse"},"RoomCreatedSchema":{"properties":{"room_id":{"type":"string","title":"Room Id","description":"The room's public id (room_<ulid>)."},"address":{"type":"string","title":"Address","description":"Ready-to-use domain address: xroom:<room_id>."},"name":{"type":"string","title":"Name","description":"The room name as stored."},"next_steps":{"type":"string","title":"Next Steps","description":"Human/agent-readable guidance: how to use the room now and how to bring other accounts in."}},"type":"object","required":["room_id","address","name","next_steps"],"title":"RoomCreatedSchema","description":"Response for a freshly created room — carries the ready-to-use address\nAND actionable next steps. Agents read tool output, not documentation: the\nresponse itself must teach how to use the room and how a second account\njoins, or the room dead-ends with its creator."},"RoomInfo":{"properties":{"room_id":{"type":"string","title":"Room Id"},"name":{"type":"string","title":"Name"},"storage_org_id":{"type":"string","title":"Storage Org Id"},"is_archived":{"type":"boolean","title":"Is Archived"}},"type":"object","required":["room_id","name","storage_org_id","is_archived"],"title":"RoomInfo"},"RoomListItemSchema":{"properties":{"room_id":{"type":"string","title":"Room Id","description":"The room's public id (room_<ulid>)."},"name":{"type":"string","title":"Name","description":"The room name."},"address":{"type":"string","title":"Address","description":"Ready-to-use domain address: xroom:<room_id>."},"role":{"type":"string","title":"Role","description":"'owner' or 'member'."},"scope":{"type":"string","title":"Scope","description":"'read' or 'read_write'."},"archived":{"type":"boolean","title":"Archived","description":"True if archived (owned rooms only; joined are active)."}},"type":"object","required":["room_id","name","address","role","scope","archived"],"title":"RoomListItemSchema","description":"One room an agent can access — owned or joined — for discovery / resume. The\n``address`` pastes straight into a ``domain`` field on memory_read / memory_write."},"SealedSecretResponse":{"properties":{"alias":{"type":"string","title":"Alias"},"sealed_secret_b64":{"type":"string","title":"Sealed Secret B64"}},"type":"object","required":["alias","sealed_secret_b64"],"title":"SealedSecretResponse"},"SecretSummary":{"properties":{"alias":{"type":"string","title":"Alias"},"context":{"type":"string","title":"Context"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"concepts":{"items":{"type":"string"},"type":"array","title":"Concepts"}},"type":"object","required":["alias","context","created_at","concepts"],"title":"SecretSummary","description":"One secret as VALUE-FREE discovery metadata. Never carries the sealed value —\nonly the alias, the in-clear context (purpose), when it was stored, and its concepts.\nThe field set is deliberately narrow: a second guardrail behind the storage layer,\nwhich already omits the ``sealed_secret`` column from ``_ATOM_COLS``."},"SelfServeKeyRequest":{"properties":{"name":{"type":"string","title":"Name","description":"Human-readable key name."},"tier":{"type":"string","title":"Tier","default":"free"},"rate_limit_per_min":{"type":"integer","title":"Rate Limit Per Min","default":60},"atom_limit":{"type":"integer","title":"Atom Limit","default":10000},"daily_query_limit":{"type":"integer","title":"Daily Query Limit","default":1000}},"type":"object","required":["name"],"title":"SelfServeKeyRequest"},"SetEmbeddingModelRequest":{"properties":{"model":{"anyOf":[{"type":"string","maxLength":150},{"type":"null"}],"title":"Model","description":"Embedding model id (e.g. 'BAAI/bge-small-en-v1.5') or null/'' to clear."},"dim":{"anyOf":[{"type":"integer","maximum":8192.0,"minimum":1.0},{"type":"null"}],"title":"Dim","description":"Native dimension of the pinned model (optional companion)."},"backend":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Backend","description":"Backend for the pinned model: 'api' | 'local' | 'mock' (optional)."}},"type":"object","title":"SetEmbeddingModelRequest","description":"Pin (or clear) the embedding model for a single organization.\n\nPass ``model=None`` (or empty string) to CLEAR the pin and fall back to the\nfleet-level ``embedding_versions`` active row / Settings default. ``dim`` and\n``backend`` are OPTIONAL companions to the model (a model-only pin lets the\nengine resolve dim/backend from its global config). Setting a pin does NOT\nre-embed the org's existing atoms — run ``scripts/reembed_atoms.py --org-id\n<org> --old-model <prev>`` to migrate the corpus onto the pinned model."},"SetLLMProviderRequest":{"properties":{"provider":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Provider","description":"Provider name (e.g. 'openai', 'anthropic', 'mock') or null to clear."}},"type":"object","title":"SetLLMProviderRequest","description":"Override the LLM provider for a single organization.\n\nPass `provider=None` (or empty string) to clear the override and\nfall back to tier/global defaults. Provider name must be one of\nthe backends registered at startup (check `GET /admin/llm/providers`)."},"StatsResponseSchema":{"properties":{"total_atoms":{"type":"integer","title":"Total Atoms","description":"Total number of atoms."},"episodes":{"type":"integer","title":"Episodes","description":"Count of episode-type atoms."},"prototypes":{"type":"integer","title":"Prototypes","description":"Count of prototype atoms."},"singletons":{"type":"integer","title":"Singletons","description":"Count of singleton (protected) atoms."},"hebbian_edges":{"type":"integer","title":"Hebbian Edges","description":"Number of Hebbian concept-concept edges."},"episodic_fingerprints":{"type":"integer","title":"Episodic Fingerprints","description":"Number of stored episodic fingerprints."},"domains":{"items":{"type":"string"},"type":"array","title":"Domains","description":"List of domain names present."},"avg_valence":{"type":"number","title":"Avg Valence","description":"Average valence across atoms."},"avg_importance":{"type":"number","title":"Avg Importance","description":"Average importance across atoms."}},"type":"object","required":["total_atoms","episodes","prototypes","singletons","hebbian_edges","episodic_fingerprints","domains","avg_valence","avg_importance"],"title":"StatsResponseSchema","description":"Memory statistics snapshot."},"SubscriptionResponse":{"properties":{"organization_id":{"type":"string","title":"Organization Id"},"tier":{"type":"string","title":"Tier"},"status":{"type":"string","title":"Status"},"requested_tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requested Tier"},"grace_until":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Grace Until"},"days_remaining":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Days Remaining"},"stripe_customer_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Customer Id"},"stripe_subscription_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Subscription Id"},"atom_limit":{"type":"integer","title":"Atom Limit"},"daily_query_limit":{"type":"integer","title":"Daily Query Limit"},"rate_limit_per_min":{"type":"integer","title":"Rate Limit Per Min"},"contact_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contact Email"},"billing_tier":{"type":"string","title":"Billing Tier"},"effective_tier":{"type":"string","title":"Effective Tier"},"effective_entitlement_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Entitlement Id"},"effective_entitlement_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Entitlement Source"},"effective_entitlement_expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Entitlement Expires At"}},"type":"object","required":["organization_id","tier","status","requested_tier","grace_until","days_remaining","stripe_customer_id","stripe_subscription_id","atom_limit","daily_query_limit","rate_limit_per_min","billing_tier","effective_tier"],"title":"SubscriptionResponse"},"UpdateSubscriptionRequest":{"properties":{"tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tier"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"requested_tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requested Tier"},"stripe_customer_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Customer Id"},"stripe_subscription_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Subscription Id"},"contact_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contact Email"},"event":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event","description":"Event hint for state transition: payment_failed, payment_succeeded, subscription_deleted, grace_expired"}},"type":"object","title":"UpdateSubscriptionRequest","description":"Generic update — used by Stripe webhooks and manual admin actions."},"UpdateTierRequest":{"properties":{"tier":{"type":"string","title":"Tier","description":"New tier: free, pro, team"},"rate_limit_per_min":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rate Limit Per Min","description":"Override rate limit"},"atom_limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Atom Limit","description":"Override atom limit"},"daily_query_limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Daily Query Limit","description":"Override daily query limit"}},"type":"object","required":["tier"],"title":"UpdateTierRequest"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"WriteBatchItemResult":{"properties":{"index":{"type":"integer","title":"Index","description":"Position in the request items list."},"stored":{"type":"boolean","title":"Stored","description":"True if the atom was stored."},"atom_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Atom Id","description":"UUID of stored atom, or None."},"importance":{"type":"number","title":"Importance","description":"Computed importance score.","default":0.0},"reason":{"type":"string","title":"Reason","description":"Engine-provided reason when the item was filtered instead of stored.","default":""},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Error message if item failed."}},"type":"object","required":["index","stored"],"title":"WriteBatchItemResult","description":"Per-item result in a batch write response."},"WriteBatchRequestSchema":{"properties":{"items":{"items":{"$ref":"#/components/schemas/WriteRequestSchema"},"type":"array","maxItems":500,"minItems":1,"title":"Items","description":"List of atoms to write."}},"type":"object","required":["items"],"title":"WriteBatchRequestSchema","description":"Request body for writing multiple atoms in one request."},"WriteBatchResponseSchema":{"properties":{"total_count":{"type":"integer","title":"Total Count","description":"Total number of atoms processed."},"stored_count":{"type":"integer","title":"Stored Count","description":"Number of atoms stored (passed importance gate)."},"results":{"items":{"$ref":"#/components/schemas/WriteBatchItemResult"},"type":"array","title":"Results","description":"Per-atom results in request order."}},"type":"object","required":["total_count","stored_count","results"],"title":"WriteBatchResponseSchema","description":"Response after batch write."},"WriteRequestSchema":{"properties":{"content":{"type":"string","maxLength":10000,"minLength":1,"title":"Content","description":"The insight, pattern, or lesson to remember."},"concepts":{"items":{"type":"string"},"type":"array","maxItems":256,"title":"Concepts","description":"Key concepts (used for Hebbian associations). At most 256 items — the write-time association pass is quadratic in this count."},"domain":{"type":"string","maxLength":100,"title":"Domain","description":"Namespace: 'general', 'user:X', 'room:Y', 'project:Z'.","default":"general"},"fingerprint":{"anyOf":[{"type":"string","maxLength":512},{"type":"null"}],"title":"Fingerprint","description":"Optional SHA256-like fingerprint for exact episodic match (e.g. task hash). At most 512 characters."},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata","description":"Arbitrary key-value metadata. The serialized JSON must be at most 65536 bytes."},"external_ref":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"External Ref","description":"Client-provided unique reference for idempotent writes and cross-system correlation."},"supersedes":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array","maxItems":32},{"type":"null"}],"title":"Supersedes","description":"Ids of atoms this write REPLACES. The successor is stored and every listed atom is marked as superseded by it, in one transaction — all of it or none. At most 32 ids, all distinct. Supersession is caller-asserted: the engine never infers that two atoms describe the same fact. Not accepted on write_batch, and not accepted alongside an `xroom:` domain."},"author":{"anyOf":[{"$ref":"#/components/schemas/ProvenanceWriteSchema"},{"type":"null"}],"description":"Reserved supplier-vouched authorship (CN-001b). Honored ONLY for SERVICE/supplier tokens (the supplier vouches for its participant); IGNORED for OIDC end-users. Even for a supplier the shape is re-normalized server-side (client_env allow-list, length caps)."}},"additionalProperties":false,"type":"object","required":["content"],"title":"WriteRequestSchema","description":"Request body for storing a new memory atom.","example":{"concepts":["rotation","symmetry","grid"],"content":"Rotation preserves symmetry in grid transformations.","domain":"arc","metadata":{}}},"WriteResponseSchema":{"properties":{"stored":{"type":"boolean","title":"Stored","description":"True if the atom was stored (passed importance gate)."},"atom_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Atom Id","description":"UUID of the stored atom, or None if filtered."},"importance":{"type":"number","title":"Importance","description":"Computed importance score in [0, 1].","default":0.0},"reason":{"type":"string","title":"Reason","description":"Short reason (e.g. why filtered or stored).","default":""},"superseded":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Superseded","description":"Ids this write superseded, in request order. Empty on an ordinary write, so clients can read it unconditionally. Non-empty means every listed atom is now marked superseded and points at `atom_id`; they will be excluded from default reads once read-side filtering (D2) ships. Until then they still appear in search and listing results."}},"type":"object","required":["stored"],"title":"WriteResponseSchema","description":"Response after attempting to store a memory atom."}}}}