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:

APPLY

The current evaluation is conclusive and the returned final state may be applied immediately.

WAIT

The current evaluation is not yet conclusive. The supervisor should keep the evaluation cycle alive and re-evaluate later.

FAULT

The 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 = APPLY

    • final_state = ObsState.SCANNING

    • severity = MEDIUM

  • a temporary non-converged situation may return:

    • action = WAIT

    • final_state = None

    • severity = MEDIUM

Although both cases may have the same severity, they require different supervisor behaviour.

Decision structure

A Decision contains:

final_state

The target observation state to apply, if the policy has reached a conclusive result.

severity

The diagnostic severity associated with the evaluated condition.

fault_msg

An optional human-readable message describing the condition.

hard_fault

A legacy boolean indicating whether the condition should be treated as a component fault.

action

An 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:

APPLIED

The supervisor applied the resolved observation state and the current evaluation cycle is complete.

WAIT

The supervisor did not apply a final state yet. The cycle remains open and must be evaluated again.

FAULT

The 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.