summaryrefslogblamecommitdiff
path: root/makima/src/llm/phase_guidance.rs
blob: 712e8bb18ba386385680a6f0794e256037c01025 (plain) (tree)
1
2
3
4



                                                                              















                                                                          


                                    
 
                                   

                                                                              

                                                






                                               






                                                         
                      
                                      




                                     
                                                         


                              

                                       

                                                       
                                                       




                                    
                           

                                                         


                      

                     

                                      
                        






                                                         

                                             























                                                         

                                            



                       

                                   
                                                                                     
                                                                 



                                                                     







                                                                                               



















































































                                                                                                   
                                               



                                                                   





                                                                                                





                                                                                                                                                                      





                                                                                     





                                                                                                                                              
                                 







                                                                           
                                                                          


                                          





                                                                                          

                                       
                                                                                                                                                              


                                         





                                                                                             

                                       
                                                                                                                                                                                


                                      





                                                                                                

                                      
                                                                                                                                                                      


                                         





                                                                                     

                                      
                                                                                                                                                     


                                        





                                                                                      

                                       



                                                                                                                                                     
                                 







                                                                                  



                                                                    
                                                                                   


                                                                                                                              


                                     
                                 

                                       
                                                                                                   



          
                                                                     

                                    
                                      



                         
                                                                             
 


                                                           
               




                                                              








                                                                             











                                                                    







                                      


                                                                 







                                     
                                         
























                                                                     

                                   

                                   




                                                                                           
                 




                                                                 
                 
                                                   




                                   
                                                            





                                                                                  
                                                                               


                                                                               



                                                          

                                                                                 
                                                                
                                                                                                     



                       






                                         


                                 
                     
                       
                                                              



















                                                                              

                                                                                            
                    



                                                                                         


                      


                                                                        


                                      

                                                                                          
                    
                                                                                         


                   



                                                                        
 

                                                                                  
                                       

                                                                                         






                                                                                      
                                                                                       
                                                     
                                                                                                                           
                        









                                                            





                                                        



                                                                        
 

                                                                                             







                                                                                            























                                                                             

                             

                               
                                                  







                                                                    


                              
                                      

                         
                             
                                        


                                                            













                                                                               




                        




                                                       




                                                  


                                             















                                                               
                                    



                                                                             

                                             









                                                                                



                                                    



             
                                                                




                                                                       



                                                                                   
                



                                                                              

            




                                                           






                                 
                                              


























                                                                                                


                            
                                      

                         

                           






                                       






































































                                                                                         




                                                            




                                                               








                                                             











                                                                                                                                                                                                


                                                                                         






                                                               


                                                                                               




            

                                                                        



                                           
 
                   
                                      
                                           

                                                             


                                                                 


                             
                                                                               












                                                                                     
                                             













                                                                    



                                                          
























                                                                                 
                                             


                                                                     


                                                                                 
 



                                                                           

                                                               



                                                    
                                                                                    

                                                                  
 
                                                                                  

                                                                        
 
                                                                                

                                                               


           
                                                   
                                                                            
                                                 

                                             


           




                                                                              
 




                                                                                     


           




                                                                                              
     
 
//! Phase guidance and deliverables tracking for contract management.
//!
//! This module provides structured guidance for each contract phase, tracking
//! expected deliverables and completion criteria.
//!
//! ## Contract Types
//!
//! ### Simple
//! - **Plan phase**: One required deliverable: "Plan"
//! - **Execute phase**: One required deliverable: "PR"
//!
//! ### Specification
//! - **Research phase**: One required deliverable: "Research Notes"
//! - **Specify phase**: One required deliverable: "Requirements Document"
//! - **Plan phase**: One required deliverable: "Plan"
//! - **Execute phase**: One required deliverable: "PR"
//! - **Review phase**: One required deliverable: "Release Notes"
//!
//! ### Execute
//! - **Execute phase only**: No deliverables at all

use serde::{Deserialize, Serialize};
use utoipa::ToSchema;

/// Priority level for deliverables
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum DeliverablePriority {
    /// Must be completed before advancing phase
    Required,
    /// Strongly suggested for phase completion
    Recommended,
    /// Nice to have, not blocking
    Optional,
}

