Skip to main content

ralph/
progress.rs

1//! Execution phases and small progress-related contracts.
2//!
3//! Responsibilities:
4//! - Define `ExecutionPhase`, a stable enum used across run history and ETA estimation.
5//! - Provide small, display-oriented helpers (phase name/number/icon) without owning rendering.
6//!
7//! Not handled here:
8//! - Rendering progress bars/spinners (CLI or GUI).
9//! - Persisting execution history (see `crate::execution_history`).
10//! - ETA heuristics (see `crate::eta_calculator`).
11//!
12//! Invariants/assumptions:
13//! - Phase numbering is stable: planning=1, implementation=2, review=3, complete=0.
14//! - Serialization format is snake_case for stable on-disk contracts.
15
16use serde::{Deserialize, Serialize};
17
18/// Execution phases for multi-phase task workflows.
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
20#[serde(rename_all = "snake_case")]
21pub enum ExecutionPhase {
22    /// Phase 1: Planning and analysis.
23    Planning,
24    /// Phase 2: Implementation and CI.
25    Implementation,
26    /// Phase 3: Review and completion.
27    Review,
28    /// Execution completed.
29    Complete,
30}
31
32impl ExecutionPhase {
33    /// Returns the human-readable name for this phase.
34    pub fn as_str(&self) -> &'static str {
35        match self {
36            ExecutionPhase::Planning => "Planning",
37            ExecutionPhase::Implementation => "Implementation",
38            ExecutionPhase::Review => "Review",
39            ExecutionPhase::Complete => "Complete",
40        }
41    }
42
43    /// Returns the phase number (1-3) or 0 for Complete.
44    pub fn phase_number(&self) -> u8 {
45        match self {
46            ExecutionPhase::Planning => 1,
47            ExecutionPhase::Implementation => 2,
48            ExecutionPhase::Review => 3,
49            ExecutionPhase::Complete => 0,
50        }
51    }
52
53    /// Returns an icon representation of the phase.
54    ///
55    /// This is used for terminal output; GUIs should render their own icons.
56    pub fn icon(&self) -> &'static str {
57        match self {
58            ExecutionPhase::Planning => "▶",
59            ExecutionPhase::Implementation => "⚙",
60            ExecutionPhase::Review => "👁",
61            ExecutionPhase::Complete => "✓",
62        }
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69
70    #[test]
71    fn execution_phase_as_str() {
72        assert_eq!(ExecutionPhase::Planning.as_str(), "Planning");
73        assert_eq!(ExecutionPhase::Implementation.as_str(), "Implementation");
74        assert_eq!(ExecutionPhase::Review.as_str(), "Review");
75        assert_eq!(ExecutionPhase::Complete.as_str(), "Complete");
76    }
77
78    #[test]
79    fn execution_phase_number() {
80        assert_eq!(ExecutionPhase::Planning.phase_number(), 1);
81        assert_eq!(ExecutionPhase::Implementation.phase_number(), 2);
82        assert_eq!(ExecutionPhase::Review.phase_number(), 3);
83        assert_eq!(ExecutionPhase::Complete.phase_number(), 0);
84    }
85}