ADR-032: Severity (Class Taxonomy) vs Priority (Evidence-Gated Urgency)
Status
Accepted — 2026-06-04. Product decision by Sergey on sv0-platform#1395 ("Recalibrate standing-authority cluster severity defaults"), ratified and partially shipped. The priority-gating half landed in PR #1401 (resolving issue #1399), built on the honesty/parity fixes in PR #1400 (resolving issues #1397 and #1398). The user-facing display swap landed in PR #1403, and the drift-rule severity follow-up (#1402) landed in PR #1404 — so every step under #1395 is now shipped (see "What shipped" below).
Context
The product surfaced a single number — severity — and used it for two unrelated jobs at once: classifying how bad a kind of problem is, and ranking how urgently to act on a specific instance. Because the cluster/finding severity default is a flat constant ("standing authority is High", "orphaned sensitive is Critical"), action-oriented surfaces produced contradictions that undercut trust:
Critical · Standing authority
when the underlying evidence was a provisioned-but-never-exercised path — i.e. the system was crying wolf. The headline said Critical purely because the cluster's class default is high and the path could reach a sensitive domain, not because anything had happened.
Sergey's framing (#1395) named the two questions the one field was straddling:
- severity answers: how bad is this class of problem if it is real?
- priority answers: how urgently should a human act on this specific instance?
The brief, top-exposure, cluster-card, and list surfaces are action-oriented, so they must lead with priority, not raw class severity.
What "proof" means here
The platform already distinguishes structural claims from observed ones (the evidence-classification layer: claim_type + evidence_strength, surfaced as "Configured" vs "Confirmed"). This ADR makes that distinction govern urgency:
- Proof of impact = observed, resource-scoped execution in the window.
- Posture = everything that describes what could happen but has not been observed: structural reachability to a sensitive domain, a structural wildcard/destructive action, an attribution or governance gap, or standing (dormant) authority.
- A sensitivity label on a reachable path is posture, not confirmed access. "Verified sensitive data access" counts as proof only when access or data movement is actually observed.
Posture is real signal and stays visible — it just must not, on its own, escalate an instance to the most urgent band.
Decision
Keep two separate axes. Stop conflating them.
1. severity — class taxonomy, backend/API only
severity remains the per-cluster / per-finding class default ("how bad if real"). It is evidence-independent and stays in the backend and API for rule taxonomy, analytics, and filtering. It is not the primary incident label on action-oriented UI. The RISK_CLUSTER_DEFS severity values are not recalibrated down — Sergey's explicit call was to retain severity as the taxonomy axis, not to flatten it, because the alarming-headline problem is solved by displaying priority instead.
2. priority — evidence-gated urgency, displayed
priority ∈ {critical, high, moderate, low} is computed from evidence (computeClusterPriority, src/services/risk-cluster-service.ts) and is the value shown on action-ranking surfaces. Its thresholds:
| Priority | Condition |
|---|---|
| Critical | Observed execution plus an aggravator: a destructive/admin action was actually exercised; or active sensitive access with an ownership governance failure (owner missing/lapsed); or confirmed egress of sensitive data. |
| High | Structural wildcard/destructive authority (a verified effective-privilege capability, e.g. dangerous_blast_radius); or observed execution on a sensitive path with no aggravator. |
| Moderate | Any single posture signal with zero proven impact — structural sensitive reach, governance/attribution gap, dormant authority, or an egress finding type. |
| Low | Residual — no posture signal, no execution. |
3. Not all governance gaps are equal
Only an ownership governance failure (orphaned_ownership — an owner is missing or lapsed) is material enough to aggravate observed execution to Critical. An attribution gap (unknown_identity_binding) or permission drift (scope_drift) is posture only and must not push an instance to Critical priority. Attribution uncertainty is not confirmed harmful access (#1395; the #1401 fidelity fix split the previously-conflated hasGovernanceFailure signal into hasOwnershipGovernanceFailure vs the rest).
4. UI consequence (the #1395 display swap)
On briefs, top exposure, cluster cards, and other action-ranking surfaces:
- Replace the visible severity chip with priority — labels
Critical priority/High priority/Moderate priority/Low priority. - Keep the existing activity chip (
Active/Standing authority). - Keep
severityavailable in the backend/API (taxonomy, analytics, filtering). - Do not introduce a new evidence chip as part of this change.
What shipped under this decision
- PR #1400 (issues #1397, #1398) — path-evaluator honesty + cross-layer severity parity. Honesty (#1397): the not-exercised branch no longer claims
execution_observed; a finding with zero execution evidence emitspermission_exists/structural("Configured", not "Confirmed"). Parity (#1398): the same condition no longer emits one severity from the entity-rule pass and a different one from the path-evaluator pass; the affected path-evaluator findings (external_egress,reachable_sensitive_domain,unproven_execution) were unified to a flatmediumseverity. - PR #1401 (issue #1399) — cluster priority gating:
computeClusterPriorityintroduced; posture (standing authority, structural dangerous actions, attribution/drift gaps) can no longer reach Critical with zero execution; ownership-vs-attribution governance failures separated. - PR #1404 (issue #1402) — drift-rule severity made evidence-independent:
scope_driftandreachability_driftno longer fold execution into severity. Severity is now sensitivity-only (sensitive → high, elsemedium) across all four emitters — the entity rules (scope-drift.ts,reachability-drift.ts) and the path-evaluator's path-level duplicates — so the two layers agree (the path-levelscope_driftalso dropped anegress → highescalation the entity rule never had). Execution drives cluster priority, not finding severity. (The W1 demo seed that hand-stamped acriticalscope_drift was corrected in #1412.)
Consequences
Positive
- Action surfaces stop contradicting their own evidence — no more
Critical · Standing authorityon a never-exercised path. severitystays a stable analytics/filtering axis;prioritybecomes the single action-ranking signal, gated on observed execution.- The "Configured vs Confirmed" honesty signal and the urgency model now agree.
Negative / trade-offs
- Two parallel axes to keep coherent. Docs and UI must be explicit about which one a given surface shows, or the conflation creeps back.
priorityis deliberately conservative — a genuinely urgent instance with no captured execution evidence reads as Moderate until evidence lands. This is the intended bias (don't cry wolf), but it shifts weight onto execution-evidence coverage.
Resolved — drift-rule severity realignment (#1402 → #1404)
- The entity- and path-level drift rules (
scope_drift,reachability_drift) previously folded execution evidence into severity (exercised && touchesSensitive→ critical /exercised || touchesSensitive→ high / else medium). PR #1404 made their severity sensitivity-only (sensitive → high, elsemedium) across all four emitters, so severity is now evidence-independent everywhere and the entity/path layers agree. Execution drives cluster priority viacomputeClusterPriority, not finding severity. (#1400 had already aligned the path-evaluator'sexternal_egress/reachable_sensitive_domain/unproven_executionfindings; #1404 finished the two drift rules.)
When to Reconsider
- A customer needs severity-driven SLAs (act-within-N-hours keyed to the class taxonomy) — then severity re-enters the action path and the two axes must be reconciled explicitly rather than by display choice.
- Stakeholders demand a single combined score. If so, derive it from both axes deterministically; do not collapse back to one ungated field.
- Priority gating proves too conservative in the field (real urgency consistently sitting at Moderate because execution evidence is under-collected) — fix the evidence pipeline first; only loosen the thresholds if that is insufficient.