Decision model
A consistency evaluation produces a Decision describing the policy interpretation of the current system snapshot.
The decision is the semantic contract between the consistency policy and the CSP-specific supervision logic. It does not describe the final outcome of the generic supervision loop; rather, it expresses what the policy believes should happen next for the current evaluation.
A Decision captures:
the observing state that should eventually be applied;
diagnostic information describing inconsistencies or degraded conditions;
whether the condition represents a hard consistency fault;
the severity of the condition for operational and diagnostic purposes;
an explicit policy action describing what the supervisor should do next.
Why an explicit action is needed
Historically, the supervisor inferred control flow indirectly from fields
such as hard_fault, severity, and final_state. This worked for
simple cases, but becomes ambiguous once the domain needs to distinguish
between:
valid but degraded operation,
temporary non-convergence,
waiting for delayed subsystem events,
fault conditions.
In particular, Severity alone is not sufficient to drive supervisor
behaviour. The same severity level may correspond to very different
operational meanings. For example, a MEDIUM severity may represent:
a degraded-but-acceptable scan, where the final state should still be applied immediately; or
a temporary situation where the supervisor should wait for more information before concluding.
For this reason, the policy now exposes an explicit PolicyAction to
describe the intended control flow.
PolicyAction
PolicyAction is a high-level control signal returned by the policy.
The currently supported actions are:
APPLYThe current evaluation is conclusive and the returned final state may be applied immediately.
WAITThe current evaluation is not yet conclusive. The supervisor should keep the evaluation cycle alive and re-evaluate later.
FAULTThe current condition is considered unsafe or unrecoverable and the supervisor should transition to
FAULT.
At present, PolicyAction is introduced as an explicit, future-proof
representation of policy intent. Existing code may still preserve backward
compatibility by deriving behaviour from legacy fields where necessary.
Severity versus action
Severity and PolicyAction express two different dimensions of a
policy result.
Severity answers:
how serious the detected condition is;
how it should be represented in diagnostics, logs, alarms, or quality reporting.
PolicyAction answers:
what the supervisor should do next.
This separation makes policy intent explicit and avoids overloading severity with control-flow meaning.
Examples:
a degraded but acceptable scan may return:
action = APPLYfinal_state = ObsState.SCANNINGseverity = MEDIUM
a temporary non-converged situation may return:
action = WAITfinal_state = Noneseverity = MEDIUM
Although both cases may have the same severity, they require different supervisor behaviour.
Decision structure
A Decision contains:
final_stateThe target observation state to apply, if the policy has reached a conclusive result.
severityThe diagnostic severity associated with the evaluated condition.
fault_msgAn optional human-readable message describing the condition.
hard_faultA legacy boolean indicating whether the condition should be treated as a component fault.
actionAn explicit control signal indicating whether the supervisor should apply, wait, or fault.
This preserves compatibility with existing policy implementations while making future control-flow extensions clearer and more robust.
Evaluation outcome
While Decision represents the result of policy evaluation,
EvaluationOutcome represents the result of supervisor execution
for one evaluation cycle.
This distinction is important and intentional.
Decision vs EvaluationOutcome
Decision is produced by policy.evaluate(...) and is
domain-oriented. It expresses the policy interpretation of the current
snapshot, including:
the selected action,
the resolved state, if any,
the severity,
any diagnostic message.
EvaluationOutcome is produced by
ObservationSupervisor._evaluate_and_publish() and is loop-oriented.
It tells the generic supervision loop whether the current evaluation
cycle has:
completed successfully,
remains pending and should be retried,
terminated in fault.
In other words:
the policy decides what should happen;
the supervisor reports what actually happened in this evaluation cycle.
Why this distinction is necessary
In the original design, the generic supervisor assumed that every evaluation was conclusive once triggered. This assumption is no longer sufficient once the system supports explicit waiting and multi-step evaluation behaviour.
For example, when the policy returns WAIT, the CSP-specific
supervisor does not apply a final state and does not fault. Instead, it
keeps the supervision cycle active so that the generic supervisor can
re-evaluate later.
To support this behaviour cleanly, _evaluate_and_publish() now
returns an EvaluationOutcome. This allows the generic supervisor to
decide whether to:
stop the current cycle,
keep the cycle alive,
or terminate because a fault has been reached.
Typical outcomes
A typical EvaluationOutcome may represent one of the following cases:
APPLIEDThe supervisor applied the resolved observation state and the current evaluation cycle is complete.
WAITThe supervisor did not apply a final state yet. The cycle remains open and must be evaluated again.
FAULTThe supervisor transitioned the resource into fault and the cycle is complete.
This separation keeps the generic supervision loop independent from domain-specific policy details, while still allowing the CSP-specific supervisor to support richer policy semantics.