/// A deliverable for a phase
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct Deliverable {
    /// Unique identifier for the deliverable
    pub id: String,
    /// Display name
    pub name: String,
    /// Priority level
    pub priority: DeliverablePriority,
    /// Brief description of purpose
    pub description: String,
}

/// Expected deliverables for a phase
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct PhaseDeliverables {
    /// Phase name
    pub phase: String,
    /// Deliverables for this phase
    pub deliverables: Vec<Deliverable>,
    /// Whether a repository is required for this phase
    pub requires_repository: bool,
    /// Whether tasks should be completed in this phase
    pub requires_tasks: bool,
    /// Guidance text for this phase
    pub guidance: String,
}

/// Status of a deliverable
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct DeliverableStatus {
    /// Deliverable ID
    pub id: String,
    /// Display name
    pub name: String,
    /// Priority
    pub priority: DeliverablePriority,
    /// Whether it has been completed
    pub completed: bool,
}

/// Checklist for phase completion
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct PhaseChecklist {
    /// Current phase
    pub phase: String,
    /// Deliverable status list
    pub deliverables: Vec<DeliverableStatus>,
    /// Whether repository is configured
    pub has_repository: bool,
    /// Whether repository was required
    pub repository_required: bool,
    /// Task statistics (for execute phase)
    pub task_stats: Option<TaskStats>,
    /// Overall completion percentage (0-100)
    pub completion_percentage: u8,
    /// Summary message
    pub summary: String,
    /// Suggestions for next actions
    pub suggestions: Vec<String>,
}

/// Task statistics for execute phase
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct TaskStats {
    pub total: usize,
    pub pending: usize,
    pub running: usize,
    pub done: usize,
    pub failed: usize,
}

/// Minimal task info for checklist building
pub struct TaskInfo {
    pub name: String,
    pub status: String,
}

use crate::db::models::PhaseConfig;

/// Get phase deliverables configuration (legacy, defaults to "simple" contract type)
pub fn get_phase_deliverables(phase: &str) -> PhaseDeliverables {
    get_phase_deliverables_for_type(phase, "simple")
}

/// Get phase deliverables configuration for a specific contract type
pub fn get_phase_deliverables_for_type(phase: &str, contract_type: &str) -> PhaseDeliverables {
    match contract_type {
        "execute" => get_execute_type_deliverables(phase),
        "specification" => get_specification_type_deliverables(phase),
        "simple" | _ => get_simple_type_deliverables(phase),
    }
}

/// Get phase deliverables from a custom PhaseConfig
/// This is used for contracts with custom templates
pub fn get_phase_deliverables_from_config(phase: &str, config: &PhaseConfig) -> PhaseDeliverables {
    // Check if this phase exists in the config
    let phase_exists = config.phases.iter().any(|p| p.id == phase);
    if !phase_exists {
        return PhaseDeliverables {
            phase: phase.to_string(),
            deliverables: vec![],
            requires_repository: false,
            requires_tasks: false,
            guidance: format!("Phase '{}' is not defined in this contract template", phase),
        };
    }

    // Get deliverables for this phase from the config
    let deliverables: Vec<Deliverable> = config
        .deliverables
        .get(phase)
        .map(|defs| {
            defs.iter()
                .map(|d| Deliverable {
                    id: d.id.clone(),
                    name: d.name.clone(),
                    priority: match d.priority.as_str() {
                        "recommended" => DeliverablePriority::Recommended,
                        "optional" => DeliverablePriority::Optional,
                        _ => DeliverablePriority::Required,
                    },
                    description: format!("{} deliverable", d.name),
                })
                .collect()
        })
        .unwrap_or_default();

    // Determine if repository is required (typically for execute-like phases)
    let requires_repository = phase == "execute" || phase == "plan";

    // Determine if tasks are required (typically for execute phase)
    let requires_tasks = phase == "execute";

    // Find the phase name for better guidance
    let phase_name = config
        .phases
        .iter()
        .find(|p| p.id == phase)
        .map(|p| p.name.clone())
        .unwrap_or_else(|| phase.to_string());

    let guidance = if deliverables.is_empty() {
        format!("Complete the {} phase. No specific deliverables are required.", phase_name)
    } else {
        let deliverable_names: Vec<_> = deliverables.iter().map(|d| d.name.clone()).collect();
        format!(
            "Complete the {} phase by producing the following deliverables: {}",
            phase_name,
            deliverable_names.join(", ")
        )
    };

    PhaseDeliverables {
        phase: phase.to_string(),
        deliverables,
        requires_repository,
        requires_tasks,
        guidance,
    }
}

