Adr 001

Status

Accepted

Context

Organizations and individuals need a systematic way to track, analyze, and mitigate risks. Risk analysis is best understood through a cause-outcome model: causalities lead to unwanted outcomes, and mitigations target either side.

This system will support hierarchical risk scoping through Systems and Components.

Decision

We will build risky, a dedicated risk analysis management daemon with a REST API based on a cause-outcome-mitigation model.

Domain Model

Core Entities

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                              SYSTEM                                     β”‚
β”‚                     "payment-service"                                    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”‚
β”‚  β”‚  COMPONENT      β”‚  β”‚  COMPONENT      β”‚  β”‚  COMPONENT      β”‚        β”‚
β”‚  β”‚  "api-gateway"  β”‚  β”‚  "database"     β”‚  β”‚  "worker-queue" β”‚        β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β”‚
β”‚           β”‚                    β”‚                    β”‚                   β”‚
β”‚           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                   β”‚
β”‚                              β”‚                                          β”‚
β”‚           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                       β”‚
β”‚           β”‚           RISK OUTCOME              β”‚  Severity: 1-5       β”‚
β”‚           β”‚  "data breach" (Severity: 5)      β”‚                       β”‚
β”‚           β”‚  Scope: System or Component         β”‚                       β”‚
β”‚           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                       β”‚
β”‚                          β”‚                                              β”‚
β”‚           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                            β”‚
β”‚           β–Ό              β–Ό              β–Ό                             β”‚
β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                   β”‚
β”‚    β”‚ CAUSALITY  β”‚  β”‚ CAUSALITY  β”‚  β”‚ CAUSALITY  β”‚  Likelihood: 1-5   β”‚
β”‚    β”‚ "no tls"   β”‚  β”‚ "shared    β”‚  β”‚ "weak      β”‚  TimeUnit: enum    β”‚
β”‚    β”‚ Scope:     β”‚  β”‚  creds"    β”‚  β”‚  passwords"β”‚                    β”‚
β”‚    β”‚ Component  β”‚  β”‚  Scope:    β”‚  β”‚  Scope:     β”‚                    β”‚
β”‚    β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β”‚  System    β”‚  β”‚  System     β”‚                    β”‚
β”‚          β”‚         β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜                    β”‚
β”‚          β”‚               β”‚               β”‚                             β”‚
β”‚          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                             β”‚
β”‚                          β”‚                                              β”‚
β”‚                          β–Ό                                              β”‚
β”‚                   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                        β”‚
β”‚                   β”‚ RISK PAIR  β”‚  (Causality Γ— Outcome)                 β”‚
β”‚                   β”‚ BaseScore  β”‚  = Severity Γ— Likelihood              β”‚
β”‚                   β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜                                        β”‚
β”‚                         β”‚                                               β”‚
β”‚              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                  β”‚
β”‚              β–Ό          β–Ό          β–Ό                                    β”‚
β”‚       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                         β”‚
β”‚       β”‚MITIGATIONβ”‚ β”‚MITIGATIONβ”‚ β”‚MITIGATIONβ”‚ Target: causality|outcome β”‚
β”‚       β”‚ "use tls"β”‚ β”‚"rotate   β”‚ β”‚ "2fa"    β”‚ Reduction: -1 to -5      β”‚
β”‚       β”‚ -5       β”‚ β”‚ creds"   β”‚ β”‚ -3       β”‚                          β”‚
β”‚       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Entity Definitions

Entity Attributes Description
System ID, Name, Description, CreatedAt Top-level container (service, infrastructure)
Component ID, SystemID, Name, Description, Type Sub-part within a system (database, API, queue)
RiskOutcome ID, Name, Description, SeverityScore (1-5), Scope (system|component), ScopeID Unwanted event that can occur
Causality ID, Name, Description, LikelihoodScore (1-5), TimeUnit, Scope (system|component), ScopeID Something that may cause an outcome
RiskPair ID, CausalityID, RiskOutcomeID, BaseScore, CalculatedAt, FinalScore Junction: Causality Γ— Outcome combination
Mitigation ID, RiskPairID, TargetType (causality|outcome), TargetID, Title, Description, ReductionValue (1-5), Status Action to reduce risk

