Ur repot
Styrytor — paritetsmatris
Skapad 2026-07-25 (paket 7, D-63). Grindad av tools/checks/check_control_surface_parity.py via pre-commit.
Modellen är A: API:et är kontraktet (intern spec för core- och gränssnittsmodellen, §3). Varje tjänst äger sin förmåga bakom sitt HTTP-kontrakt. Ingen yta får egen affärslogik och ingen yta får egen dataväg. UI:t (frontends/ops-ui) talar uteslutande /api/... genom BFF:n; automation talar kontraktet direkt. Break-glass-CLI:t är det enda uttalade undantaget.
Den här filen är inte prosa vid sidan av koden — vakten läser den. En styråtgärd som tillkommer utan en rad här fäller pre-commit, och en rad som pekar på kod som inte finns gör det också.
Identifierare: <tjänst>:<modul>:<METOD> <path>. Modulen ingår för att routerns prefix= inte syns i dekoratorn — utan den kollapsar GET "" i users.py och group_mappings.py till samma sträng, och en matrisrad kan då beskriva fel förmåga. Kolumnen “Full path” visar routerns prefix + dekoratorns path.
Täckningsgräns — läs detta innan du drar slutsatser
Vakten enumererar två saker, medvetet snävt:
- Admin-plansrutter — route-dekoratorer i filer under en katalog som heter
admin(i dagauth-api,bff,llm-gateway) eller i en fil som heteradmin.py(i dagmcp-gateway). Filformen kom till iP58: före den föll mcp-gatewayensroutes/admin.pyutanför på en filnamnsdetalj. Andra namn — t.ex.policy-enginesadmin_*.py— räknas inte. - Break-glass-CLI-kommandon — typer-subappar i
tools/auth-cli, argparse-subkommandon itools/audit-chain.
Allt annat är utanför. Vanliga tenant-scopade API:er (/v1/assistants, /v1/collections, …), UI-vyer, MCP-verktyg och provisioning-apis tenant-livscykel granskas inte av vakten och ska inte läsas som täckta. Att bredda täckningen är ett eget arbete — inte något som ska antas ha skett.
auth-api — identitet, behörighet, GDPR
Router-prefix: /v1/admin/tenants/{tenant_id}/… (monteras under /admin).
| Styråtgärd | Identifierare | Full path | UI | Break-glass |
|---|---|---|---|---|
| Lista användare | auth-api:users:GET / |
…/users |
ja | — |
| Bjud in användare | auth-api:users:POST / |
…/users |
ja | — |
| Återkalla användare | auth-api:users:POST /{user_id}/revoke |
…/users/{id}/revoke |
ja | — |
| Återaktivera användare | auth-api:users:POST /{user_id}/enable |
…/users/{id}/enable |
ja | — |
| SAR-export för en användare | auth-api:gdpr:POST /{user_id}/export |
…/users/{id}/export |
ja | — |
| Radera/pseudonymisera användare | auth-api:gdpr:POST /{user_id}/erase |
…/users/{id}/erase |
ja | — |
| Lista gruppmappningar | auth-api:group_mappings:GET / |
…/group-mappings |
ja | — |
| Skapa gruppmappning | auth-api:group_mappings:POST / |
…/group-mappings |
ja | — |
| Ta bort gruppmappning | auth-api:group_mappings:DELETE / |
…/group-mappings |
ja | — |
| Lista rollbindningar | auth-api:role_bindings:GET / |
…/role-bindings |
ja | — |
| Skapa rollbindning | auth-api:role_bindings:POST / |
…/role-bindings |
ja | — |
| Ta bort en användares rollbindningar | auth-api:role_bindings:DELETE /{user_id} |
…/role-bindings/{user_id} |
ja | — |
| Tenant-exit-export | auth-api:tenant_export:GET /export |
…/{tenant_id}/export |
— | — |
| Lista tenantens service clients | auth-api:service_clients:GET / |
…/service-clients |
— | — |
Ge delegeringsrätt (token:delegate) |
auth-api:service_clients:PUT /{client_id}/delegation |
…/service-clients/{id}/delegation |
— | — |
| Ta tillbaka delegeringsrätt | auth-api:service_clients:DELETE /{client_id}/delegation |
…/service-clients/{id}/delegation |
— | — |
Ge kanalrätt (token:channel, P3) |
auth-api:service_clients:PUT /{client_id}/channel |
…/service-clients/{id}/channel |
— | — |
| Ta tillbaka kanalrätt | auth-api:service_clients:DELETE /{client_id}/channel |
…/service-clients/{id}/channel |
— | — |
| Lista kanalidentiteter (P3) | auth-api:channel_identities:GET / |
…/channel-identities |
— | — |
| Mappa kanalkonto till person | auth-api:channel_identities:PUT /{channel}/{team_id}/{external_user_id} |
…/channel-identities/{channel}/{team}/{user} |
— | — |
| Ta bort kanalmappning | auth-api:channel_identities:DELETE /{channel}/{team_id}/{external_user_id} |
…/channel-identities/{channel}/{team}/{user} |
— | — |
| Bootstrap av första tenant-admin | — | — | — | auth-cli:bootstrap |
| Rotation av signeringsnycklar | — | — | — | auth-cli:keys |
| Skapa/återkalla service client | saknas | — | — | auth-cli:service-clients |
Bootstrap och nyckelrotation saknar API-yta med flit: bootstrap måste fungera innan plattformen har någon tenant eller någon som kan autentisera sig, och signeringsnycklarna är förutsättningen för att API-auth alls fungerar — en API-väg vore cirkulär.
Service clients är en ÄKTA LUCKA, och sedan P19 en MINDRE sådan. Specen §4 antog att hela ytan fanns i auth-apis kontrakt. Det gjorde den inte. P19 levererade den halva som stod mellan plattformen och varje agentdriftsättning — att lista tenantens klienter och att slå på/av token:delegate — men skapandet och återkallandet av själva klientraden ligger kvar i break-glass. Det är avsiktligt så länge det är sant: create skriver ut en hemlighet en gång, och tenant_id NULL (plattformsskopad klient, bl.a. rag-apis eval-trigger-identitet, D-41) hör till operatörsplanet, som require_tenant_admin inte får styra. CLI-kommandot står därför kvar tills auth-api levererar även den halvan. Spårat i D-63.
llm-gateway — nycklar, budget, förbrukning
Router-prefix: /admin.
| Styråtgärd | Identifierare | UI | Break-glass |
|---|---|---|---|
| Skapa tenant-nyckel | llm-gateway:keys:POST /tenants/{tenant_id}/keys |
— | — |
| Lista tenant-nycklar | llm-gateway:keys:GET /tenants/{tenant_id}/keys |
— | — |
| Återkalla nyckel | llm-gateway:keys:DELETE /keys/{key_id} |
— | — |
| Ändra nyckelns modellåtkomst | llm-gateway:keys:PATCH /keys/{key_id} |
— | — |
| Läsa budget | llm-gateway:budgets:GET /tenants/{tenant_id}/budget |
— | — |
| Sätta budget | llm-gateway:budgets:PUT /tenants/{tenant_id}/budget |
— | — |
| Sätta alert-webhook | llm-gateway:budgets:PUT /tenants/{tenant_id}/webhook |
— | — |
| Förbrukning per tenant | llm-gateway:usage:GET /tenants/{tenant_id}/usage |
ja | — |
| Förbrukning per användare | llm-gateway:usage:GET /tenants/{tenant_id}/usage/by-user |
ja | — |
| Förbrukning per grupp | llm-gateway:usage:GET /tenants/{tenant_id}/usage/by-group |
ja | — |
| Förbrukning, översikt | llm-gateway:usage:GET /usage/summary |
ja | — |
| Auditlogg | llm-gateway:audit:GET /audit |
ja | — |
| Tenant-exit-export | llm-gateway:tenant_export:GET /tenants/{tenant_id}/export |
— | — |
De fyra nyckel-/budget-raderna ersatte gateway-clis create-key/list-keys/revoke-key/set-budget/set-webhook när CLI:t raderades i paket 5. E2e-sviten och load-riggen mintar sedan dess nycklar genom keys:POST.
mcp-gateway — MCP-servrar och behörigheter
Router-prefix: /v1/admin/mcp-servers (UI når det som /api/mcp/… genom BFF:n). Alla rutter kräver tenant_admin.
| Styråtgärd | Identifierare | Full path | UI | Break-glass |
|---|---|---|---|---|
| Registrera MCP-server | mcp-gateway:admin:POST / |
…/mcp-servers |
ja | — |
| Lista MCP-servrar | mcp-gateway:admin:GET / |
…/mcp-servers |
ja | — |
| Läsa en MCP-server | mcp-gateway:admin:GET /{server_id} |
…/mcp-servers/{id} |
— | — |
| Köra om verktygsupptäckt | mcp-gateway:admin:POST /{server_id}/rediscover |
…/mcp-servers/{id}/rediscover |
— | — |
| Ändra server (beskrivning, status, egress, auth, identitetsläge) | mcp-gateway:admin:PATCH /{server_id} |
…/mcp-servers/{id} |
ja (bara status) | — |
| Ta bort MCP-server | mcp-gateway:admin:DELETE /{server_id} |
…/mcp-servers/{id} |
ja | — |
| Ändra ett verktygs scope | mcp-gateway:admin:PATCH /{server_id}/tools/{tool_name}/scope |
…/mcp-servers/{id}/tools/{tool}/scope |
— | — |
Lista behörigheter (P19) |
mcp-gateway:admin:GET /{server_id}/grants |
…/mcp-servers/{id}/grants |
ja | — |
| Ge behörighet | mcp-gateway:admin:POST /{server_id}/grants |
…/mcp-servers/{id}/grants |
ja | — |
| Ta bort behörighet | mcp-gateway:admin:DELETE /{server_id}/grants/{grant_id} |
…/mcp-servers/{id}/grants/{grant_id} |
ja | — |
bff — publika siter och drift
Router-prefix: /api/public-sites.
| Styråtgärd | Identifierare | UI | Break-glass |
|---|---|---|---|
| Skapa publik site | bff:public_sites:POST / |
ja | — |
| Lista publika siter | bff:public_sites:GET / |
ja | — |
| Återkalla publik site | bff:public_sites:POST /{site_id}/revoke |
ja | — |
| Lås upp forensik för en session | bff:public_sites:POST /{site_id}/forensics/{session_id}/unlock |
ja | — |
| Trigga retention-sweep | bff:public_sites:POST /maintenance/sweep |
— | — |
audit-chain — forensik
| Styråtgärd | API | UI | Break-glass |
|---|---|---|---|
| Validera hash-kedja | — | — | audit-chain:validate |
| Validera alla kedjor (audit.chain_heads) | — | — | audit-chain:validate-all |
| Kedjestatus | — | — | audit-chain:status |
Saknar API-yta med flit: ska fungera under incident, när tjänsterna inte gör det.
Medvetet utan yta
Det här är beslut, inte luckor (till skillnad från service clients ovan):
- Inget
platformctl, ingen CLI-paritet. Ett CLI som täcker plattformens styrning är dubblettfunktionalitet by construction — varje förmåga får två implementationer och två testytor, för ett krav som inte finns skrivet (spec §4). - Inga styråtgärder som MCP-verktyg — ännu. Rätt yta för en AI-operatör är MCP, inte CLI:
mcp-gatewaystool_callgör redan schemavalidering → policy enforcement → dispatch med audit-first-invariant. Steg 2 i spec §7 är inte påbörjat. - Plattforms-admin-planet (
provisioning-api) nås inte genom BFF:n. Det ligger utanför BFF:nsupstream_mapoch kräver service-token, vilket gör tenant-livscykel och tenant-exit-export oåtkomliga för både UI och användar-JWT. Detta är specens öppna fråga §10 — ännu inte avgjord, alltså varken ett dokumenterat val eller ett åtgärdat hål. - Ingen
POST /admin/tenantsi llm-gateway. Tenants ägs avprovisioning-api(POST /v1/tenants). Runbooken påstod länge motsatsen och rättades i paket 5.
Ändra den här filen
Lägger du till en admin-rutt eller ett break-glass-kommando: lägg en rad i rätt tabell med identifieraren i backticks. Kör vakten manuellt med:
python3 tools/checks/check_control_surface_parity.py