/// Get phase deliverables, checking custom config first, then falling back to built-in types
pub fn get_phase_deliverables_with_config(
    phase: &str,
    contract_type: &str,
    phase_config: Option<&PhaseConfig>,
) -> PhaseDeliverables {
    // If we have a custom phase config, use it
    if let Some(config) = phase_config {
        return get_phase_deliverables_from_config(phase, config);
    }

    // Otherwise, fall back to built-in contract types
    get_phase_deliverables_for_type(phase, contract_type)
}

/// Get deliverables for 'simple' contract type
fn get_simple_type_deliverables(phase: &str) -> PhaseDeliverables {
    match phase {
        "plan" => PhaseDeliverables {
            phase: "plan".to_string(),
            deliverables: vec![Deliverable {
                id: "plan-document".to_string(),
                name: "Plan".to_string(),
                priority: DeliverablePriority::Required,
                description: "Implementation plan detailing the approach and tasks".to_string(),
            }],
            requires_repository: true,
            requires_tasks: false,
            guidance: "Create a plan document that outlines the implementation approach. A repository must be configured before moving to Execute phase.".to_string(),
        },
        "execute" => PhaseDeliverables {
            phase: "execute".to_string(),
            deliverables: vec![Deliverable {
                id: "pull-request".to_string(),
                name: "Pull Request".to_string(),
                priority: DeliverablePriority::Required,
                description: "Pull request with the implemented changes".to_string(),
            }],
            requires_repository: true,
            requires_tasks: true,
            guidance: "Execute the plan and create a PR with the implemented changes. Complete all tasks to finish the contract.".to_string(),
        },
        _ => PhaseDeliverables {
            phase: phase.to_string(),
            deliverables: vec![],
            requires_repository: false,
            requires_tasks: false,
            guidance: "Unknown phase for simple contract type".to_string(),
        },
    }
}

/// Get deliverables for 'specification' contract type
fn get_specification_type_deliverables(phase: &str) -> PhaseDeliverables {
    match phase {
        "research" => PhaseDeliverables {
            phase: "research".to_string(),
            deliverables: vec![Deliverable {
                id: "research-notes".to_string(),
                name: "Research Notes".to_string(),
                priority: DeliverablePriority::Required,
                description: "Document findings and insights during research".to_string(),
            }],
            requires_repository: false,
            requires_tasks: false,
            guidance: "Focus on understanding the problem space and document your findings in the Research Notes before moving to Specify phase.".to_string(),
        },
        "specify" => PhaseDeliverables {
            phase: "specify".to_string(),
            deliverables: vec![Deliverable {
                id: "requirements-document".to_string(),
                name: "Requirements Document".to_string(),
                priority: DeliverablePriority::Required,
                description: "Define functional and non-functional requirements".to_string(),
            }],
            requires_repository: false,
            requires_tasks: false,
            guidance: "Define what needs to be built with clear requirements in the Requirements Document. Ensure specifications are detailed enough for planning.".to_string(),
        },
        "plan" => PhaseDeliverables {
            phase: "plan".to_string(),
            deliverables: vec![Deliverable {
                id: "plan-document".to_string(),
                name: "Plan".to_string(),
                priority: DeliverablePriority::Required,
                description: "Implementation plan detailing the approach and tasks".to_string(),
            }],
            requires_repository: true,
            requires_tasks: false,
            guidance: "Create a plan document that outlines the implementation approach. A repository must be configured before moving to Execute phase.".to_string(),
        },
        "execute" => PhaseDeliverables {
            phase: "execute".to_string(),
            deliverables: vec![Deliverable {
                id: "pull-request".to_string(),
                name: "Pull Request".to_string(),
                priority: DeliverablePriority::Required,
                description: "Pull request with the implemented changes".to_string(),
            }],
            requires_repository: true,
            requires_tasks: true,
            guidance: "Execute the plan and create a PR with the implemented changes. Complete all tasks before moving to Review phase.".to_string(),
        },
        "review" => PhaseDeliverables {
            phase: "review".to_string(),
            deliverables: vec![Deliverable {
                id: "release-notes".to_string(),
                name: "Release Notes".to_string(),
                priority: DeliverablePriority::Required,
                description: "Document changes for release communication".to_string(),
            }],
            requires_repository: false,
            requires_tasks: false,
            guidance: "Review completed work and document the release in the Release Notes. The contract can be completed after review.".to_string(),
        },
        _ => PhaseDeliverables {
            phase: phase.to_string(),
            deliverables: vec![],
            requires_repository: false,
            requires_tasks: false,
            guidance: "Unknown phase for specification contract type".to_string(),
        },
    }
}

