446 lines
15 KiB
Markdown
446 lines
15 KiB
Markdown
|
|
# 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.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`
|
|||
|
|
```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.
|