ralph_workflow/reducer/event/pipeline_phase.rs
1//! Pipeline phase definitions.
2
3use serde::{Deserialize, Serialize};
4
5/// Pipeline phases for checkpoint tracking.
6///
7/// These phases represent the major stages of the Ralph pipeline.
8/// Reducers transition between phases based on events.
9///
10/// # Phase Transitions
11///
12/// ```text
13/// Planning → Development → Review → CommitMessage → FinalValidation → Finalizing → Complete
14/// ↓ ↓ ↓
15/// AwaitingDevFix → Interrupted
16/// ```
17///
18/// # Phase Descriptions
19///
20/// - **Planning**: Generate implementation plan for the iteration
21/// - **Development**: Execute plan, write code
22/// - **Review**: Review code changes, identify issues
23/// - **`CommitMessage`**: Generate commit message
24/// - **`FinalValidation`**: Final checks before completion
25/// - **Finalizing**: Cleanup operations (restore permissions, etc.)
26/// - **Complete**: Pipeline completed successfully
27/// - **`AwaitingDevFix`**: Terminal failure occurred, dev agent diagnosing
28/// - **Interrupted**: Pipeline terminated (success or failure)
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
30pub enum PipelinePhase {
31 Planning,
32 Development,
33 Review,
34 CommitMessage,
35 FinalValidation,
36 /// Finalizing phase for cleanup operations before completion.
37 ///
38 /// This phase handles:
39 /// - Restoring PROMPT.md write permissions
40 /// - Any other cleanup that must go through the effect system
41 Finalizing,
42 Complete,
43 /// Awaiting development agent to fix pipeline failure.
44 ///
45 /// This phase occurs when the pipeline encounters a terminal failure condition
46 /// (e.g., agent chain exhausted) but before transitioning to Interrupted. It
47 /// signals that the development agent should be invoked to diagnose and fix
48 /// the failure root cause.
49 ///
50 /// ## Failure Handling Flow
51 ///
52 /// 1. `ErrorEvent::AgentChainExhausted` occurs in any phase
53 /// 2. Reducer transitions state to `AwaitingDevFix`
54 /// 3. Orchestration determines `Effect::TriggerDevFixFlow`
55 /// 4. Handler executes `TriggerDevFixFlow`:
56 /// a. Writes completion marker to .`agent/tmp/completion_marker` (failure status)
57 /// b. Emits `DevFixTriggered` event
58 /// c. Dispatches dev-fix agent
59 /// d. Emits `DevFixCompleted` event
60 /// e. Emits `CompletionMarkerEmitted` event
61 /// 5. DevFixTriggered/DevFixCompleted events: no state change (stays in `AwaitingDevFix`)
62 /// 6. `CompletionMarkerEmitted` event: transitions to Interrupted
63 /// 7. Orchestration determines `Effect::SaveCheckpoint` for Interrupted
64 /// 8. Handler saves checkpoint, increments `checkpoint_saved_count`
65 /// 9. Event loop recognizes `is_complete()` == true and exits successfully
66 ///
67 /// ## Event Loop Termination Guarantees
68 ///
69 /// The event loop MUST NOT exit with completed=false when in `AwaitingDevFix` phase.
70 /// The failure handling flow is designed to always complete with:
71 /// - Completion marker written to filesystem
72 /// - State transitioned to Interrupted
73 /// - Checkpoint saved (`checkpoint_saved_count` > 0)
74 /// - Event loop returning completed=true
75 ///
76 /// If the event loop exits with completed=false from `AwaitingDevFix`, this indicates
77 /// a critical bug (e.g., max iterations reached before checkpoint saved).
78 ///
79 /// ## Completion Marker Requirement
80 ///
81 /// The completion marker MUST be written before transitioning to Interrupted.
82 /// This ensures external orchestration systems (CI, monitoring) can detect
83 /// pipeline termination even if the event loop exits unexpectedly.
84 ///
85 /// ## Agent Chain Exhaustion Handling
86 ///
87 /// When in `AwaitingDevFix` phase with an exhausted agent chain, orchestration
88 /// falls through to phase-specific logic (`TriggerDevFixFlow`) instead of reporting
89 /// exhaustion again. This prevents infinite loops where exhaustion is reported
90 /// repeatedly.
91 ///
92 /// Transitions:
93 /// - From: Any phase where `AgentChainExhausted` error occurs
94 /// - To: Interrupted (after dev-fix attempt completes or fails)
95 AwaitingDevFix,
96 Interrupted,
97}
98
99impl std::fmt::Display for PipelinePhase {
100 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101 match self {
102 Self::Planning => write!(f, "Planning"),
103 Self::Development => write!(f, "Development"),
104 Self::Review => write!(f, "Review"),
105 Self::CommitMessage => write!(f, "Commit Message"),
106 Self::FinalValidation => write!(f, "Final Validation"),
107 Self::Finalizing => write!(f, "Finalizing"),
108 Self::Complete => write!(f, "Complete"),
109 Self::AwaitingDevFix => write!(f, "Awaiting Dev Fix"),
110 Self::Interrupted => write!(f, "Interrupted"),
111 }
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
120 fn test_pipeline_phase_display() {
121 assert_eq!(format!("{}", PipelinePhase::Planning), "Planning");
122 assert_eq!(format!("{}", PipelinePhase::Development), "Development");
123 assert_eq!(format!("{}", PipelinePhase::Review), "Review");
124 assert_eq!(
125 format!("{}", PipelinePhase::CommitMessage),
126 "Commit Message"
127 );
128 assert_eq!(
129 format!("{}", PipelinePhase::FinalValidation),
130 "Final Validation"
131 );
132 assert_eq!(format!("{}", PipelinePhase::Finalizing), "Finalizing");
133 assert_eq!(format!("{}", PipelinePhase::Complete), "Complete");
134 assert_eq!(
135 format!("{}", PipelinePhase::AwaitingDevFix),
136 "Awaiting Dev Fix"
137 );
138 assert_eq!(format!("{}", PipelinePhase::Interrupted), "Interrupted");
139 }
140}