From 06fb883b2b7a49c7123722463d24b0b4e57c3277 Mon Sep 17 00:00:00 2001 From: soryu Date: Sat, 17 Jan 2026 06:05:21 +0000 Subject: Add phase_guard field to Contract model and database This adds a new boolean field to control whether the supervisor should wait for user confirmation before progressing to the next phase. When enabled, users can review and potentially amend phase outputs (like plans, requirements docs) before the contract continues. Changes: - Add migration for phase_guard column (defaults to false) - Add phase_guard to Contract, CreateContractRequest, and UpdateContractRequest structs - Update create_contract_for_owner and update_contract_for_owner repository functions to handle phase_guard - Update all CreateContractRequest instantiations with phase_guard field Co-Authored-By: Claude Opus 4.5 --- makima/src/db/models.rs | 15 +++++++++++++++ makima/src/db/repository.rs | 15 ++++++++++----- makima/src/server/handlers/contract_chat.rs | 1 + makima/src/server/handlers/mesh.rs | 1 + makima/src/server/handlers/transcript_analysis.rs | 1 + 5 files changed, 28 insertions(+), 5 deletions(-) (limited to 'makima/src') diff --git a/makima/src/db/models.rs b/makima/src/db/models.rs index 72ba6f2..33ef52e 100644 --- a/makima/src/db/models.rs +++ b/makima/src/db/models.rs @@ -1264,6 +1264,11 @@ pub struct Contract { /// 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, pub version: i32, pub created_at: DateTime, pub updated_at: DateTime, @@ -1389,6 +1394,11 @@ pub struct CreateContractRequest { /// without a COMPLETION_GATE indicating ready: true. #[serde(default)] pub autonomous_loop: Option, + /// 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, } /// Request payload for updating a contract @@ -1405,6 +1415,11 @@ pub struct UpdateContractRequest { /// Enable or disable autonomous loop mode for tasks in this contract. #[serde(default)] pub autonomous_loop: Option, + /// 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, /// Version for optimistic locking pub version: Option, } diff --git a/makima/src/db/repository.rs b/makima/src/db/repository.rs index 43b8e3a..3d1efd1 100644 --- a/makima/src/db/repository.rs +++ b/makima/src/db/repository.rs @@ -2136,11 +2136,12 @@ pub async fn create_contract_for_owner( } let autonomous_loop = req.autonomous_loop.unwrap_or(false); + let phase_guard = req.phase_guard.unwrap_or(false); sqlx::query_as::<_, Contract>( r#" - INSERT INTO contracts (owner_id, name, description, contract_type, phase, autonomous_loop) - VALUES ($1, $2, $3, $4, $5, $6) + INSERT INTO contracts (owner_id, name, description, contract_type, phase, autonomous_loop, phase_guard) + VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING * "#, ) @@ -2150,6 +2151,7 @@ pub async fn create_contract_for_owner( .bind(contract_type) .bind(phase) .bind(autonomous_loop) + .bind(phase_guard) .fetch_one(pool) .await } @@ -2249,14 +2251,15 @@ pub async fn update_contract_for_owner( let status = req.status.unwrap_or(existing.status); let supervisor_task_id = req.supervisor_task_id.or(existing.supervisor_task_id); let autonomous_loop = req.autonomous_loop.unwrap_or(existing.autonomous_loop); + let phase_guard = req.phase_guard.unwrap_or(existing.phase_guard); let result = if req.version.is_some() { sqlx::query_as::<_, Contract>( r#" UPDATE contracts SET name = $3, description = $4, phase = $5, status = $6, - supervisor_task_id = $7, autonomous_loop = $8, version = version + 1, updated_at = NOW() - WHERE id = $1 AND owner_id = $2 AND version = $9 + supervisor_task_id = $7, autonomous_loop = $8, phase_guard = $9, version = version + 1, updated_at = NOW() + WHERE id = $1 AND owner_id = $2 AND version = $10 RETURNING * "#, ) @@ -2268,6 +2271,7 @@ pub async fn update_contract_for_owner( .bind(&status) .bind(supervisor_task_id) .bind(autonomous_loop) + .bind(phase_guard) .bind(req.version.unwrap()) .fetch_optional(pool) .await? @@ -2276,7 +2280,7 @@ pub async fn update_contract_for_owner( r#" UPDATE contracts SET name = $3, description = $4, phase = $5, status = $6, - supervisor_task_id = $7, autonomous_loop = $8, version = version + 1, updated_at = NOW() + supervisor_task_id = $7, autonomous_loop = $8, phase_guard = $9, version = version + 1, updated_at = NOW() WHERE id = $1 AND owner_id = $2 RETURNING * "#, @@ -2289,6 +2293,7 @@ pub async fn update_contract_for_owner( .bind(&status) .bind(supervisor_task_id) .bind(autonomous_loop) + .bind(phase_guard) .fetch_optional(pool) .await? }; diff --git a/makima/src/server/handlers/contract_chat.rs b/makima/src/server/handlers/contract_chat.rs index 101b257..48dd864 100644 --- a/makima/src/server/handlers/contract_chat.rs +++ b/makima/src/server/handlers/contract_chat.rs @@ -2377,6 +2377,7 @@ async fn handle_contract_request( contract_type: Some("specification".to_string()), initial_phase: Some("research".to_string()), autonomous_loop: None, + phase_guard: None, }; let contract = match repository::create_contract_for_owner(pool, owner_id, contract_req).await { diff --git a/makima/src/server/handlers/mesh.rs b/makima/src/server/handlers/mesh.rs index 5a08a49..f8df69f 100644 --- a/makima/src/server/handlers/mesh.rs +++ b/makima/src/server/handlers/mesh.rs @@ -3239,6 +3239,7 @@ pub async fn create_adhoc_task( contract_type: Some(CONTRACT_TYPE_TASK.to_string()), initial_phase: Some("execute".to_string()), // Skip planning autonomous_loop: Some(false), + phase_guard: None, }; let contract = match repository::create_contract_for_owner(pool, auth.owner_id, contract_req).await { diff --git a/makima/src/server/handlers/transcript_analysis.rs b/makima/src/server/handlers/transcript_analysis.rs index 275905e..99f9ea7 100644 --- a/makima/src/server/handlers/transcript_analysis.rs +++ b/makima/src/server/handlers/transcript_analysis.rs @@ -277,6 +277,7 @@ pub async fn create_contract_from_analysis( contract_type: Some("specification".to_string()), initial_phase: Some("research".to_string()), autonomous_loop: None, + phase_guard: None, }; let contract = match repository::create_contract_for_owner(pool, auth.owner_id, contract_req).await { -- cgit v1.2.3