summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-02-15 22:58:17 +0000
committersoryu <soryu@soryu.co>2026-02-15 22:58:17 +0000
commitbf087f48af2962d884b861345ae52be4f4a54daa (patch)
treeb366e28a9c1e85d893fdfb8692bb9ee28e52f011
parente449d55e70453a28f1de6dc8ceccc0f23fcce4e1 (diff)
downloadsoryu-bf087f48af2962d884b861345ae52be4f4a54daa.tar.gz
soryu-bf087f48af2962d884b861345ae52be4f4a54daa.zip
Add verifier post-directive
-rw-r--r--makima/src/db/repository.rs24
-rw-r--r--makima/src/orchestration/directive.rs136
2 files changed, 154 insertions, 6 deletions
diff --git a/makima/src/db/repository.rs b/makima/src/db/repository.rs
index ed4a1fa..71ad524 100644
--- a/makima/src/db/repository.rs
+++ b/makima/src/db/repository.rs
@@ -5198,6 +5198,7 @@ pub struct DirectiveCompletionCheck {
pub completion_task_id: Uuid,
pub task_status: String,
pub pr_url: Option<String>,
+ pub task_name: String,
}
/// Get idle directives that need a completion task spawned.
@@ -5212,6 +5213,7 @@ pub async fn get_idle_directives_needing_completion(
FROM directives d
WHERE d.status = 'idle'
AND d.completion_task_id IS NULL
+ AND d.pr_branch IS NULL
AND d.repository_url IS NOT NULL
AND EXISTS (
SELECT 1 FROM directive_steps ds
@@ -5225,13 +5227,33 @@ pub async fn get_idle_directives_needing_completion(
.await
}
+/// Get directives that attempted completion (pr_branch set) but have no PR URL yet
+/// and no active completion task. These need a verification task spawned.
+pub async fn get_directives_needing_verification(
+ pool: &PgPool,
+) -> Result<Vec<Directive>, sqlx::Error> {
+ sqlx::query_as::<_, Directive>(
+ r#"
+ SELECT d.*
+ FROM directives d
+ WHERE d.status = 'idle'
+ AND d.pr_branch IS NOT NULL
+ AND d.pr_url IS NULL
+ AND d.completion_task_id IS NULL
+ AND d.repository_url IS NOT NULL
+ "#,
+ )
+ .fetch_all(pool)
+ .await
+}
+
/// Get directives with active completion tasks, joined with task status.
pub async fn get_completion_tasks_to_check(
pool: &PgPool,
) -> Result<Vec<DirectiveCompletionCheck>, sqlx::Error> {
sqlx::query_as::<_, DirectiveCompletionCheck>(
r#"
- SELECT d.id as directive_id, d.owner_id, d.completion_task_id, t.status as task_status, d.pr_url
+ SELECT d.id as directive_id, d.owner_id, d.completion_task_id, t.status as task_status, d.pr_url, t.name as task_name
FROM directives d
JOIN tasks t ON t.id = d.completion_task_id
WHERE d.completion_task_id IS NOT NULL
diff --git a/makima/src/orchestration/directive.rs b/makima/src/orchestration/directive.rs
index 0deacca..5f8cb486 100644
--- a/makima/src/orchestration/directive.rs
+++ b/makima/src/orchestration/directive.rs
@@ -660,11 +660,31 @@ impl DirectiveOrchestrator {
.await;
}
Ok(None) => {
- tracing::warn!(
- directive_id = %check.directive_id,
- task_id = %check.completion_task_id,
- "Completion task finished but no PR URL found in output"
- );
+ if check.task_name.starts_with("Verify PR:") {
+ // Verification task failed to find/create PR — mark directive completed (one-shot)
+ tracing::warn!(
+ directive_id = %check.directive_id,
+ task_id = %check.completion_task_id,
+ "Verification task finished but no PR URL found — marking directive completed"
+ );
+ let update = crate::db::models::UpdateDirectiveRequest {
+ status: Some("completed".to_string()),
+ ..Default::default()
+ };
+ let _ = repository::update_directive_for_owner(
+ &self.pool,
+ check.owner_id,
+ check.directive_id,
+ update,
+ )
+ .await;
+ } else {
+ tracing::warn!(
+ directive_id = %check.directive_id,
+ task_id = %check.completion_task_id,
+ "Completion task finished but no PR URL found — will spawn verifier"
+ );
+ }
}
Err(e) => {
tracing::warn!(
@@ -692,6 +712,58 @@ impl DirectiveOrchestrator {
}
}
+ // Part 3: Spawn verification tasks for directives with pr_branch but no pr_url
+ let verify_directives =
+ repository::get_directives_needing_verification(&self.pool).await?;
+
+ for directive in verify_directives {
+ let placeholder_id = Uuid::new_v4();
+ let claimed = repository::claim_directive_for_completion(
+ &self.pool,
+ directive.id,
+ placeholder_id,
+ )
+ .await?;
+
+ if !claimed {
+ continue;
+ }
+
+ tracing::info!(
+ directive_id = %directive.id,
+ title = %directive.title,
+ "Directive has pr_branch but no pr_url — spawning verification task"
+ );
+
+ let pr_branch = directive.pr_branch.as_deref().unwrap_or("unknown");
+ let base_branch = directive.base_branch.as_deref().unwrap_or("main");
+ let prompt = build_verification_prompt(&directive, pr_branch, base_branch);
+
+ match self
+ .spawn_completion_task(
+ directive.id,
+ directive.owner_id,
+ format!("Verify PR: {}", directive.title),
+ prompt,
+ directive.repository_url.as_deref(),
+ directive.base_branch.as_deref(),
+ )
+ .await
+ {
+ Ok(task_id) => {
+ repository::assign_completion_task(&self.pool, directive.id, task_id).await?;
+ }
+ Err(e) => {
+ tracing::warn!(
+ directive_id = %directive.id,
+ error = %e,
+ "Failed to spawn verification task — releasing claim"
+ );
+ let _ = repository::clear_completion_task(&self.pool, directive.id).await;
+ }
+ }
+ }
+
Ok(())
}
@@ -1057,3 +1129,57 @@ If there are merge conflicts, resolve them sensibly before pushing.
)
}
}
+
+/// Build a prompt for verifying whether a PR was created for a directive.
+/// This is a one-shot task: if it can't find or create the PR, the directive
+/// will be marked completed to avoid infinite retries.
+fn build_verification_prompt(
+ directive: &crate::db::models::Directive,
+ pr_branch: &str,
+ base_branch: &str,
+) -> String {
+ format!(
+ r#"You are verifying whether a PR exists for directive "{title}".
+
+The completion task already ran and pushed branch `{pr_branch}`, but the PR URL was not captured.
+
+Follow these steps IN ORDER:
+
+1. Check if a PR already exists for this branch:
+```
+gh pr list --head {pr_branch} --json url --jq '.[0].url'
+```
+
+2. If the command outputs a URL, store it:
+```
+makima directive update --pr-url "<URL_FROM_ABOVE>"
+```
+Done — the PR already exists.
+
+3. If no PR was found, check if the branch exists on the remote:
+```
+git ls-remote --heads origin {pr_branch}
+```
+
+4. If the branch exists, create the PR:
+```
+gh pr create --title "{title}" --body "Directive PR verification — auto-created" --head {pr_branch} --base {base_branch}
+```
+Then store the resulting URL:
+```
+makima directive update --pr-url "<URL_FROM_GH_PR_CREATE>"
+```
+
+5. If the branch does NOT exist on the remote, the work was likely merged directly.
+Mark the directive as completed:
+```
+makima directive update --status completed
+```
+
+IMPORTANT: You MUST run `makima directive update` with either `--pr-url` or `--status completed` before finishing.
+"#,
+ title = directive.title,
+ pr_branch = pr_branch,
+ base_branch = base_branch,
+ )
+}