# Risk Engine Spec (Layer 6 MVP)

Date: 2026-03-23  
Status: implemented in `canonical_layer/risk.py`

## 1. Purpose

Transform anomaly signals into explainable risk patterns and a global risk score.

## 2. Inputs

- `feature_runs` (latest successful run context)
- `anomaly_signals` for selected feature run
- optional explicit `source_feature_run_id`

## 3. Outputs

### `risk_runs`

Execution journal for each risk-scoring run:

- status, timestamps
- source feature run
- patterns written
- global score
- details/error

### `risk_patterns`

Explainable risk patterns:

- `pattern_key`
- `severity`
- `scope`, `scope_id`
- `score`, `confidence`
- `details` (breakdown + evidence examples)
- `is_active`

Always includes:

- `global_risk_summary`

## 4. Domain mapping

Anomaly signal → risk domain:

- `stale_refresh`, `missing_refresh_baseline`, `no_canonical_data` → `operational_freshness`
- `high_link_degree` → `suspicious_link_hub`
- `entity_count_drift` → `structural_drift`
- `empty_display_share_high` → `data_quality`
- unknown → `miscellaneous`

## 5. Scoring model (MVP)

1. Convert each anomaly to normalized signal score.
2. Aggregate per domain into domain risk pattern.
3. Compute global weighted score over domains.
4. Map score to severity via thresholds:
   - `RISK_MEDIUM_THRESHOLD`
   - `RISK_HIGH_THRESHOLD`

## 6. Runtime interfaces

API:

- `POST /risk/run`
- `GET /risk/stats`
- `GET /risk/runs`
- `GET /risk/patterns`

CLI:

- `python scripts/run_risk.py`
- `powershell scripts/run_risk.ps1`
