Skip to main content

yarli_cli/yarli-core/src/
domain.rs

1//! Core domain primitives: Run, Task, Evidence, Gate, PolicyDecision, etc.
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use uuid::Uuid;
6
7/// Unique identifier for a run.
8pub type RunId = Uuid;
9
10/// Unique identifier for a task.
11pub type TaskId = Uuid;
12
13/// Unique identifier for an event.
14pub type EventId = Uuid;
15
16/// Unique identifier for a correlation chain.
17pub type CorrelationId = Uuid;
18
19/// Unique identifier for a worktree binding.
20pub type WorktreeId = Uuid;
21
22/// Unique identifier for a merge intent.
23pub type MergeIntentId = Uuid;
24
25/// Entity types in the system.
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
27#[serde(rename_all = "snake_case")]
28pub enum EntityType {
29    Run,
30    Task,
31    Worktree,
32    Merge,
33    Command,
34    Gate,
35    Policy,
36}
37
38/// An immutable event in the event log.
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct Event {
41    pub event_id: EventId,
42    pub occurred_at: DateTime<Utc>,
43    pub entity_type: EntityType,
44    pub entity_id: String,
45    pub event_type: String,
46    pub payload: serde_json::Value,
47    pub correlation_id: CorrelationId,
48    pub causation_id: Option<EventId>,
49    pub actor: String,
50    pub idempotency_key: Option<String>,
51}
52
53/// Evidence proving a task outcome.
54#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct Evidence {
56    pub evidence_id: Uuid,
57    pub task_id: TaskId,
58    pub run_id: RunId,
59    pub evidence_type: String,
60    pub payload: serde_json::Value,
61    pub created_at: DateTime<Utc>,
62}
63
64/// A policy decision record.
65#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct PolicyDecision {
67    pub decision_id: Uuid,
68    pub run_id: RunId,
69    pub actor: String,
70    pub action: String,
71    pub outcome: PolicyOutcome,
72    pub rule_id: String,
73    pub reason: String,
74    pub decided_at: DateTime<Utc>,
75}
76
77/// Outcome of a policy evaluation.
78#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
79#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
80pub enum PolicyOutcome {
81    Allow,
82    Deny,
83    RequireApproval,
84}
85
86/// Exit reason codes for runs.
87#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
88#[serde(rename_all = "snake_case")]
89pub enum ExitReason {
90    CompletedAllGates,
91    BlockedOpenTasks,
92    BlockedGateFailure,
93    MergeConflict,
94    FailedPolicyDenial,
95    FailedRuntimeError,
96    CancelledByOperator,
97    DrainedByOperator,
98    TimedOut,
99    StalledNoProgress,
100}
101
102impl std::fmt::Display for ExitReason {
103    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104        match self {
105            Self::CompletedAllGates => write!(f, "completed_all_gates"),
106            Self::BlockedOpenTasks => write!(f, "blocked_open_tasks"),
107            Self::BlockedGateFailure => write!(f, "blocked_gate_failure"),
108            Self::MergeConflict => write!(f, "merge_conflict"),
109            Self::FailedPolicyDenial => write!(f, "failed_policy_denial"),
110            Self::FailedRuntimeError => write!(f, "failed_runtime_error"),
111            Self::CancelledByOperator => write!(f, "cancelled_by_operator"),
112            Self::DrainedByOperator => write!(f, "drained_by_operator"),
113            Self::TimedOut => write!(f, "timed_out"),
114            Self::StalledNoProgress => write!(f, "stalled_no_progress"),
115        }
116    }
117}
118
119/// Provenance for cancellation-triggered shutdown.
120#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
121#[serde(rename_all = "snake_case")]
122pub enum CancellationSource {
123    Operator,
124    Sigint,
125    Sigterm,
126    Sw4rmPreemption,
127    Unknown,
128}
129
130impl std::fmt::Display for CancellationSource {
131    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132        match self {
133            Self::Operator => write!(f, "operator"),
134            Self::Sigint => write!(f, "sigint"),
135            Self::Sigterm => write!(f, "sigterm"),
136            Self::Sw4rmPreemption => write!(f, "sw4rm_preemption"),
137            Self::Unknown => write!(f, "unknown"),
138        }
139    }
140}
141
142/// Best-effort actor classification for cancellation origin.
143#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
144#[serde(rename_all = "snake_case")]
145pub enum CancellationActorKind {
146    Operator,
147    System,
148    Supervisor,
149    Unknown,
150}
151
152impl std::fmt::Display for CancellationActorKind {
153    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
154        match self {
155            Self::Operator => write!(f, "operator"),
156            Self::System => write!(f, "system"),
157            Self::Supervisor => write!(f, "supervisor"),
158            Self::Unknown => write!(f, "unknown"),
159        }
160    }
161}
162
163/// Pipeline stage where cancellation was observed.
164#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
165#[serde(rename_all = "snake_case")]
166pub enum CancellationStage {
167    Executing,
168    Retrying,
169    Verifying,
170    Unknown,
171}
172
173impl std::fmt::Display for CancellationStage {
174    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175        match self {
176            Self::Executing => write!(f, "executing"),
177            Self::Retrying => write!(f, "retrying"),
178            Self::Verifying => write!(f, "verifying"),
179            Self::Unknown => write!(f, "unknown"),
180        }
181    }
182}
183
184/// Structured cancellation provenance attached to cancellation terminal events.
185#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
186pub struct CancellationProvenance {
187    pub cancellation_source: CancellationSource,
188    #[serde(default)]
189    pub signal_name: Option<String>,
190    #[serde(default)]
191    pub signal_number: Option<i32>,
192    #[serde(default)]
193    pub sender_pid: Option<u32>,
194    #[serde(default)]
195    pub receiver_pid: Option<u32>,
196    #[serde(default)]
197    pub parent_pid: Option<u32>,
198    #[serde(default)]
199    pub process_group_id: Option<u32>,
200    #[serde(default)]
201    pub session_id: Option<u32>,
202    #[serde(default)]
203    pub tty: Option<String>,
204    #[serde(default)]
205    pub actor_kind: Option<CancellationActorKind>,
206    #[serde(default)]
207    pub actor_detail: Option<String>,
208    #[serde(default)]
209    pub stage: Option<CancellationStage>,
210}
211
212/// Safe modes for the orchestrator.
213#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
214#[serde(rename_all = "snake_case")]
215pub enum SafeMode {
216    /// Read-only, no mutations.
217    Observe,
218    /// Normal execution with policy.
219    Execute,
220    /// Only allowlisted commands.
221    Restricted,
222    /// Temporary elevated mode with high audit level.
223    Breakglass,
224}
225
226/// Command class for concurrency caps.
227#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
228#[serde(rename_all = "snake_case")]
229pub enum CommandClass {
230    Io,
231    Cpu,
232    Git,
233    Tool,
234}