summaryrefslogtreecommitdiff
path: root/makima/src/db
diff options
context:
space:
mode:
Diffstat (limited to 'makima/src/db')
-rw-r--r--makima/src/db/repository.rs74
1 files changed, 68 insertions, 6 deletions
diff --git a/makima/src/db/repository.rs b/makima/src/db/repository.rs
index 1021c35..27bd47e 100644
--- a/makima/src/db/repository.rs
+++ b/makima/src/db/repository.rs
@@ -5625,12 +5625,15 @@ pub async fn check_directive_idle(
}
/// Update a directive's goal and bump goal_updated_at.
-/// Reactivates draft/idle/paused directives and clears any stale orchestrator
-/// task so that planning/replanning triggers on the next reconciler tick.
+/// Reactivates draft/idle/paused/inactive directives and clears any stale
+/// orchestrator task so that planning/replanning triggers on the next
+/// reconciler tick.
///
-/// `draft` is included in the flip set because the document-mode UI treats
-/// the first goal save as the implicit "start" — without this, a brand-new
-/// directive's goal save would persist but never spawn a planner.
+/// `draft` flips because the document-mode UI treats the first goal save as
+/// the implicit "start". `inactive` flips because editing a contract whose
+/// last revision was already shipped is the way the user kicks off an
+/// amendment — the planner picks it up via phase_planning/replanning and
+/// uses get_latest_merged_revision to learn the BEFORE→AFTER diff.
pub async fn update_directive_goal(
pool: &PgPool,
owner_id: Uuid,
@@ -5642,7 +5645,10 @@ pub async fn update_directive_goal(
UPDATE directives
SET goal = $3,
goal_updated_at = NOW(),
- status = CASE WHEN status IN ('draft', 'idle', 'paused') THEN 'active' ELSE status END,
+ status = CASE
+ WHEN status IN ('draft', 'idle', 'paused', 'inactive') THEN 'active'
+ ELSE status
+ END,
orchestrator_task_id = NULL,
updated_at = NOW(),
version = version + 1
@@ -5657,6 +5663,62 @@ pub async fn update_directive_goal(
.await
}
+/// Mark a directive 'inactive'. Used at the moment a PR is raised — at that
+/// point the contract's current iteration is "shipped" and editing the goal
+/// (Stage 4) starts an amendment cycle. Idempotent: no-op if status is
+/// already inactive or already past it (e.g. archived).
+pub async fn set_directive_inactive(
+ pool: &PgPool,
+ directive_id: Uuid,
+) -> Result<(), sqlx::Error> {
+ sqlx::query(
+ r#"
+ UPDATE directives
+ SET status = 'inactive',
+ updated_at = NOW(),
+ version = version + 1
+ WHERE id = $1
+ AND status IN ('active', 'idle', 'paused')
+ "#,
+ )
+ .bind(directive_id)
+ .execute(pool)
+ .await?;
+ Ok(())
+}
+
+/// Reset a directive for a "new draft" cycle: clear the goal back to empty,
+/// flip status to 'draft', and detach the current pr_url / pr_branch /
+/// orchestrator linkage so the next goal save starts fresh. Prior revisions
+/// remain in `directive_revisions` as the historical record. Used by the
+/// sidebar's "New draft" right-click on inactive contracts.
+pub async fn reset_directive_for_new_draft(
+ pool: &PgPool,
+ owner_id: Uuid,
+ directive_id: Uuid,
+) -> Result<Option<Directive>, sqlx::Error> {
+ sqlx::query_as::<_, Directive>(
+ r#"
+ UPDATE directives
+ SET goal = '',
+ goal_updated_at = NOW(),
+ status = 'draft',
+ pr_url = NULL,
+ pr_branch = NULL,
+ orchestrator_task_id = NULL,
+ completion_task_id = NULL,
+ updated_at = NOW(),
+ version = version + 1
+ WHERE id = $1 AND owner_id = $2
+ RETURNING *
+ "#,
+ )
+ .bind(directive_id)
+ .bind(owner_id)
+ .fetch_optional(pool)
+ .await
+}
+
/// Update a directive's goal WITHOUT clearing the orchestrator task id.
///
/// This is the path used by the goal-edit interrupt cycle: when a small goal