/// Get deliverables for 'execute' contract type
fn get_execute_type_deliverables(phase: &str) -> PhaseDeliverables {
    match phase {
        "execute" => PhaseDeliverables {
            phase: "execute".to_string(),
            deliverables: vec![], // No deliverables for execute-only contract type
            requires_repository: true,
            requires_tasks: true,
            guidance: "Execute the tasks directly. No deliverable documents are required for this contract type.".to_string(),
        },
        _ => PhaseDeliverables {
            phase: phase.to_string(),
            deliverables: vec![],
            requires_repository: false,
            requires_tasks: false,
            guidance: "The 'execute' contract type only supports the 'execute' phase.".to_string(),
        },
    }
}

/// Build a phase checklist comparing expected vs actual deliverables
pub fn get_phase_checklist_for_type(
    phase: &str,
    completed_deliverables: &[String],
    tasks: &[TaskInfo],
    has_repository: bool,
    contract_type: &str,
) -> PhaseChecklist {
    let phase_config = get_phase_deliverables_for_type(phase, contract_type);

    // Build deliverable status list
    let deliverables: Vec<DeliverableStatus> = phase_config
        .deliverables
        .iter()
        .map(|d| DeliverableStatus {
            id: d.id.clone(),
            name: d.name.clone(),
            priority: d.priority,
            completed: completed_deliverables.contains(&d.id),
        })
        .collect();

    // Calculate task stats for execute phase
    let task_stats = if phase == "execute" {
        let total = tasks.len();
        let pending = tasks.iter().filter(|t| t.status == "pending").count();
        let running = tasks.iter().filter(|t| t.status == "running").count();
        let done = tasks.iter().filter(|t| t.status == "done").count();
        let failed = tasks
            .iter()
            .filter(|t| t.status == "failed" || t.status == "error")
            .count();

        Some(TaskStats {
            total,
            pending,
            running,
            done,
            failed,
        })
    } else {
        None
    };

    // Calculate completion percentage
    let mut completed_items = 0;
    let mut total_items = 0;

    // Count required and recommended deliverables (not optional)
    for status in &deliverables {
        if status.priority != DeliverablePriority::Optional {
            total_items += 1;
            if status.completed {
                completed_items += 1;
            }
        }
    }

    // Count repository if required
    if phase_config.requires_repository {
        total_items += 1;
        if has_repository {
            completed_items += 1;
        }
    }

    // Count tasks if in execute phase
    if let Some(ref stats) = task_stats {
        if stats.total > 0 {
            total_items += 1;
            if stats.done == stats.total && stats.total > 0 {
                completed_items += 1;
            }
        }
    }

    let completion_percentage = if total_items > 0 {
        ((completed_items as f64 / total_items as f64) * 100.0) as u8
    } else {
        100 // No requirements means complete
    };

    // Generate suggestions
    let mut suggestions = Vec::new();

    // Suggest missing deliverables
    for status in &deliverables {
        if !status.completed {
            match status.priority {
                DeliverablePriority::Required => {
                    suggestions.push(format!(
                        "Mark '{}' as complete using mark_deliverable_complete (required)",
                        status.name
                    ));
                }
                DeliverablePriority::Recommended => {
                    suggestions.push(format!(
                        "Consider completing '{}' (recommended)",
                        status.name
                    ));
                }
                DeliverablePriority::Optional => {}
            }
        }
    }

    // Suggest repository if needed
    if phase_config.requires_repository && !has_repository {
        suggestions.push("Configure a repository for task execution".to_string());
    }

    // Suggest task actions for execute phase
    if let Some(ref stats) = task_stats {
        if stats.total == 0 {
            suggestions.push("Create tasks to implement the plan".to_string());
        } else if stats.pending > 0 {
            suggestions.push(format!("Run {} pending task(s)", stats.pending));
        } else if stats.running > 0 {
            suggestions.push(format!(
                "Wait for {} running task(s) to complete",
                stats.running
            ));
        } else if stats.failed > 0 {
            suggestions.push(format!("Address {} failed task(s)", stats.failed));
        } else if stats.done == stats.total && stats.total > 0 {
            suggestions.push("All tasks complete. Mark deliverables and advance phase.".to_string());
        }
    }

    // Generate summary
    let summary = generate_phase_summary(
        phase,
        &deliverables,
        has_repository,
        &task_stats,
        completion_percentage,
    );

    PhaseChecklist {
        phase: phase.to_string(),
        deliverables,
        has_repository,
        repository_required: phase_config.requires_repository,
        task_stats,
        completion_percentage,
        summary,
        suggestions,
    }
}

