Decisions and blockers
The verdict lives in three fields. decision.level is authoritative.
| Field | Type | Meaning |
|---|---|---|
decision.level | SAFE | WARNING | CRITICAL | ERROR | The verdict. |
decision.allow | bool | false when blocked. |
decision.blockers | []string | Every reason it's CRITICAL. |
Levels
| Level | allow | When |
|---|---|---|
SAFE | true | No blocker, and the score meets the profile's SAFE threshold. |
WARNING | true | Attention needed (low score, unstable pods) but no deterministic blocker. |
CRITICAL | false | At least one deterministic blocker. |
ERROR | — | The analysis couldn't run (e.g. targetVersion ≤ current version). |
Deterministic blockers
A CRITICAL verdict comes only from conditions the engine can prove — never from the score:
| Blocker | Condition |
|---|---|
| PDB blocking | A PodDisruptionBudget that would stall a node drain. |
| CPU pressure | CPU requests > 90% of allocatable. |
| Memory pressure | Memory requests > 90% of allocatable. |
| Severely unstable | Not-ready pods beyond the profile's block ratio. |
| Incompatible add-on | An add-on version unsupported on the target (with the version to upgrade to). |
| Lost PVC | A PersistentVolumeClaim in the Lost phase. |
Every match is recorded in decision.blockers, so mirops scan --enforce and the UI can show all reasons, not just the first. Fix them all to reach SAFE.
The score never blocks
CPU/memory pressure lowers the Capacity dimension of the score proportionally, but the block comes from the deterministic threshold (> 90%), independent of the score. A cluster can score well and still be CRITICAL; a low score alone is at most WARNING. See readiness vs. decision.