diff options
| author | soryu <soryu@soryu.co> | 2026-02-15 22:58:17 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-02-15 22:58:17 +0000 |
| commit | bf087f48af2962d884b861345ae52be4f4a54daa (patch) | |
| tree | b366e28a9c1e85d893fdfb8692bb9ee28e52f011 | |
| parent | e449d55e70453a28f1de6dc8ceccc0f23fcce4e1 (diff) | |
| download | soryu-bf087f48af2962d884b861345ae52be4f4a54daa.tar.gz soryu-bf087f48af2962d884b861345ae52be4f4a54daa.zip | |
Add verifier post-directive
| -rw-r--r-- | makima/src/db/repository.rs | 24 | ||||
| -rw-r--r-- | makima/src/orchestration/directive.rs | 136 |
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, + ) +} |