fn generate_phase_summary(
    phase: &str,
    deliverables: &[DeliverableStatus],
    has_repository: bool,
    task_stats: &Option<TaskStats>,
    completion_percentage: u8,
) -> String {
    let completed_count = deliverables.iter().filter(|d| d.completed).count();
    let total_count = deliverables.len();

    match phase {
        "research" => {
            if completed_count == 0 {
                "Research phase needs documentation. Mark deliverables complete when ready."
                    .to_string()
            } else {
                format!(
                    "{}/{} deliverables complete. Ready to transition to Specify phase.",
                    completed_count, total_count
                )
            }
        }
        "specify" => {
            let has_required = deliverables
                .iter()
                .filter(|d| d.priority == DeliverablePriority::Required)
                .all(|d| d.completed);

            if !has_required {
                "Specify phase requires completing the Requirements Document deliverable."
                    .to_string()
            } else {
                "Specifications ready. Consider transitioning to Plan phase.".to_string()
            }
        }
        "plan" => {
            let has_required = deliverables
                .iter()
                .filter(|d| d.priority == DeliverablePriority::Required)
                .all(|d| d.completed);

            if !has_required {
                "Plan phase requires completing the Plan deliverable.".to_string()
            } else if !has_repository {
                "Repository not configured. Configure a repository before Execute phase."
                    .to_string()
            } else {
                "Planning complete. Ready to transition to Execute phase.".to_string()
            }
        }
        "execute" => {
            if let Some(stats) = task_stats {
                if stats.total == 0 {
                    "No tasks created. Create tasks to implement the plan.".to_string()
                } else if stats.done == stats.total {
                    "All tasks complete! Mark deliverables and advance to Review phase (or complete contract).".to_string()
                } else {
                    format!(
                        "{}/{} tasks completed ({}% done)",
                        stats.done,
                        stats.total,
                        if stats.total > 0 {
                            (stats.done * 100) / stats.total
                        } else {
                            0
                        }
                    )
                }
            } else {
                "Execute phase in progress.".to_string()
            }
        }
        "review" => {
            let has_required = deliverables
                .iter()
                .filter(|d| d.priority == DeliverablePriority::Required)
                .all(|d| d.completed);

            if !has_required {
                "Review phase requires completing the Release Notes deliverable.".to_string()
            } else {
                "Review documentation complete. Contract can be marked as done.".to_string()
            }
        }
        _ => format!("Phase {} - {}% complete", phase, completion_percentage),
    }
}

/// Result of checking if deliverables are met for the current phase
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct DeliverableCheckResult {
    /// Whether all required deliverables are met
    pub deliverables_met: bool,
    /// Whether the phase is ready to advance (includes all readiness checks)
    pub ready_to_advance: bool,
    /// Current phase
    pub phase: String,
    /// Next phase (if available)
    pub next_phase: Option<String>,
    /// List of required deliverables and their status
    pub required_deliverables: Vec<DeliverableItem>,
    /// List of what's missing (if any)
    pub missing: Vec<String>,
    /// Human-readable summary
    pub summary: String,
    /// Whether auto-progress is recommended
    pub auto_progress_recommended: bool,
}

