summaryrefslogtreecommitdiff
path: root/makima/src/db/models.rs
diff options
context:
space:
mode:
Diffstat (limited to 'makima/src/db/models.rs')
-rw-r--r--makima/src/db/models.rs905
1 files changed, 2 insertions, 903 deletions
diff --git a/makima/src/db/models.rs b/makima/src/db/models.rs
index 3fb9667..bfb8bf3 100644
--- a/makima/src/db/models.rs
+++ b/makima/src/db/models.rs
@@ -111,10 +111,6 @@ pub enum BodyElement {
pub struct File {
pub id: Uuid,
pub owner_id: Uuid,
- /// Contract this file belongs to (optional)
- pub contract_id: Option<Uuid>,
- /// Phase of the contract when file was added (e.g., "research", "specify")
- pub contract_phase: Option<String>,
pub name: String,
pub description: Option<String>,
#[sqlx(json)]
@@ -141,8 +137,6 @@ pub struct File {
#[derive(Debug, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct CreateFileRequest {
- /// Contract this file belongs to (required - files must belong to a contract)
- pub contract_id: Uuid,
/// Name of the file (auto-generated if not provided)
pub name: Option<String>,
/// Optional description
@@ -157,8 +151,6 @@ pub struct CreateFileRequest {
pub body: Vec<BodyElement>,
/// Path to linked repository file (e.g., "README.md")
pub repo_file_path: Option<String>,
- /// Contract phase this file belongs to (for deliverable tracking)
- pub contract_phase: Option<String>,
}
/// Request payload for updating an existing file.
@@ -194,12 +186,6 @@ pub struct FileListResponse {
#[serde(rename_all = "camelCase")]
pub struct FileSummary {
pub id: Uuid,
- /// Contract this file belongs to
- pub contract_id: Option<Uuid>,
- /// Contract name (joined from contracts table)
- pub contract_name: Option<String>,
- /// Phase when file was added to contract
- pub contract_phase: Option<String>,
pub name: String,
pub description: Option<String>,
pub transcript_count: usize,
@@ -224,9 +210,6 @@ impl From<File> for FileSummary {
.fold(0.0_f32, f32::max);
Self {
id: file.id,
- contract_id: file.contract_id,
- contract_name: None, // Not available from File alone, requires JOIN
- contract_phase: file.contract_phase,
name: file.name,
description: file.description,
transcript_count: file.transcript.len(),
@@ -425,8 +408,6 @@ impl std::str::FromStr for MergeMode {
pub struct Task {
pub id: Uuid,
pub owner_id: Uuid,
- /// Contract this task belongs to (required for new tasks)
- pub contract_id: Option<Uuid>,
pub parent_task_id: Option<Uuid>,
/// Depth in task hierarchy (no longer constrained)
pub depth: i32,
@@ -436,11 +417,6 @@ pub struct Task {
pub priority: i32,
pub plan: String,
- // Supervisor flag
- /// True for contract supervisor tasks. Only supervisors can spawn new tasks.
- #[serde(default)]
- pub is_supervisor: bool,
-
// Daemon/container info
pub daemon_id: Option<Uuid>,
pub container_id: Option<String>,
@@ -565,14 +541,6 @@ impl Task {
#[serde(rename_all = "camelCase")]
pub struct TaskSummary {
pub id: Uuid,
- /// Contract this task belongs to
- pub contract_id: Option<Uuid>,
- /// Contract name (joined from contracts table)
- pub contract_name: Option<String>,
- /// Contract phase (joined from contracts table)
- pub contract_phase: Option<String>,
- /// Contract status (joined from contracts table): 'active', 'completed', 'archived'
- pub contract_status: Option<String>,
pub parent_task_id: Option<Uuid>,
/// Depth in task hierarchy: 0=orchestrator (top-level), 1=subtask (max)
pub depth: i32,
@@ -582,9 +550,6 @@ pub struct TaskSummary {
pub progress_summary: Option<String>,
pub subtask_count: i64,
pub version: i32,
- /// True for contract supervisor tasks
- #[serde(default)]
- pub is_supervisor: bool,
/// Whether this task is hidden from the UI (user dismissed it)
#[serde(default)]
pub hidden: bool,
@@ -597,10 +562,6 @@ impl From<Task> for TaskSummary {
fn from(task: Task) -> Self {
Self {
id: task.id,
- contract_id: task.contract_id,
- contract_name: None, // Not available from Task directly
- contract_phase: None, // Not available from Task directly
- contract_status: None, // Not available from Task directly
parent_task_id: task.parent_task_id,
depth: task.depth,
name: task.name,
@@ -609,7 +570,6 @@ impl From<Task> for TaskSummary {
progress_summary: task.progress_summary,
subtask_count: 0, // Would need separate query
version: task.version,
- is_supervisor: task.is_supervisor,
hidden: task.hidden,
created_at: task.created_at,
updated_at: task.updated_at,
@@ -629,8 +589,6 @@ pub struct TaskListResponse {
#[derive(Debug, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct CreateTaskRequest {
- /// Contract this task belongs to (optional for branched/anonymous tasks)
- pub contract_id: Option<Uuid>,
/// Name of the task
pub name: String,
/// Optional description
@@ -639,9 +597,6 @@ pub struct CreateTaskRequest {
pub plan: String,
/// Parent task ID (for subtasks)
pub parent_task_id: Option<Uuid>,
- /// True for contract supervisor tasks. Only supervisors can spawn new tasks.
- #[serde(default)]
- pub is_supervisor: bool,
/// Priority (higher = more urgent)
#[serde(default)]
pub priority: i32,
@@ -668,9 +623,6 @@ pub struct CreateTaskRequest {
pub branched_from_task_id: Option<Uuid>,
/// Conversation history to initialize the task with (JSON array of messages)
pub conversation_history: Option<serde_json::Value>,
- /// Task ID whose worktree this task shares. When set, this task reuses the supervisor's
- /// worktree instead of creating its own, and should NOT have its worktree deleted during cleanup.
- pub supervisor_worktree_task_id: Option<Uuid>,
/// Directive this task belongs to (for directive-driven tasks)
pub directive_id: Option<Uuid>,
/// Directive step this task executes
@@ -935,87 +887,8 @@ pub struct TaskOutputResponse {
pub task_id: Uuid,
}
-// =============================================================================
-// Mesh Chat History Types
-// =============================================================================
-
-/// Mesh chat conversation for persisting history
-#[derive(Debug, Clone, FromRow, Serialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct MeshChatConversation {
- pub id: Uuid,
- pub owner_id: Uuid,
- pub name: Option<String>,
- pub is_active: bool,
- pub created_at: DateTime<Utc>,
- pub updated_at: DateTime<Utc>,
-}
-
-/// Individual message in a mesh chat conversation
-#[derive(Debug, Clone, FromRow, Serialize, Deserialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct MeshChatMessageRecord {
- pub id: Uuid,
- pub conversation_id: Uuid,
- pub role: String,
- pub content: String,
- pub context_type: String,
- pub context_task_id: Option<Uuid>,
- /// Tool calls made during this message (JSON, nullable)
- pub tool_calls: Option<serde_json::Value>,
- /// Pending questions requiring user response (JSON, nullable)
- pub pending_questions: Option<serde_json::Value>,
- pub created_at: DateTime<Utc>,
-}
-
-/// Response for chat history endpoint
-#[derive(Debug, Serialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct MeshChatHistoryResponse {
- pub conversation_id: Uuid,
- pub messages: Vec<MeshChatMessageRecord>,
-}
-
-// =============================================================================
-// Contract Chat History Types
-// =============================================================================
-
-/// Conversation thread for contract chat (scoped to a specific contract)
-#[derive(Debug, Clone, FromRow, Serialize, Deserialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct ContractChatConversation {
- pub id: Uuid,
- pub contract_id: Uuid,
- pub owner_id: Uuid,
- pub name: Option<String>,
- pub is_active: bool,
- pub created_at: DateTime<Utc>,
- pub updated_at: DateTime<Utc>,
-}
-
-/// Individual message in a contract chat conversation
-#[derive(Debug, Clone, FromRow, Serialize, Deserialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct ContractChatMessageRecord {
- pub id: Uuid,
- pub conversation_id: Uuid,
- pub role: String,
- pub content: String,
- /// Tool calls made during this message (JSON, nullable)
- pub tool_calls: Option<serde_json::Value>,
- /// Pending questions requiring user response (JSON, nullable)
- pub pending_questions: Option<serde_json::Value>,
- pub created_at: DateTime<Utc>,
-}
-
-/// Response for contract chat history endpoint
-#[derive(Debug, Serialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct ContractChatHistoryResponse {
- pub contract_id: Uuid,
- pub conversation_id: Uuid,
- pub messages: Vec<ContractChatMessageRecord>,
-}
+// (MeshChat* + ContractChat* types removed alongside their dead
+// tables/handlers — see migration 20260517000000.)
// =============================================================================
// Merge API Types
@@ -1120,772 +993,6 @@ pub struct MergeCompleteCheckResponse {
pub skipped_count: u32,
}
-// =============================================================================
-// Contract Type Templates (User-defined)
-// =============================================================================
-
-/// A phase definition within a contract template
-#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct PhaseDefinition {
- /// Phase identifier (e.g., "research", "plan", "execute")
- pub id: String,
- /// Display name for the phase
- pub name: String,
- /// Order in the workflow (0-indexed)
- pub order: i32,
-}
-
-/// A deliverable definition within a phase
-#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct DeliverableDefinition {
- /// Deliverable identifier (e.g., "plan-document", "pull-request")
- pub id: String,
- /// Display name for the deliverable
- pub name: String,
- /// Priority: "required", "recommended", or "optional"
- #[serde(default = "default_priority")]
- pub priority: String,
-}
-
-fn default_priority() -> String {
- "required".to_string()
-}
-
-/// Phase configuration stored on a contract (copied from template at creation)
-#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct PhaseConfig {
- /// Ordered list of phases in the workflow
- pub phases: Vec<PhaseDefinition>,
- /// Default starting phase
- pub default_phase: String,
- /// Deliverables per phase: { "phase_id": [deliverables] }
- #[serde(default)]
- pub deliverables: std::collections::HashMap<String, Vec<DeliverableDefinition>>,
-}
-
-/// Contract type template record from the database
-#[derive(Debug, Clone, FromRow, Serialize, Deserialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct ContractTypeTemplateRecord {
- pub id: Uuid,
- pub owner_id: Uuid,
- pub name: String,
- pub description: Option<String>,
- #[sqlx(json)]
- pub phases: Vec<PhaseDefinition>,
- pub default_phase: String,
- #[sqlx(json)]
- pub deliverables: Option<std::collections::HashMap<String, Vec<DeliverableDefinition>>>,
- pub version: i32,
- pub created_at: DateTime<Utc>,
- pub updated_at: DateTime<Utc>,
-}
-
-/// Request to create a new contract type template
-#[derive(Debug, Clone, Deserialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct CreateTemplateRequest {
- pub name: String,
- pub description: Option<String>,
- pub phases: Vec<PhaseDefinition>,
- pub default_phase: String,
- pub deliverables: Option<std::collections::HashMap<String, Vec<DeliverableDefinition>>>,
-}
-
-/// Request to update a contract type template
-#[derive(Debug, Clone, Deserialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct UpdateTemplateRequest {
- pub name: Option<String>,
- pub description: Option<String>,
- pub phases: Option<Vec<PhaseDefinition>>,
- pub default_phase: Option<String>,
- pub deliverables: Option<std::collections::HashMap<String, Vec<DeliverableDefinition>>>,
- /// Version for optimistic locking
- pub version: Option<i32>,
-}
-
-/// Summary of a contract type template for list views
-#[derive(Debug, Clone, Serialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct ContractTypeTemplateSummary {
- pub id: Uuid,
- pub name: String,
- pub description: Option<String>,
- pub phases: Vec<PhaseDefinition>,
- pub default_phase: String,
- pub is_builtin: bool,
- pub version: i32,
- pub created_at: DateTime<Utc>,
-}
-
-// =============================================================================
-// Contract Types
-// =============================================================================
-
-/// Contract type determines the workflow and required documents
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
-#[serde(rename_all = "lowercase")]
-pub enum ContractType {
- /// Simple Plan -> Execute workflow (default)
- /// - Plan phase: requires a "Plan" document
- /// - Execute phase: requires a "PR" document
- Simple,
- /// Specification-based development with TDD
- /// - Research: requires "Research Notes" document
- /// - Specify: requires "Requirements Document"
- /// - Plan: requires "Plan" document
- /// - Execute: requires "PR" document
- /// - Review: requires "Release Notes" document
- Specification,
- /// Execute-only workflow with no deliverables
- /// - Only has "execute" phase
- /// - NO deliverables at all - just execute tasks directly
- Execute,
-}
-
-impl Default for ContractType {
- fn default() -> Self {
- ContractType::Simple
- }
-}
-
-impl std::fmt::Display for ContractType {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- ContractType::Simple => write!(f, "simple"),
- ContractType::Specification => write!(f, "specification"),
- ContractType::Execute => write!(f, "execute"),
- }
- }
-}
-
-impl std::str::FromStr for ContractType {
- type Err = String;
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s.to_lowercase().as_str() {
- "simple" => Ok(ContractType::Simple),
- "specification" => Ok(ContractType::Specification),
- "execute" => Ok(ContractType::Execute),
- _ => Err(format!("Unknown contract type: {}", s)),
- }
- }
-}
-
-/// Contract phase for workflow progression
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
-#[serde(rename_all = "lowercase")]
-pub enum ContractPhase {
- Research,
- Specify,
- Plan,
- Execute,
- Review,
-}
-
-impl std::fmt::Display for ContractPhase {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- ContractPhase::Research => write!(f, "research"),
- ContractPhase::Specify => write!(f, "specify"),
- ContractPhase::Plan => write!(f, "plan"),
- ContractPhase::Execute => write!(f, "execute"),
- ContractPhase::Review => write!(f, "review"),
- }
- }
-}
-
-impl std::str::FromStr for ContractPhase {
- type Err = String;
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s.to_lowercase().as_str() {
- "research" => Ok(ContractPhase::Research),
- "specify" => Ok(ContractPhase::Specify),
- "plan" => Ok(ContractPhase::Plan),
- "execute" => Ok(ContractPhase::Execute),
- "review" => Ok(ContractPhase::Review),
- _ => Err(format!("Unknown contract phase: {}", s)),
- }
- }
-}
-
-/// Contract status
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
-#[serde(rename_all = "lowercase")]
-pub enum ContractStatus {
- Active,
- Completed,
- Archived,
-}
-
-impl std::fmt::Display for ContractStatus {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- ContractStatus::Active => write!(f, "active"),
- ContractStatus::Completed => write!(f, "completed"),
- ContractStatus::Archived => write!(f, "archived"),
- }
- }
-}
-
-impl std::str::FromStr for ContractStatus {
- type Err = String;
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s.to_lowercase().as_str() {
- "active" => Ok(ContractStatus::Active),
- "completed" => Ok(ContractStatus::Completed),
- "archived" => Ok(ContractStatus::Archived),
- _ => Err(format!("Unknown contract status: {}", s)),
- }
- }
-}
-
-/// Repository source type
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
-#[serde(rename_all = "lowercase")]
-pub enum RepositorySourceType {
- /// Existing remote repo (GitHub, GitLab, etc)
- Remote,
- /// Existing local repo
- Local,
- /// New repo created/managed by Makima daemon
- Managed,
-}
-
-impl std::fmt::Display for RepositorySourceType {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- RepositorySourceType::Remote => write!(f, "remote"),
- RepositorySourceType::Local => write!(f, "local"),
- RepositorySourceType::Managed => write!(f, "managed"),
- }
- }
-}
-
-impl std::str::FromStr for RepositorySourceType {
- type Err = String;
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s.to_lowercase().as_str() {
- "remote" => Ok(RepositorySourceType::Remote),
- "local" => Ok(RepositorySourceType::Local),
- "managed" => Ok(RepositorySourceType::Managed),
- _ => Err(format!("Unknown repository source type: {}", s)),
- }
- }
-}
-
-/// Repository status (for managed repos)
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
-#[serde(rename_all = "lowercase")]
-pub enum RepositoryStatus {
- /// Repo is usable
- Ready,
- /// Waiting for daemon to create
- Pending,
- /// Daemon is creating the repo
- Creating,
- /// Creation failed
- Failed,
-}
-
-impl std::fmt::Display for RepositoryStatus {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- RepositoryStatus::Ready => write!(f, "ready"),
- RepositoryStatus::Pending => write!(f, "pending"),
- RepositoryStatus::Creating => write!(f, "creating"),
- RepositoryStatus::Failed => write!(f, "failed"),
- }
- }
-}
-
-impl std::str::FromStr for RepositoryStatus {
- type Err = String;
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s.to_lowercase().as_str() {
- "ready" => Ok(RepositoryStatus::Ready),
- "pending" => Ok(RepositoryStatus::Pending),
- "creating" => Ok(RepositoryStatus::Creating),
- "failed" => Ok(RepositoryStatus::Failed),
- _ => Err(format!("Unknown repository status: {}", s)),
- }
- }
-}
-
-/// Contract record from the database
-#[derive(Debug, Clone, FromRow, Serialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct Contract {
- pub id: Uuid,
- pub owner_id: Uuid,
- pub name: String,
- pub description: Option<String>,
- /// Contract type: "simple" or "specification"
- pub contract_type: String,
- pub phase: String,
- pub status: String,
- /// The long-running supervisor task that orchestrates this contract
- #[serde(skip_serializing_if = "Option::is_none")]
- pub supervisor_task_id: Option<Uuid>,
- /// Whether tasks for this contract should run in autonomous loop mode.
- /// When enabled, tasks will automatically restart with --continue if they exit
- /// without a COMPLETION_GATE indicating ready: true.
- #[serde(default)]
- pub autonomous_loop: bool,
- /// Whether to wait for user confirmation before progressing to the next phase.
- /// When enabled, the supervisor will pause and ask the user to review and approve
- /// phase outputs (like plans, requirements, etc.) before continuing.
- #[serde(default)]
- pub phase_guard: bool,
- /// Completed deliverables per phase.
- /// Structure: { "plan": ["plan-document"], "execute": ["pull-request"] }
- #[sqlx(json)]
- #[serde(default)]
- pub completed_deliverables: serde_json::Value,
- /// Whether this contract operates in local-only mode.
- /// When enabled, automatic completion actions (branch, merge, pr) are skipped,
- /// allowing users to manually handle code changes via patch files or other means.
- #[serde(default)]
- pub local_only: bool,
- /// Whether to auto-merge to target branch locally when local_only mode is enabled.
- /// When both local_only and auto_merge_local are true, completed task changes will be
- /// automatically merged to the master/main branch locally (without pushing or creating PRs).
- #[serde(default)]
- pub auto_merge_local: bool,
- /// Phase configuration copied from template at contract creation (raw JSON).
- /// When present, this overrides the built-in contract type phases.
- /// Use `get_phase_config()` to get the parsed PhaseConfig.
- #[serde(skip_serializing_if = "Option::is_none")]
- pub phase_config: Option<serde_json::Value>,
- pub version: i32,
- pub created_at: DateTime<Utc>,
- pub updated_at: DateTime<Utc>,
-}
-
-impl Contract {
- /// Parse contract_type string to ContractType enum
- pub fn contract_type_enum(&self) -> Result<ContractType, String> {
- self.contract_type.parse()
- }
-
- /// Parse phase string to ContractPhase enum
- pub fn phase_enum(&self) -> Result<ContractPhase, String> {
- self.phase.parse()
- }
-
- /// Parse status string to ContractStatus enum
- pub fn status_enum(&self) -> Result<ContractStatus, String> {
- self.status.parse()
- }
-
- /// Get valid phase IDs for this contract (as strings)
- pub fn valid_phase_ids(&self) -> Vec<String> {
- // Check phase_config first (for custom templates)
- if let Some(config) = self.get_phase_config() {
- let mut phases: Vec<_> = config.phases.iter().collect();
- phases.sort_by_key(|p| p.order);
- return phases.iter().map(|p| p.id.clone()).collect();
- }
-
- // Fall back to built-in contract types
- match self.contract_type.as_str() {
- "simple" => vec!["plan".to_string(), "execute".to_string()],
- "specification" => vec![
- "research".to_string(),
- "specify".to_string(),
- "plan".to_string(),
- "execute".to_string(),
- "review".to_string(),
- ],
- "execute" => vec!["execute".to_string()],
- _ => vec!["plan".to_string(), "execute".to_string()],
- }
- }
-
- /// Get valid phases for this contract type (as ContractPhase enums)
- /// Note: For custom templates with non-standard phases, this only returns
- /// phases that map to the ContractPhase enum.
- pub fn valid_phases(&self) -> Vec<ContractPhase> {
- self.valid_phase_ids()
- .iter()
- .filter_map(|id| id.parse::<ContractPhase>().ok())
- .collect()
- }
-
- /// Get the initial phase ID for this contract type (as string)
- pub fn initial_phase_id(&self) -> String {
- // Check phase_config first (for custom templates)
- if let Some(config) = self.get_phase_config() {
- return config.default_phase.clone();
- }
-
- // Fall back to built-in contract types
- match self.contract_type.as_str() {
- "specification" => "research".to_string(),
- "execute" => "execute".to_string(),
- _ => "plan".to_string(),
- }
- }
-
- /// Get the initial phase for this contract type (as ContractPhase enum)
- pub fn initial_phase(&self) -> ContractPhase {
- self.initial_phase_id()
- .parse()
- .unwrap_or(ContractPhase::Plan)
- }
-
- /// Get the terminal phase ID for this contract type (as string)
- pub fn terminal_phase_id(&self) -> String {
- // Check phase_config first (for custom templates)
- if let Some(config) = self.get_phase_config() {
- // Last phase in sorted order is the terminal phase
- let mut phases: Vec<_> = config.phases.iter().collect();
- phases.sort_by_key(|p| p.order);
- if let Some(last) = phases.last() {
- return last.id.clone();
- }
- }
-
- // Fall back to built-in contract types
- match self.contract_type.as_str() {
- "specification" => "review".to_string(),
- _ => "execute".to_string(),
- }
- }
-
- /// Get the terminal phase for this contract type (phase where contract can be completed)
- pub fn terminal_phase(&self) -> ContractPhase {
- self.terminal_phase_id()
- .parse()
- .unwrap_or(ContractPhase::Execute)
- }
-
- /// Check if a phase ID is valid for this contract
- pub fn is_valid_phase(&self, phase_id: &str) -> bool {
- self.valid_phase_ids().contains(&phase_id.to_string())
- }
-
- /// Get the phase configuration for custom templates
- pub fn get_phase_config(&self) -> Option<PhaseConfig> {
- self.phase_config
- .as_ref()
- .and_then(|v| serde_json::from_value(v.clone()).ok())
- }
-
- /// Get completed deliverable IDs for a specific phase
- pub fn get_completed_deliverables(&self, phase: &str) -> Vec<String> {
- self.completed_deliverables
- .get(phase)
- .and_then(|v| v.as_array())
- .map(|arr| {
- arr.iter()
- .filter_map(|v| v.as_str().map(String::from))
- .collect()
- })
- .unwrap_or_default()
- }
-
- /// Check if a specific deliverable is marked as complete for a phase
- pub fn is_deliverable_complete(&self, phase: &str, deliverable_id: &str) -> bool {
- self.get_completed_deliverables(phase)
- .contains(&deliverable_id.to_string())
- }
-}
-
-/// Contract repository record from the database
-#[derive(Debug, Clone, FromRow, Serialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct ContractRepository {
- pub id: Uuid,
- pub contract_id: Uuid,
- pub name: String,
- pub repository_url: Option<String>,
- pub local_path: Option<String>,
- pub source_type: String,
- pub status: String,
- pub is_primary: bool,
- pub created_at: DateTime<Utc>,
- pub updated_at: DateTime<Utc>,
-}
-
-impl ContractRepository {
- /// Parse source_type string to RepositorySourceType enum
- pub fn source_type_enum(&self) -> Result<RepositorySourceType, String> {
- self.source_type.parse()
- }
-
- /// Parse status string to RepositoryStatus enum
- pub fn status_enum(&self) -> Result<RepositoryStatus, String> {
- self.status.parse()
- }
-}
-
-/// Summary of a contract for list views
-#[derive(Debug, Clone, FromRow, Serialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct ContractSummary {
- pub id: Uuid,
- pub name: String,
- pub description: Option<String>,
- /// Contract type: "simple" or "specification"
- pub contract_type: String,
- pub phase: String,
- pub status: String,
- /// Supervisor task ID for contract orchestration
- pub supervisor_task_id: Option<Uuid>,
- /// When true, tasks do not auto-execute completion actions and work stays in worktrees.
- #[serde(default)]
- pub local_only: bool,
- /// When true with local_only, automatically merge completed tasks to target branch locally.
- #[serde(default)]
- pub auto_merge_local: bool,
- pub file_count: i64,
- pub task_count: i64,
- pub repository_count: i64,
- pub version: i32,
- pub created_at: DateTime<Utc>,
-}
-
-/// Contract with all relations for detail view
-#[derive(Debug, Serialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct ContractWithRelations {
- #[serde(flatten)]
- pub contract: Contract,
- pub repositories: Vec<ContractRepository>,
- pub files: Vec<FileSummary>,
- pub tasks: Vec<TaskSummary>,
-}
-
-/// Response for contract list endpoint
-#[derive(Debug, Serialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct ContractListResponse {
- pub contracts: Vec<ContractSummary>,
- pub total: i64,
-}
-
-/// Request payload for creating a new contract
-#[derive(Debug, Clone, Deserialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct CreateContractRequest {
- /// Name of the contract
- pub name: String,
- /// Optional description
- pub description: Option<String>,
- /// Contract type: "simple" (default), "specification", "execute", or a custom template name.
- /// For built-in types:
- /// - simple: Plan -> Execute workflow
- /// - specification: Research -> Specify -> Plan -> Execute -> Review
- /// - execute: Execute only
- /// For custom templates, use the template name or provide template_id.
- #[serde(default)]
- pub contract_type: Option<String>,
- /// UUID of a custom template to use. If provided, this takes precedence over contract_type.
- /// The template's phase configuration will be copied to the contract.
- #[serde(default)]
- pub template_id: Option<Uuid>,
- /// Initial phase to start in (defaults based on contract_type or template)
- /// - simple: defaults to "plan"
- /// - specification: defaults to "research"
- #[serde(default)]
- pub initial_phase: Option<String>,
- /// Enable autonomous loop mode for tasks in this contract.
- /// When enabled, tasks automatically restart with --continue if they exit
- /// without a COMPLETION_GATE indicating ready: true.
- #[serde(default)]
- pub autonomous_loop: Option<bool>,
- /// Enable phase guard mode for this contract.
- /// When enabled, the supervisor will pause and ask the user to review and approve
- /// phase outputs before progressing to the next phase.
- #[serde(default)]
- pub phase_guard: Option<bool>,
- /// Enable local-only mode for this contract.
- /// When enabled, automatic completion actions (branch, merge, pr) are skipped,
- /// allowing users to manually handle code changes via patch files or other means.
- #[serde(default)]
- pub local_only: Option<bool>,
- /// Enable auto-merge to target branch locally when local_only mode is enabled.
- /// When both local_only and auto_merge_local are true, completed task changes will be
- /// automatically merged to the master/main branch locally (without pushing or creating PRs).
- #[serde(default)]
- pub auto_merge_local: Option<bool>,
-}
-
-/// Request payload for updating a contract
-#[derive(Debug, Default, Deserialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct UpdateContractRequest {
- pub name: Option<String>,
- pub description: Option<String>,
- pub phase: Option<String>,
- pub status: Option<String>,
- /// Supervisor task ID for contract orchestration
- #[serde(skip_serializing_if = "Option::is_none")]
- pub supervisor_task_id: Option<Uuid>,
- /// Enable or disable autonomous loop mode for tasks in this contract.
- #[serde(default)]
- pub autonomous_loop: Option<bool>,
- /// Enable or disable phase guard mode for this contract.
- /// When enabled, the supervisor will pause and ask the user to review and approve
- /// phase outputs before progressing to the next phase.
- #[serde(default)]
- pub phase_guard: Option<bool>,
- /// Enable or disable local-only mode for this contract.
- /// When enabled, automatic completion actions (branch, merge, pr) are skipped,
- /// allowing users to manually handle code changes via patch files or other means.
- #[serde(default)]
- pub local_only: Option<bool>,
- /// Enable or disable auto-merge to target branch locally when local_only mode is enabled.
- /// When both local_only and auto_merge_local are true, completed task changes will be
- /// automatically merged to the master/main branch locally (without pushing or creating PRs).
- #[serde(default)]
- pub auto_merge_local: Option<bool>,
- /// Version for optimistic locking
- pub version: Option<i32>,
-}
-
-/// Request to add a remote repository to a contract
-#[derive(Debug, Deserialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct AddRemoteRepositoryRequest {
- pub name: String,
- pub repository_url: String,
- #[serde(default)]
- pub is_primary: bool,
-}
-
-/// Request to add a local repository to a contract
-#[derive(Debug, Deserialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct AddLocalRepositoryRequest {
- pub name: String,
- pub local_path: String,
- #[serde(default)]
- pub is_primary: bool,
-}
-
-/// Request to create a managed repository (daemon will create it)
-#[derive(Debug, Deserialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct CreateManagedRepositoryRequest {
- pub name: String,
- #[serde(default)]
- pub is_primary: bool,
-}
-
-/// Request to change contract phase
-#[derive(Debug, Deserialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct ChangePhaseRequest {
- pub phase: String,
- /// If phase_guard is enabled, this must be true to confirm the transition.
- /// If not provided or false, returns phase deliverables for review.
- #[serde(default)]
- pub confirmed: Option<bool>,
- /// User feedback for changes (used when not confirming)
- #[serde(skip_serializing_if = "Option::is_none")]
- pub feedback: Option<String>,
- /// Expected version for optimistic locking. If provided, the phase change
- /// will only succeed if the current contract version matches.
- #[serde(skip_serializing_if = "Option::is_none")]
- pub expected_version: Option<i32>,
-}
-
-/// Result of a phase change operation, supporting explicit conflict detection.
-#[derive(Debug, Clone)]
-pub enum PhaseChangeResult {
- /// Phase change succeeded, returning the updated contract
- Success(Contract),
- /// Version conflict: the contract was modified concurrently
- VersionConflict {
- /// The version the client expected
- expected: i32,
- /// The actual current version in the database
- actual: i32,
- /// The current phase of the contract
- current_phase: String,
- },
- /// Validation failed (e.g., invalid phase transition)
- ValidationFailed {
- /// Human-readable reason for the failure
- reason: String,
- /// List of missing requirements for the phase transition
- missing_requirements: Vec<String>,
- },
- /// The caller is not authorized to change this contract's phase
- Unauthorized,
- /// The contract was not found
- NotFound,
-}
-
-/// Response for phase transition when phase_guard is enabled
-#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct PhaseTransitionRequest {
- /// Current contract phase
- pub current_phase: String,
- /// Requested next phase
- pub next_phase: String,
- /// Summary of phase deliverables/outputs
- pub deliverables_summary: String,
- /// List of files created in this phase
- pub phase_files: Vec<PhaseFileInfo>,
- /// List of completed tasks in this phase
- pub phase_tasks: Vec<PhaseTaskInfo>,
- /// Whether user confirmation is required
- pub requires_confirmation: bool,
- /// Unique ID for tracking this transition request
- pub transition_id: String,
-}
-
-/// File info for phase transition review
-#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct PhaseFileInfo {
- pub id: Uuid,
- pub name: String,
- pub description: Option<String>,
-}
-
-/// Task info for phase transition review
-#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct PhaseTaskInfo {
- pub id: Uuid,
- pub name: String,
- pub status: String,
-}
-
-/// Contract event record from the database
-#[derive(Debug, Clone, FromRow, Serialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct ContractEvent {
- pub id: Uuid,
- pub contract_id: Uuid,
- pub event_type: String,
- pub previous_phase: Option<String>,
- pub new_phase: Option<String>,
- #[sqlx(json)]
- pub event_data: Option<serde_json::Value>,
- pub created_at: DateTime<Utc>,
-}
-
-/// Response for contract events list endpoint
-#[derive(Debug, Serialize, ToSchema)]
-#[serde(rename_all = "camelCase")]
-pub struct ContractEventListResponse {
- pub events: Vec<ContractEvent>,
- pub total: i64,
-}
// ============================================================================
// Task Checkpoints (for git checkpoint tracking)
@@ -2173,11 +1280,9 @@ pub struct ConversationSnapshot {
pub struct HistoryEvent {
pub id: Uuid,
pub owner_id: Uuid,
- pub contract_id: Option<Uuid>,
pub task_id: Option<Uuid>,
pub event_type: String,
pub event_subtype: Option<String>,
- pub phase: Option<String>,
#[sqlx(json)]
pub event_data: serde_json::Value,
pub created_at: DateTime<Utc>,
@@ -2221,7 +1326,6 @@ pub struct ToolCallInfo {
#[derive(Debug, Deserialize, ToSchema, Default)]
#[serde(rename_all = "camelCase")]
pub struct HistoryQueryFilters {
- pub phase: Option<String>,
pub event_types: Option<Vec<String>>,
#[serde(default, deserialize_with = "flexible_datetime::deserialize")]
pub from: Option<DateTime<Utc>>,
@@ -2766,11 +1870,6 @@ pub struct DirectiveStep {
/// Status: pending, ready, running, completed, failed, skipped
pub status: String,
pub task_id: Option<Uuid>,
- /// Optional contract ID for contract-backed execution.
- pub contract_id: Option<Uuid>,
- /// Optional contract type (e.g. "simple", "specification", "execute").
- /// When set, the orchestrator creates a contract instead of a standalone task.
- pub contract_type: Option<String>,
pub order_index: i32,
pub generation: i32,
pub started_at: Option<DateTime<Utc>>,