Skip to main content

termivar_scanner/decision_loop/
command.rs

1//! Side-effect-free commands emitted by the decision state machine.
2
3use super::{Deserialize, Serialize, VerificationCase};
4
5/// Why an action execution was emitted.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(rename_all = "snake_case")]
8#[non_exhaustive]
9pub enum DecisionActionOrigin {
10    /// Requested by a host runtime to establish initial observations.
11    Bootstrap,
12    /// Selected by utility planning.
13    Planned,
14    /// Scheduled by adaptive policy.
15    Adaptive,
16    /// Re-issued after adaptive backpressure.
17    Retry,
18}
19
20/// Stable terminal reason for a decision session.
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
22#[serde(rename_all = "snake_case")]
23#[non_exhaustive]
24pub enum DecisionStopReason {
25    /// A verifier confirmed the current objective.
26    ObjectiveComplete,
27    /// Planning found no executable action.
28    NoEligibleAction,
29    /// Policy requires a human decision.
30    HumanReview,
31    /// Adaptive transition limits were exhausted.
32    AdaptationLimit,
33    /// The outer action-cycle guard was exhausted.
34    ActionCycleLimit,
35    /// A host runtime exhausted its side-effect resource envelope.
36    RuntimeBudgetLimit,
37    /// The host explicitly cancelled the target-scoped runtime.
38    CancelledByHost,
39}
40
41/// Side-effect-free command consumed by a runner or scheduler.
42#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
43#[serde(tag = "command", rename_all = "snake_case")]
44#[non_exhaustive]
45pub enum DecisionLoopCommand {
46    /// Execute one action and record its observations as evidence.
47    ExecuteAction {
48        /// Verification identity attached to the execution.
49        case: VerificationCase,
50        /// Concrete executor selected by the planner, when applicable.
51        executor: Option<String>,
52        /// Source of the execution request.
53        origin: DecisionActionOrigin,
54        /// Required scheduler delay before execution.
55        delay_ms: Option<u64>,
56    },
57    /// Collect explicit probe evidence for an unresolved case.
58    CollectActiveEvidence {
59        /// Case awaiting active evidence.
60        case: VerificationCase,
61    },
62    /// Re-run reasoning and utility planning.
63    Replan,
64    /// Stop because the current objective was verified.
65    Complete {
66        /// Completed verification case.
67        case: VerificationCase,
68    },
69    /// Preserve the case for a human decision.
70    AwaitHumanReview {
71        /// Case requiring review.
72        case: VerificationCase,
73    },
74    /// Stop deterministically at a loop boundary.
75    Halt {
76        /// Reason no further command will be emitted.
77        reason: DecisionStopReason,
78    },
79}
80
81pub(crate) fn command_requiring_host_policy_context(
82    command: &DecisionLoopCommand,
83) -> Option<&'static str> {
84    match command {
85        DecisionLoopCommand::ExecuteAction {
86            origin: DecisionActionOrigin::Adaptive,
87            ..
88        } => Some("adaptive_execute_action"),
89        DecisionLoopCommand::ExecuteAction {
90            origin: DecisionActionOrigin::Retry,
91            ..
92        } => Some("retry_execute_action"),
93        DecisionLoopCommand::CollectActiveEvidence { .. } => Some("collect_active_evidence"),
94        DecisionLoopCommand::Replan => Some("replan"),
95        DecisionLoopCommand::ExecuteAction { .. }
96        | DecisionLoopCommand::Complete { .. }
97        | DecisionLoopCommand::AwaitHumanReview { .. }
98        | DecisionLoopCommand::Halt { .. } => None,
99    }
100}
101
102pub(crate) fn execution_command_action_id(command: &DecisionLoopCommand) -> Option<&str> {
103    match command {
104        DecisionLoopCommand::ExecuteAction { case, .. }
105        | DecisionLoopCommand::CollectActiveEvidence { case } => Some(case.action_id()),
106        DecisionLoopCommand::Replan
107        | DecisionLoopCommand::Complete { .. }
108        | DecisionLoopCommand::AwaitHumanReview { .. }
109        | DecisionLoopCommand::Halt { .. } => None,
110    }
111}