/// A single deliverable item status
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct DeliverableItem {
    /// ID of the deliverable
    pub id: String,
    /// Name of the deliverable
    pub name: String,
    /// Type: "deliverable", "repository", "tasks"
    pub deliverable_type: String,
    /// Whether it's met
    pub met: bool,
    /// Additional details
    pub details: Option<String>,
}

/// Check if all required deliverables for the current phase are met
pub fn check_deliverables_met(
    phase: &str,
    contract_type: &str,
    completed_deliverables: &[String],
    tasks: &[TaskInfo],
    has_repository: bool,
) -> DeliverableCheckResult {
    let mut required_items = Vec::new();
    let mut missing = Vec::new();

    // Get the deliverables for this contract type and phase
    let phase_config = get_phase_deliverables_for_type(phase, contract_type);

    // Check required deliverables for this phase
    for deliverable in &phase_config.deliverables {
        if deliverable.priority == DeliverablePriority::Required {
            let is_complete = completed_deliverables.contains(&deliverable.id);

            required_items.push(DeliverableItem {
                id: deliverable.id.clone(),
                name: deliverable.name.clone(),
                deliverable_type: "deliverable".to_string(),
                met: is_complete,
                details: if is_complete {
                    Some("Marked complete".to_string())
                } else {
                    None
                },
            });

            if !is_complete {
                missing.push(format!(
                    "Mark '{}' as complete (required)",
                    deliverable.name
                ));
            }
        }
    }

    // Check repository for phases that require it
    if phase_config.requires_repository {
        required_items.push(DeliverableItem {
            id: "repository".to_string(),
            name: "Repository".to_string(),
            deliverable_type: "repository".to_string(),
            met: has_repository,
            details: if has_repository {
                Some("Repository configured".to_string())
            } else {
                None
            },
        });

        if !has_repository {
            missing.push("Configure a repository".to_string());
        }
    }

    // Check tasks for execute phase
    if phase_config.requires_tasks {
        let total_tasks = tasks.len();
        let done_tasks = tasks.iter().filter(|t| t.status == "done").count();
        let tasks_complete = total_tasks > 0 && done_tasks == total_tasks;

        required_items.push(DeliverableItem {
            id: "tasks".to_string(),
            name: "Tasks Completed".to_string(),
            deliverable_type: "tasks".to_string(),
            met: tasks_complete,
            details: Some(format!("{}/{} tasks done", done_tasks, total_tasks)),
        });

        if !tasks_complete {
            if total_tasks == 0 {
                missing.push("Create and complete tasks".to_string());
            } else {
                missing.push(format!(
                    "Complete remaining {} task(s)",
                    total_tasks - done_tasks
                ));
            }
        }
    }

    let deliverables_met = required_items.iter().all(|d| d.met);
    let next_phase = get_next_phase_for_contract(contract_type, phase);
    let ready_to_advance = deliverables_met && next_phase.is_some();

    let summary = if deliverables_met {
        if let Some(ref next) = next_phase {
            format!(
                "All deliverables met for {} phase. Ready to advance to {} phase.",
                phase, next
            )
        } else {
            format!(
                "All deliverables met for {} phase. This is the final phase.",
                phase
            )
        }
    } else {
        format!(
            "{} deliverable(s) still needed for {} phase.",
            missing.len(),
            phase
        )
    };

    DeliverableCheckResult {
        deliverables_met,
        ready_to_advance,
        phase: phase.to_string(),
        next_phase,
        required_deliverables: required_items,
        missing,
        summary,
        auto_progress_recommended: deliverables_met && ready_to_advance,
    }
}

/// Get the next phase based on contract type
pub fn get_next_phase_for_contract(contract_type: &str, current_phase: &str) -> Option<String> {
    match contract_type {
        "simple" => match current_phase {
            "plan" => Some("execute".to_string()),
            "execute" => None, // Terminal phase for simple contracts
            _ => None,
        },
        "execute" => None, // Execute-only contracts don't have phase transitions
        "specification" | _ => match current_phase {
            "research" => Some("specify".to_string()),
            "specify" => Some("plan".to_string()),
            "plan" => Some("execute".to_string()),
            "execute" => Some("review".to_string()),
            "review" => None, // Final phase
            _ => None,
        },
    }
}

