summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-01-17 06:05:21 +0000
committersoryu <soryu@soryu.co>2026-01-17 16:38:44 +0000
commit06fb883b2b7a49c7123722463d24b0b4e57c3277 (patch)
tree9c0d07daeff90fa31cea320171a8678133fab801
parent2f62df1cc89a23a5bd30e1a3f68a39bcfce9665c (diff)
downloadsoryu-06fb883b2b7a49c7123722463d24b0b4e57c3277.tar.gz
soryu-06fb883b2b7a49c7123722463d24b0b4e57c3277.zip
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 <noreply@anthropic.com>
-rw-r--r--makima/migrations/20250119000000_add_phase_guard.sql9
-rw-r--r--makima/src/db/models.rs15
-rw-r--r--makima/src/db/repository.rs15
-rw-r--r--makima/src/server/handlers/contract_chat.rs1
-rw-r--r--makima/src/server/handlers/mesh.rs1
-rw-r--r--makima/src/server/handlers/transcript_analysis.rs1
6 files changed, 37 insertions, 5 deletions
diff --git a/makima/migrations/20250119000000_add_phase_guard.sql b/makima/migrations/20250119000000_add_phase_guard.sql
new file mode 100644
index 0000000..dfa642a
--- /dev/null
+++ b/makima/migrations/20250119000000_add_phase_guard.sql
@@ -0,0 +1,9 @@
+-- Add phase_guard column to contracts table
+-- When enabled, the supervisor will wait for user confirmation before progressing to the next phase.
+-- This allows users to review and potentially amend phase outputs (plans, requirements, etc.)
+-- before the contract continues to the next phase.
+
+ALTER TABLE contracts
+ADD COLUMN IF NOT EXISTS phase_guard BOOLEAN NOT NULL DEFAULT FALSE;
+
+COMMENT ON COLUMN contracts.phase_guard IS 'Whether to wait for user confirmation before progressing to the next phase';
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<Utc>,
pub updated_at: DateTime<Utc>,
@@ -1389,6 +1394,11 @@ pub struct CreateContractRequest {
/// 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>,
}
/// 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<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>,
/// Version for optimistic locking
pub version: Option<i32>,
}
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 {