Files
boc/docs/arc/ARC-002-capability-registry.md
T
Bernt bae705aa97 ARCHITECTURE: NFC roadmap, edge AI, audit logging
- Add NFC ePassport roadmap (ICAO 9303, eIDAS)
- Add TensorFlow.js edge face detection (BlazeFace)
- Add structured audit logger (GDPR-compliant)
- Risk scoring support

Part of KYC Apple Native UX v1.1.0
2026-06-29 16:24:48 +00:00

446 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.