/// Determine if the contract should auto-progress to the next phase
pub fn should_auto_progress(
    phase: &str,
    contract_type: &str,
    completed_deliverables: &[String],
    tasks: &[TaskInfo],
    has_repository: bool,
    autonomous_loop: bool,
) -> AutoProgressDecision {
    let check = check_deliverables_met(
        phase,
        contract_type,
        completed_deliverables,
        tasks,
        has_repository,
    );

    if !check.deliverables_met {
        return AutoProgressDecision {
            should_progress: false,
            next_phase: None,
            reason: format!("Deliverables not met: {}", check.missing.join(", ")),
            action: AutoProgressAction::WaitForDeliverables,
        };
    }

    if check.next_phase.is_none() {
        return AutoProgressDecision {
            should_progress: false,
            next_phase: None,
            reason: "This is the terminal phase. Contract can be completed.".to_string(),
            action: AutoProgressAction::CompleteContract,
        };
    }

    if autonomous_loop {
        AutoProgressDecision {
            should_progress: true,
            next_phase: check.next_phase,
            reason: "All deliverables met and autonomous_loop is enabled.".to_string(),
            action: AutoProgressAction::AdvancePhase,
        }
    } else {
        AutoProgressDecision {
            should_progress: false,
            next_phase: check.next_phase,
            reason: "All deliverables met. Suggest advancing to next phase.".to_string(),
            action: AutoProgressAction::SuggestAdvance,
        }
    }
}

/// Result of auto-progress decision
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AutoProgressDecision {
    /// Whether to automatically progress
    pub should_progress: bool,
    /// The next phase to progress to
    pub next_phase: Option<String>,
    /// Reason for the decision
    pub reason: String,
    /// Recommended action
    pub action: AutoProgressAction,
}

/// Actions that can be taken based on auto-progress decision
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AutoProgressAction {
    /// Wait for required deliverables
    WaitForDeliverables,
    /// Automatically advance to next phase
    AdvancePhase,
    /// Suggest user to advance (when not autonomous)
    SuggestAdvance,
    /// Contract is complete, mark as done
    CompleteContract,
}

/// Generate enhanced prompt guidance for deliverable checking
pub fn generate_deliverable_prompt_guidance(
    phase: &str,
    contract_type: &str,
    check_result: &DeliverableCheckResult,
) -> String {
    let mut guidance = String::new();

    guidance.push_str("\n## Phase Deliverables Status\n\n");
    guidance.push_str(&format!(
        "**Current Phase**: {} | **Contract Type**: {}\n\n",
        capitalize(phase),
        contract_type
    ));

    // Show required deliverables checklist
    guidance.push_str("### Required Deliverables Checklist\n");
    for item in &check_result.required_deliverables {
        let status = if item.met { "[x]" } else { "[ ]" };
        let details = item
            .details
            .as_ref()
            .map(|d| format!(" - {}", d))
            .unwrap_or_default();
        guidance.push_str(&format!(
            "{} **{}** ({}){}\n",
            status, item.name, item.deliverable_type, details
        ));
    }

    // Show status and next actions
    guidance.push_str("\n### Status\n");
    if check_result.deliverables_met {
        guidance.push_str("**All deliverables are met.**\n\n");
        if let Some(ref next) = check_result.next_phase {
            guidance.push_str(&format!("Ready to advance to **{}** phase.\n", next));
            if check_result.auto_progress_recommended {
                guidance.push_str(&format!("\n**ACTION REQUIRED**: Since all deliverables are met, you should call `advance_phase` with `new_phase=\"{}\"` to progress the contract.\n", next));
            }
        } else {
            guidance.push_str(
                "This is the terminal phase. The contract can be marked as completed.\n",
            );
        }
    } else {
        guidance.push_str("**Deliverables not yet met.**\n\n");
        guidance.push_str("Missing:\n");
        for item in &check_result.missing {
            guidance.push_str(&format!("- {}\n", item));
        }
        guidance.push_str(
            "\nUse `mark_deliverable_complete` to mark deliverables as complete when ready.\n",
        );
    }

    guidance
}

