Skip to main content

ralph_workflow/app/
finalization.rs

1//! Pipeline finalization and cleanup.
2//!
3//! This module handles the final phase of the pipeline including cleanup,
4//! final summary, and checkpoint clearing.
5//!
6//! Note: PROMPT.md permission restoration is now handled by the reducer's
7//! `Effect::RestorePromptPermissions` during the `Finalizing` phase, ensuring
8//! it goes through the effect system for proper testability.
9
10use crate::banner::{print_final_summary, PipelineSummary};
11use crate::checkpoint::{clear_checkpoint, clear_checkpoint_with_workspace};
12use crate::config::Config;
13use crate::files::protection::monitoring::PromptMonitor;
14use crate::logger::Colors;
15use crate::logger::Logger;
16use crate::pipeline::Timer;
17use crate::pipeline::{AgentPhaseGuard, Stats};
18use crate::workspace::Workspace;
19
20/// Runtime statistics collected during pipeline execution.
21pub struct RuntimeStats<'a> {
22    pub timer: &'a Timer,
23    pub stats: &'a Stats,
24}
25
26/// Finalizes the pipeline: cleans up and prints summary.
27///
28/// Commits now happen per-iteration during development and per-cycle during review,
29/// so this function only handles cleanup and final summary.
30///
31/// # Arguments
32///
33/// * `workspace` - Optional workspace for file operations (enables testability)
34pub fn finalize_pipeline(
35    agent_phase_guard: &mut AgentPhaseGuard,
36    logger: &Logger,
37    colors: Colors,
38    config: &Config,
39    runtime: RuntimeStats<'_>,
40    prompt_monitor: Option<PromptMonitor>,
41    workspace: Option<&dyn Workspace>,
42) {
43    // Stop the PROMPT.md monitor if it was started
44    if let Some(monitor) = prompt_monitor {
45        monitor.stop();
46    }
47
48    // End agent phase and clean up
49    crate::git_helpers::end_agent_phase();
50    crate::git_helpers::disable_git_wrapper(agent_phase_guard.git_helpers);
51    if let Err(err) = crate::git_helpers::uninstall_hooks(logger) {
52        logger.warn(&format!("Failed to uninstall Ralph hooks: {err}"));
53    }
54
55    // Note: Individual commits were created per-iteration during development
56    // and per-cycle during review. The final commit phase has been removed.
57
58    // Final summary
59    let summary = PipelineSummary {
60        total_time: runtime.timer.elapsed_formatted(),
61        dev_runs_completed: runtime.stats.developer_runs_completed as usize,
62        dev_runs_total: config.developer_iters as usize,
63        review_runs: runtime.stats.reviewer_runs_completed as usize,
64        changes_detected: runtime.stats.changes_detected as usize,
65        isolation_mode: config.isolation_mode,
66        verbose: config.verbosity.is_verbose(),
67        review_summary: None,
68    };
69    print_final_summary(colors, &summary, logger);
70
71    if config.features.checkpoint_enabled {
72        let result = if let Some(ws) = workspace {
73            clear_checkpoint_with_workspace(ws)
74        } else {
75            clear_checkpoint()
76        };
77        if let Err(err) = result {
78            logger.warn(&format!("Failed to clear checkpoint: {err}"));
79        }
80    }
81
82    // Note: PROMPT.md write permissions are now restored via the reducer's
83    // Effect::RestorePromptPermissions during the Finalizing phase.
84    // This ensures the operation goes through the effect system for testability.
85
86    agent_phase_guard.disarm();
87}