ralph_workflow/checkpoint/
run_context.rs1use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct RunContext {
19 pub run_id: String,
21 pub parent_run_id: Option<String>,
23 pub resume_count: u32,
25 pub actual_developer_runs: u32,
27 pub actual_reviewer_runs: u32,
29}
30
31impl RunContext {
32 pub fn new() -> Self {
34 Self {
35 run_id: uuid::Uuid::new_v4().to_string(),
36 parent_run_id: None,
37 resume_count: 0,
38 actual_developer_runs: 0,
39 actual_reviewer_runs: 0,
40 }
41 }
42
43 pub fn from_checkpoint(checkpoint: &super::PipelineCheckpoint) -> Self {
45 Self {
46 run_id: uuid::Uuid::new_v4().to_string(), parent_run_id: Some(checkpoint.run_id.clone()),
48 resume_count: checkpoint.resume_count + 1,
49 actual_developer_runs: checkpoint.actual_developer_runs,
50 actual_reviewer_runs: checkpoint.actual_reviewer_runs,
51 }
52 }
53
54 #[cfg(test)]
56 pub fn with_developer_runs(mut self, runs: u32) -> Self {
57 self.actual_developer_runs = runs;
58 self
59 }
60
61 #[cfg(test)]
63 pub fn with_reviewer_runs(mut self, runs: u32) -> Self {
64 self.actual_reviewer_runs = runs;
65 self
66 }
67
68 pub fn record_developer_iteration(&mut self) {
70 self.actual_developer_runs += 1;
71 }
72
73 pub fn record_reviewer_pass(&mut self) {
75 self.actual_reviewer_runs += 1;
76 }
77}
78
79impl Default for RunContext {
80 fn default() -> Self {
81 Self::new()
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88 use crate::checkpoint::state::{
89 AgentConfigSnapshot, CheckpointParams, CliArgsSnapshot, PipelineCheckpoint, PipelinePhase,
90 RebaseState,
91 };
92
93 #[test]
94 fn test_run_context_new() {
95 let ctx = RunContext::new();
96 assert!(!ctx.run_id.is_empty());
97 assert!(ctx.parent_run_id.is_none());
98 assert_eq!(ctx.resume_count, 0);
99 assert_eq!(ctx.actual_developer_runs, 0);
100 assert_eq!(ctx.actual_reviewer_runs, 0);
101 }
102
103 #[test]
104 fn test_run_context_from_checkpoint() {
105 let cli_args = CliArgsSnapshot::new(5, 2, None, false, true, 2, false, None);
107 let dev_config =
108 AgentConfigSnapshot::new("claude".into(), "cmd".into(), "-o".into(), None, true);
109 let rev_config =
110 AgentConfigSnapshot::new("codex".into(), "cmd".into(), "-o".into(), None, true);
111
112 let original_run_id = uuid::Uuid::new_v4().to_string();
113 let checkpoint = PipelineCheckpoint::from_params(CheckpointParams {
114 phase: PipelinePhase::Development,
115 iteration: 2,
116 total_iterations: 5,
117 reviewer_pass: 0,
118 total_reviewer_passes: 2,
119 developer_agent: "claude",
120 reviewer_agent: "codex",
121 cli_args,
122 developer_agent_config: dev_config,
123 reviewer_agent_config: rev_config,
124 rebase_state: RebaseState::default(),
125 git_user_name: None,
126 git_user_email: None,
127 run_id: &original_run_id,
128 parent_run_id: None,
129 resume_count: 1,
130 actual_developer_runs: 2,
131 actual_reviewer_runs: 0,
132 });
133
134 let run_ctx = RunContext::from_checkpoint(&checkpoint);
135
136 assert_ne!(
137 run_ctx.run_id, original_run_id,
138 "new run_id should be generated"
139 );
140 assert_eq!(run_ctx.parent_run_id, Some(original_run_id));
141 assert_eq!(run_ctx.resume_count, 2, "resume_count should increment");
142 assert_eq!(run_ctx.actual_developer_runs, 2);
143 assert_eq!(run_ctx.actual_reviewer_runs, 0);
144 }
145
146 #[test]
147 fn test_run_context_with_developer_runs() {
148 let ctx = RunContext::new().with_developer_runs(5);
149 assert_eq!(ctx.actual_developer_runs, 5);
150 }
151
152 #[test]
153 fn test_run_context_with_reviewer_runs() {
154 let ctx = RunContext::new().with_reviewer_runs(3);
155 assert_eq!(ctx.actual_reviewer_runs, 3);
156 }
157}