Scoring Values

Scale Values
Severity/Likelihood 1 (very low) to 5 (very high)
Time Units per_request, per_day, per_week, per_month, per_year
Status planned, in_progress, implemented, verified
RiskPair Calculation Contained in service, refactorable

Goals

ID Goal Priority
G1 Hierarchical risk scoping via Systems and Components Must
G2 Cause-outcome risk modeling with multiple causalities per outcome Must
G3 Configurable risk calculation (contained, refactorable) Must
G4 Mitigation tracking with target selection (causality or outcome) Must
G5 REST API for full CRUD on all entities Must
G6 Risk aggregation and querying by system/component Should
G7 Export/import for bulk operations Could

Non-Goals

ID Non-Goal Rationale
NG1 Web interface Out of scope; backend only
NG2 Real-time updates REST polling sufficient
NG3 Authentication Network-level security (Tailscale)
NG4 External database SQLite embedded sufficient

Technical Stack

Component Choice
Language Go 1.24+
HTTP Router Chi
REST Framework Huma (OpenAPI generation)
Database SQLite (embedded)
SQL sqlc (type-safe)
Migrations golang-migrate
Config Environment vars

API Endpoints

Systems

GET /api/v1/systems POST /api/v1/systems GET /api/v1/systems/{id} PUT /api/v1/systems/{id} DELETE /api/v1/systems/{id} GET /api/v1/systems/{id}/components GET /api/v1/systems/{id}/risks GET /api/v1/systems/{id}/aggregate-risk

Components

GET /api/v1/systems/{systemId}/components POST /api/v1/systems/{systemId}/components GET /api/v1/components/{id} PUT /api/v1/components/{id} DELETE /api/v1/components/{id} GET /api/v1/components/{id}/risks

Risk Outcomes

GET /api/v1/risk-outcomes POST /api/v1/risk-outcomes GET /api/v1/risk-outcomes/{id} PUT /api/v1/risk-outcomes/{id} DELETE /api/v1/risk-outcomes/{id} GET /api/v1/risk-outcomes/{id}/pairs GET /api/v1/risk-outcomes/{id}/causalities

Causalities

GET /api/v1/causalities POST /api/v1/causalities GET /api/v1/causalities/{id} PUT /api/v1/causalities/{id} DELETE /api/v1/causalities/{id} GET /api/v1/causalities/{id}/outcomes

Risk Pairs

GET /api/v1/risk-pairs POST /api/v1/risk-pairs GET /api/v1/risk-pairs/{id} PUT /api/v1/risk-pairs/{id} DELETE /api/v1/risk-pairs/{id} GET /api/v1/risk-pairs/{id}/mitigations GET /api/v1/risk-pairs/{id}/calculate

Mitigations

GET /api/v1/mitigations POST /api/v1/mitigations GET /api/v1/mitigations/{id} PUT /api/v1/mitigations/{id} DELETE /api/v1/mitigations/{id} PATCH /api/v1/mitigations/{id}/status

Calculation Service Interface

type RiskCalculator interface { // Calculate base score for a risk pair CalculateBase(causality Causality, outcome RiskOutcome) int

// Apply mitigations to get final score
ApplyMitigations(baseScore int, mitigations []Mitigation) int

// Recalculate and persist a risk pair
Recalculate(pairID uuid.UUID) (RiskPair, error)

}

Initial implementation: Base = Severity Γ— Likelihood, Final = Base - sum(MitigationReduction)

Calculation Example

Component Value
Outcome “Data breach”
Outcome Severity 5
Causality “Using insecure channels”
Causality Likelihood 5 (always)
Base Score 5 Γ— 5 = 25
Mitigation “Use HTTPS” targeting causality
Reduction -5
Final Score 20

Authors: inful, Count
Date: 2026-02-17
Status: Accepted