/// Format checklist as markdown for LLM context
pub fn format_checklist_markdown(checklist: &PhaseChecklist) -> String {
    let mut md = format!(
        "## Phase Progress ({} Phase)\n\n",
        capitalize(&checklist.phase)
    );

    // Deliverables
    md.push_str("### Deliverables\n");
    for status in &checklist.deliverables {
        let check = if status.completed { "+" } else { "-" };
        let priority_label = match status.priority {
            DeliverablePriority::Required => " (required)",
            DeliverablePriority::Recommended => " (recommended)",
            DeliverablePriority::Optional => " (optional)",
        };

        if status.completed {
            md.push_str(&format!("[{}] {} - completed\n", check, status.name));
        } else {
            md.push_str(&format!("[{}] {}{}\n", check, status.name, priority_label));
        }
    }

    // Repository status
    if checklist.repository_required {
        let check = if checklist.has_repository { "+" } else { "-" };
        md.push_str(&format!("[{}] Repository configured (required)\n", check));
    }

    // Task stats for execute phase
    if let Some(ref stats) = checklist.task_stats {
        md.push_str("\n### Task Progress\n");
        md.push_str(&format!("- Total: {}\n", stats.total));
        md.push_str(&format!("- Done: {}\n", stats.done));
        if stats.pending > 0 {
            md.push_str(&format!("- Pending: {}\n", stats.pending));
        }
        if stats.running > 0 {
            md.push_str(&format!("- Running: {}\n", stats.running));
        }
        if stats.failed > 0 {
            md.push_str(&format!("- Failed: {}\n", stats.failed));
        }
    }

    // Summary
    md.push_str(&format!(
        "\n**Status**: {} ({}% complete)\n",
        checklist.summary, checklist.completion_percentage
    ));

    // Suggestions
    if !checklist.suggestions.is_empty() {
        md.push_str("\n**Next Steps**:\n");
        for suggestion in &checklist.suggestions {
            md.push_str(&format!("- {}\n", suggestion));
        }
    }

    md
}

fn capitalize(s: &str) -> String {
    let mut chars = s.chars();
    match chars.next() {
        None => String::new(),
        Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_get_phase_deliverables_simple() {
        let plan = get_phase_deliverables_for_type("plan", "simple");
        assert_eq!(plan.phase, "plan");
        assert!(plan.requires_repository);
        assert_eq!(plan.deliverables.len(), 1);
        assert_eq!(plan.deliverables[0].id, "plan-document");
        assert_eq!(plan.deliverables[0].priority, DeliverablePriority::Required);

        let execute = get_phase_deliverables_for_type("execute", "simple");
        assert_eq!(execute.phase, "execute");
        assert!(execute.requires_repository);
        assert!(execute.requires_tasks);
        assert_eq!(execute.deliverables.len(), 1);
        assert_eq!(execute.deliverables[0].id, "pull-request");
    }

    #[test]
    fn test_get_phase_deliverables_specification() {
        let research = get_phase_deliverables_for_type("research", "specification");
        assert_eq!(research.deliverables.len(), 1);
        assert_eq!(research.deliverables[0].id, "research-notes");

        let specify = get_phase_deliverables_for_type("specify", "specification");
        assert_eq!(specify.deliverables.len(), 1);
        assert_eq!(specify.deliverables[0].id, "requirements-document");

        let review = get_phase_deliverables_for_type("review", "specification");
        assert_eq!(review.deliverables.len(), 1);
        assert_eq!(review.deliverables[0].id, "release-notes");
    }

    #[test]
    fn test_get_phase_deliverables_execute_type() {
        let execute = get_phase_deliverables_for_type("execute", "execute");
        assert!(execute.deliverables.is_empty());
        assert!(execute.requires_repository);
        assert!(execute.requires_tasks);
    }

    #[test]
    fn test_check_deliverables_met() {
        // No deliverables marked complete
        let result = check_deliverables_met("plan", "simple", &[], &[], true);
        assert!(!result.deliverables_met);
        assert!(!result.missing.is_empty());

        // Deliverable marked complete
        let completed = vec!["plan-document".to_string()];
        let result = check_deliverables_met("plan", "simple", &completed, &[], true);
        assert!(result.deliverables_met);
        assert!(result.ready_to_advance);
    }

    #[test]
    fn test_phase_checklist() {
        let completed = vec!["plan-document".to_string()];
        let checklist = get_phase_checklist_for_type("plan", &completed, &[], true, "simple");
        assert_eq!(checklist.completion_percentage, 100);
        assert!(checklist.deliverables[0].completed);
    }
}