- 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
15 KiB
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
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.0–1.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
{
"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
{
"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
{
"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
{
"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
{
"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
{
"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:
{
"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
// 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
// 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
- Modul-team skapar ett PR med ny capability-definition
- Architecture Team granskar
decision_boundaryochallowed_decision_sources - Security review om
audit_config.pii_fieldsär tomt (alla fält måste granskas) - 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_fieldsi 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)
- Skapa
capability_registry-tabell i PostgreSQL - Implementera
POST /api/v1/capabilities/{id}/invokemed schema-validering - Registrera de 6 initial-capabilities ovan
- Lägg till audit-loggning för varje anrop
Fas 2 (plattformsnivå)
- Capabilities Registry som standalone-tjänst (
:3260) - gRPC-kontrakt för inter-service-kommunikation
- Dashboard för capability-översikt och anropsstatistik
Fas 3 (mognad)
- Automatisk schema-drift-detektion
- A/B-versionshantering med gradvis utrullning
- Federated registry för externa AI-providers
Öppna frågor
-
Ska capabilities kunna kedjas?
T.ex.document_extraction→classificationsom ett pipeline. Kräver att chain-invocation_id loggas. -
Hur hanteras LLM-specifik prompt-versionshantering?
Capability-versionen bör inkludera prompt-template-version för reproducerbarhet. -
Ska
can_auto_execute: truenå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. -
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.