Files
boc/docs/arc/ARC-002-capability-registry.md
T

446 lines
15 KiB
Markdown
Raw Normal View History

# ARC-002 — Capability Registry
**Status:** Accepted
**Datum:** 2026-06-01
**Beslutsfattare:** AAMOS Architecture Team
---
## Kontext
### Problemet med oreglerad AI-integration
AI-komponenter (LLM-anrop, klassificeringsmodeller, anomalidetektion) integreras i AAMOS för att höja kvalitet och automatiseringsgrad. Utan ett centralt register skapas ofrånkomligen:
- **Okontrollerade beslutsgränser:** En modul kan börja fatta autonoma beslut utan att det är explicit designat, dokumenterat eller granskat
- **AI-drift:** Samma logiska funktion (t.ex. "klassificera kostnad") implementeras på 3 olika sätt i 3 moduler med 3 olika prompter och 3 olika feltoleranser
- **Revisionsbrist:** Vid en redovisningsfråga kan vi inte svara på "vilken AI-funktion fattade det här beslutet, med vilket confidence och vilka indata?"
- **GDPR-exponering:** Känsliga persondata kan hamna i AI-prompts utan spårbarhet
### Principen: AI föreslår, människa beslutar
**I AAMOS är det alltid en människa (eller ett explicit auktoriserat system) som fattar ekonomiska beslut.**
AI:n klassificerar, flaggar, rekommenderar och sammanfattar — aldrig bokför, attesterar eller godkänner.
Denna princip gäller för alla moduler. Den är inte förhandlingsbar.
---
## Beslut
### 1. Capability Registry som central komponent
Alla AI-funktioner i AAMOS **MÅSTE** registreras i Capability Registry innan de exponeras mot en modul. En capability som inte finns i registret får inte anropas i produktion.
Registret är källan till sanning för:
- Vad AI-systemet **får** göra
- Vad AI-systemet **inte får** besluta
- Hur AI-beslut ska **loggas och spåras**
---
### 2. Registry-schema
```typescript
interface Capability {
// Identitet
capability_id: string; // Format: "<modul>.<funktion>" t.ex. "ekonomi.classification"
version: string; // Semver: "1.0.0"
name: string; // Läsbart namn: "Kostnadsklassificering"
description: string; // Vad funktionen gör, i ett stycke
module: string; // Ägande modul: "ekonomi", "crm", "*" (global)
status: "active" | "beta" | "deprecated" | "disabled";
// Datakontraktet
input_schema: JSONSchema; // Validerar indata till capability
output_schema: JSONSchema; // Validerar utdata från capability
// Konfidensmodell
confidence_model: {
type: "binary" | "score" | "categorical" | "none";
threshold_for_auto_action?: number; // 0.01.0; null = aldrig auto
threshold_for_suggestion?: number; // Under detta: visa men flagga som osäker
uncertainty_action: "reject" | "escalate" | "flag";
};
// Beslutsgränser — KRITISKT
decision_boundary: {
can_auto_execute: boolean; // Får capability köras utan mänsklig granskning?
auto_execute_conditions?: string[]; // Om true: exakta villkor som måste gälla
max_financial_impact?: number; // Maxbelopp i SEK för auto-action (null = inga finansiella effekter tillåtna)
requires_dual_approval?: boolean; // Fyra-ögonprincipen
immutable_fields?: string[]; // Fält capability inte får påverka
};
// Vem får fatta beslut baserat på denna capability
allowed_decision_sources: Array<
| "human:any" // Vilken inloggad användare som helst
| "human:manager" // Kräver manager-roll
| "human:auditor" // Kräver auditor-roll
| "system:workflow" // Workflow Engine (med godkänd definition)
| "system:scheduler" // Schemalagd process
>;
// Spårbarhet
audit_config: {
log_inputs: boolean; // Logga indata (obs: GDPR-krav)
log_outputs: boolean; // Logga utdata
log_confidence: boolean; // Logga konfidensscore
retention_days: number; // Lagringstid för loggar
pii_fields: string[]; // Fält som ska redigeras/krypteras i logg
};
// Livscykel
created_at: string; // ISO 8601
deprecated_at?: string; // När deprecation inleddes
sunset_date?: string; // Deadline för borttagning
superseded_by?: string; // capability_id för ersättare
}
```
---
### 3. Initiala capabilities
#### `ekonomi.classification`
```json
{
"capability_id": "ekonomi.classification",
"version": "1.0.0",
"name": "Kostnadsklassificering",
"description": "Klassificerar en transaktion eller kostnadsrad mot kontoplan och kostnadsbärare baserat på historik och regelbaserad logik.",
"module": "ekonomi",
"status": "active",
"confidence_model": {
"type": "score",
"threshold_for_auto_action": null,
"threshold_for_suggestion": 0.75,
"uncertainty_action": "escalate"
},
"decision_boundary": {
"can_auto_execute": false,
"max_financial_impact": null,
"requires_dual_approval": false,
"immutable_fields": ["account_code", "amount", "transaction_date"]
},
"allowed_decision_sources": ["human:any", "human:manager"]
}
```
#### `ekonomi.forecasting`
```json
{
"capability_id": "ekonomi.forecasting",
"version": "1.0.0",
"name": "Ekonomisk prognos",
"description": "Genererar kassaflödesprognoser och budgetavvikelseprojektioner baserat på historiska transaktionsdata.",
"module": "ekonomi",
"status": "active",
"confidence_model": {
"type": "score",
"threshold_for_auto_action": null,
"threshold_for_suggestion": 0.60,
"uncertainty_action": "flag"
},
"decision_boundary": {
"can_auto_execute": false,
"max_financial_impact": null,
"requires_dual_approval": false,
"immutable_fields": ["*"]
},
"allowed_decision_sources": ["human:manager", "human:auditor"]
}
```
#### `ekonomi.anomaly_detection`
```json
{
"capability_id": "ekonomi.anomaly_detection",
"version": "1.0.0",
"name": "Transaktionsanomalidetektion",
"description": "Identifierar avvikande transaktioner som kan indikera fel, dubbletter eller bedrägerimönster. Flaggar för mänsklig granskning.",
"module": "ekonomi",
"status": "active",
"confidence_model": {
"type": "score",
"threshold_for_auto_action": null,
"threshold_for_suggestion": 0.65,
"uncertainty_action": "flag"
},
"decision_boundary": {
"can_auto_execute": false,
"max_financial_impact": null,
"requires_dual_approval": false,
"immutable_fields": ["*"]
},
"allowed_decision_sources": ["human:any", "human:auditor"]
}
```
#### `ekonomi.recommendation`
```json
{
"capability_id": "ekonomi.recommendation",
"version": "1.0.0",
"name": "Åtgärdsrekommendation",
"description": "Föreslår nästa steg i ett arbetsflöde — t.ex. betalningsförslag, matchning av faktura mot order, eller kontokorrigeringsförslag. Aldrig auto-exekverande.",
"module": "ekonomi",
"status": "active",
"confidence_model": {
"type": "categorical",
"threshold_for_auto_action": null,
"threshold_for_suggestion": 0.70,
"uncertainty_action": "escalate"
},
"decision_boundary": {
"can_auto_execute": false,
"max_financial_impact": null,
"requires_dual_approval": false,
"immutable_fields": ["amount", "account_code", "transaction_date"]
},
"allowed_decision_sources": ["human:any"]
}
```
#### `ekonomi.compliance_review`
```json
{
"capability_id": "ekonomi.compliance_review",
"version": "1.0.0",
"name": "Regelefterlevnadsgranskning",
"description": "Kontrollerar transaktioner och rapporter mot bokföringslagens krav, momskoder och interna kontrollregler. Returnerar en checklista med flaggor.",
"module": "ekonomi",
"status": "active",
"confidence_model": {
"type": "binary",
"threshold_for_auto_action": null,
"threshold_for_suggestion": null,
"uncertainty_action": "escalate"
},
"decision_boundary": {
"can_auto_execute": false,
"max_financial_impact": null,
"requires_dual_approval": false,
"immutable_fields": ["*"]
},
"allowed_decision_sources": ["human:auditor", "human:manager"]
}
```
#### `ekonomi.document_extraction`
```json
{
"capability_id": "ekonomi.document_extraction",
"version": "1.0.0",
"name": "Dokumentdataextraktion",
"description": "Extraherar strukturerade data från faktura-PDF:er och kvitton. Returnerar extraherade fält för mänsklig verifiering. Fyller ALDRIG i bokföringssystem autonomt.",
"module": "ekonomi",
"status": "active",
"confidence_model": {
"type": "score",
"threshold_for_auto_action": null,
"threshold_for_suggestion": 0.85,
"uncertainty_action": "flag"
},
"decision_boundary": {
"can_auto_execute": false,
"max_financial_impact": null,
"requires_dual_approval": false,
"immutable_fields": ["account_code", "amount", "vat_amount", "invoice_date"]
},
"allowed_decision_sources": ["human:any"]
}
```
---
### 4. Hur en modul konsumerar en capability
#### 4.1 API-mönster (REST)
```
POST /api/v1/capabilities/{capability_id}/invoke
Authorization: Bearer <service-token>
X-Tenant-ID: <tenant_id>
X-Correlation-ID: <uuid>
X-Requested-By: <person_id|system_id>
{
"version": "1.0.0", // Pinnad version (required)
"input": { ... }, // Valideras mot capability.input_schema
"context": { // Optional: extra kontext för AI
"subject_id": "<uuid>",
"subject_type": "Transaction"
}
}
```
**Svar:**
```json
{
"capability_id": "ekonomi.classification",
"version": "1.0.0",
"invocation_id": "<uuid>", // Unikt anrops-ID för audit
"output": { ... }, // Validerat mot capability.output_schema
"confidence": 0.91,
"decision_required": true, // Alltid true om can_auto_execute=false
"suggestion": { ... }, // Presentationsformat för UI
"audit_ref": "<uuid>" // Referens till loggpost
}
```
#### 4.2 Konsumtionsmönster i modulkod
```javascript
// Rätt mönster
const result = await capabilityRegistry.invoke('ekonomi.classification', {
version: '1.0.0',
input: { transaction_id: txId, description: tx.description, amount: tx.amount },
requestedBy: currentUser.id
});
// Presentera förslaget för användaren
ui.showSuggestion({
label: 'Föreslaget konto',
value: result.output.suggested_account,
confidence: result.confidence,
invocationId: result.invocation_id // Måste sparas om användaren accepterar
});
// ALDRIG detta:
// await db.updateTransaction(txId, { account: result.output.suggested_account });
// ↑ AI får inte skriva direkt till bokföring, oavsett confidence
```
#### 4.3 Acceptans-mönster
```javascript
// När användaren accepterar ett AI-förslag
await capabilityRegistry.recordDecision({
invocation_id: result.invocation_id,
decision: 'accepted', // 'accepted' | 'modified' | 'rejected'
decided_by: currentUser.id,
final_value: chosenAccount,
modification_reason: null
});
// Sedan applicera beslutet
await economyService.postJournalEntry({ ...entry, account: chosenAccount });
```
---
### 5. Lifecycle-hantering
#### Registrering
1. Modul-team skapar ett PR med ny capability-definition
2. Architecture Team granskar `decision_boundary` och `allowed_decision_sources`
3. Security review om `audit_config.pii_fields` är tomt (alla fält måste granskas)
4. Merged → automatisk registrering vid deploy
#### Versionshantering
- Bakåtkompatibla ändringar → minor version (`1.0.0 → 1.1.0`)
- Breaking changes → major version (`1.0.0 → 2.0.0`)
- Gamla versioner hålls aktiva i **90 dagar** efter att ny major-version lanserats
- Konsumenter måste upgraderas inom 90 dagars deprecated-period
#### Deprecation-flöde
```
status: active → deprecated (sunset_date sätts, superseded_by pekar på ny version)
→ sunset_date passeras → status: disabled
→ anrop returnerar 410 Gone med referens till ny version
```
---
### 6. Enforcement
#### Vad händer om en modul försöker fatta beslut utanför sin capability?
**Scenario A: Anrop till icke-registrerad capability**
```
HTTP 403 Forbidden
{
"error": "CAPABILITY_NOT_REGISTERED",
"message": "Capability 'ekonomi.auto_post' is not registered in the Capability Registry.",
"action_required": "Register the capability before use."
}
```
→ Loggas som SECURITY_VIOLATION i audit-systemet
→ Alert till Architecture Team
**Scenario B: `can_auto_execute = false` men modulen försöker direktskriva**
→ Enforcement på applikationsnivå: alla skrivanrop till bokföring kräver ett `invocation_id` som kan spåras till ett mänskligt `recordDecision`-anrop
→ Om `invocation_id` saknas eller inte är `accepted`: 403 + audit-logg
**Scenario C: Capability anropas av ej tillåten decision_source**
```
HTTP 403 Forbidden
{
"error": "DECISION_SOURCE_NOT_ALLOWED",
"capability_id": "ekonomi.compliance_review",
"attempted_source": "system:scheduler",
"allowed_sources": ["human:auditor", "human:manager"]
}
```
**Scenario D: Capability anropas utanför versionens supportfönster**
```
HTTP 410 Gone
{
"error": "CAPABILITY_VERSION_SUNSET",
"superseded_by": "ekonomi.classification@2.0.0"
}
```
---
## Konsekvenser
### Positiva
- **Full spårbarhet:** Varje AI-handling kan kopplas till en människa som fattade beslutet
- **Revision-ready:** Vid extern revision kan vi visa exakt vilka AI-funktioner använts, av vem, med vilket confidence
- **GDPR-kompabilitet:** `pii_fields` i audit_config gör att vi aldrig loggar personnummer etc. i klartext
- **Modularitet:** Capabilities kan delas mellan moduler (t.ex. kan CRM använda `document_extraction`)
### Negativa / risker
- **Overhead vid ny feature:** Varje ny AI-funktion kräver Architecture Team-granskning → kan upplevas som flaskhals
- **Version-pinning-disciplin:** Moduler som inte uppgraderar i tid blockeras av sunset
- **Registry som SPOF:** Om registret är nere kan inga AI-anrop göras — kräver hög tillgänglighet och lokal cache-fallback
---
## Implementation
### Fas 1 (Ekonomimodulen, nu)
1. Skapa `capability_registry`-tabell i PostgreSQL
2. Implementera `POST /api/v1/capabilities/{id}/invoke` med schema-validering
3. Registrera de 6 initial-capabilities ovan
4. Lägg till audit-loggning för varje anrop
### Fas 2 (plattformsnivå)
1. Capabilities Registry som standalone-tjänst (`:3260`)
2. gRPC-kontrakt för inter-service-kommunikation
3. Dashboard för capability-översikt och anropsstatistik
### Fas 3 (mognad)
1. Automatisk schema-drift-detektion
2. A/B-versionshantering med gradvis utrullning
3. Federated registry för externa AI-providers
---
## Öppna frågor
1. **Ska capabilities kunna kedjas?**
T.ex. `document_extraction``classification` som ett pipeline. Kräver att chain-invocation_id loggas.
2. **Hur hanteras LLM-specifik prompt-versionshantering?**
Capability-versionen bör inkludera prompt-template-version för reproducerbarhet.
3. **Ska `can_auto_execute: true` någonsin tillåtas?**
Möjligt för låg-risk, hög-confidence klassificering av intern data — men kräver separat Architecture Decision och Security Review.
4. **Multi-tenant capability-konfiguration?**
En tenant kan behöva inaktivera specifika capabilities (t.ex. av regulatoriska skäl). Registry bör ha tenant-override-stöd.