omk 0.5.0

A Rust runtime for Kimi CLI. Turns prompts into proof-backed engineering runs with gates, worktrees, and replay.
Documentation
use anyhow::Result;
use chrono::Utc;
use serde_json::json;
use std::path::{Path, PathBuf};

use crate::runtime::goal::delivery::{
    open_goal_pr_with_client, poll_github_pr_checks, GoalDeliveryPolicy, GoalGithubPrClient,
    GoalGithubPrCommandClient, GoalGithubPrDeliveryOptions, GoalGithubPrRequest, GoalMergePolicy,
};
use crate::runtime::goal::proof::GoalProof;
use crate::runtime::goal::state::{
    self, FileSystemGoalStateStore, GoalPhase, GoalStateStore, GoalStatus,
};
use crate::runtime::goal::types::{
    GoalControllerStep, GoalControllerStepKind, GoalRunUntilReadyOutcome,
};
use crate::runtime::goal::{evidence, proof};

use super::blocker::{finalize_until_ready_blocker, UntilReadyBlocker};
use super::cleanup_goal_worktrees;
use super::MANUAL_INTEGRATION_BLOCKER_FILE;

pub(crate) async fn finalize_until_ready_delivery(
    goal_id: &str,
    mut steps: Vec<GoalControllerStep>,
    policy: GoalDeliveryPolicy,
    merge_policy: GoalMergePolicy,
    enforce_protection: bool,
    project_dir: &Path,
) -> Result<GoalRunUntilReadyOutcome> {
    let state = crate::runtime::goal::resolve_goal(goal_id).await?;

    if state.slice_execution && policy != GoalDeliveryPolicy::Local {
        return super::integrator::finalize_slice_integrator(
            goal_id,
            steps,
            policy,
            merge_policy,
            enforce_protection,
            project_dir,
        )
        .await;
    }

    let mut state = crate::runtime::goal::resolve_goal(goal_id).await?;
    let mut proof = GoalProof::load(&state.state_dir).await?;

    let delivery_options = GoalGithubPrDeliveryOptions {
        policy,
        dry_run: false,
        draft: policy == GoalDeliveryPolicy::DraftPr,
        base_branch: None,
    };
    let mut client = GoalGithubPrCommandClient::default();
    let outcome = open_goal_pr_with_client(goal_id, delivery_options, &mut client).await?;

    let now = Utc::now();
    let pr_url = outcome.pr_url.clone();

    match merge_policy {
        GoalMergePolicy::Disabled => {
            state.status = GoalStatus::Ready;
            state.phase = GoalPhase::Proof;
            state.completed_at = Some(now);
            state.updated_at = now;
            FileSystemGoalStateStore::new().save(&state).await?;

            proof.status = GoalStatus::Ready;
            proof.readiness =
                "ready: integration and oracle evidence passed; merge disabled by policy"
                    .to_string();
            proof.summary = format!(
                "Goal '{}' is proof-backed ready: gates, execution, review, and integration evidence passed. Merge is disabled by policy.",
                state.normalized_goal
            );
            proof.generated_at = now;
            proof.artifacts = state.artifacts.clone();
            proof.known_gaps.clear();
            proof.human_decisions_required.clear();
            proof.git = crate::runtime::goal::evidence::detect_git_evidence(project_dir)
                .await
                .or(proof.git);
            proof::write_json_artifact(&state.state_dir.join(state::GOAL_PROOF_FILE), &proof)
                .await?;

            steps.push(GoalControllerStep {
                kind: GoalControllerStepKind::Deliver,
                status: GoalStatus::Ready,
                summary: format!(
                    "GitHub PR created under {} policy; merge disabled",
                    policy.as_str()
                ),
            });

            cleanup_goal_worktrees(&state, project_dir).await;

            Ok(GoalRunUntilReadyOutcome {
                state,
                proof,
                steps,
                blocker: None,
                policy_evidence_path: None,
            })
        }
        GoalMergePolicy::Manual => {
            let instruction = if let Some(ref url) = pr_url {
                format!("run `gh pr merge {url} --squash --delete-branch` after CI passes")
            } else {
                "no PR was created; inspect the goal state for delivery evidence".to_string()
            };
            cleanup_goal_worktrees(&state, project_dir).await;
            state.status = GoalStatus::BlockedOnHuman;
            state.phase = GoalPhase::Proof;
            state.completed_at = Some(now);
            state.updated_at = now;
            FileSystemGoalStateStore::new().save(&state).await?;

            proof.status = GoalStatus::BlockedOnHuman;
            proof.readiness =
                "blocked: manual merge required before goal is fully delivered".to_string();
            proof.summary = format!(
                "Goal '{}' passed gates, execution, review, and integration evidence. Manual merge is required.",
                state.normalized_goal
            );
            proof.generated_at = now;
            proof.artifacts = state.artifacts.clone();
            proof.human_decisions_required.push(instruction.clone());
            proof.git = crate::runtime::goal::evidence::detect_git_evidence(project_dir)
                .await
                .or(proof.git);
            proof::write_json_artifact(&state.state_dir.join(state::GOAL_PROOF_FILE), &proof)
                .await?;

            let artifact = json!({
                "status": "blocked",
                "reason": &instruction,
                "delivery_policy": policy.as_str(),
                "merge_policy": merge_policy.as_str(),
                "github_mutation": outcome.mutated,
                "integrator_acceptance": "manual",
                "proof": state::GOAL_PROOF_FILE,
                "recorded_at": now,
            });
            proof::write_json_artifact(
                &state.state_dir.join(MANUAL_INTEGRATION_BLOCKER_FILE),
                &artifact,
            )
            .await?;
            evidence::record_artifact_path_once(
                &mut state,
                "policy_blocker",
                PathBuf::from(MANUAL_INTEGRATION_BLOCKER_FILE),
                now,
            );

            steps.push(GoalControllerStep {
                kind: GoalControllerStepKind::Blocked,
                status: GoalStatus::BlockedOnHuman,
                summary: instruction.clone(),
            });

            Ok(GoalRunUntilReadyOutcome {
                state,
                proof,
                steps,
                blocker: Some(instruction),
                policy_evidence_path: Some(PathBuf::from(MANUAL_INTEGRATION_BLOCKER_FILE)),
            })
        }
        GoalMergePolicy::Gated => {
            if let Err(e) = proof.validate_for_merge() {
                return finalize_until_ready_blocker(
                    goal_id,
                    steps,
                    UntilReadyBlocker::policy(format!(
                        "gated merge blocked: proof validation failed: {e}"
                    )),
                )
                .await;
            }
            if pr_url.is_none() {
                return finalize_until_ready_blocker(
                    goal_id,
                    steps,
                    UntilReadyBlocker::policy(
                        "gated merge blocked: no PR URL available for merge".to_string(),
                    ),
                )
                .await;
            }
            if let Some(ref url) = pr_url {
                let check_timeout = std::time::Duration::from_secs(120);
                let poll_interval = std::time::Duration::from_secs(10);
                let mut checks_pass = false;
                for _ in 0..36 {
                    match poll_github_pr_checks(url, check_timeout).await {
                        Ok(true) => {
                            checks_pass = true;
                            break;
                        }
                        Ok(false) => {
                            tokio::time::sleep(poll_interval).await;
                            continue;
                        }
                        Err(e) => {
                            return finalize_until_ready_blocker(
                                goal_id,
                                steps,
                                UntilReadyBlocker::policy(format!(
                                    "gated merge blocked: required CI check failed: {e}"
                                )),
                            )
                            .await;
                        }
                    }
                }
                if !checks_pass {
                    return finalize_until_ready_blocker(
                        goal_id,
                        steps,
                        UntilReadyBlocker::policy(
                            "gated merge blocked: required CI checks did not pass within timeout"
                                .to_string(),
                        ),
                    )
                    .await;
                }
                if let Err(e) = client.merge_pr(url).await {
                    return finalize_until_ready_blocker(
                        goal_id,
                        steps,
                        UntilReadyBlocker::policy(format!(
                            "gated merge blocked: PR merge failed: {e}"
                        )),
                    )
                    .await;
                }
            }

            state.status = GoalStatus::Ready;
            state.phase = GoalPhase::Proof;
            state.completed_at = Some(now);
            state.updated_at = now;
            FileSystemGoalStateStore::new().save(&state).await?;

            proof.status = GoalStatus::Ready;
            proof.readiness =
                "ready: integration and oracle evidence passed, GitHub PR merged after gated checks"
                    .to_string();
            proof.summary = format!(
                "Goal '{}' is proof-backed ready: gates, execution, review, integration evidence passed, and PR was merged after required checks passed.",
                state.normalized_goal
            );
            proof.generated_at = now;
            proof.artifacts = state.artifacts.clone();
            proof.known_gaps.clear();
            proof.human_decisions_required.clear();
            proof.git = crate::runtime::goal::evidence::detect_git_evidence(project_dir)
                .await
                .or(proof.git);
            proof::write_json_artifact(&state.state_dir.join(state::GOAL_PROOF_FILE), &proof)
                .await?;

            steps.push(GoalControllerStep {
                kind: GoalControllerStepKind::Deliver,
                status: GoalStatus::Ready,
                summary: format!(
                    "GitHub PR created and merged under {} policy after gated checks",
                    policy.as_str()
                ),
            });

            cleanup_goal_worktrees(&state, project_dir).await;

            Ok(GoalRunUntilReadyOutcome {
                state,
                proof,
                steps,
                blocker: None,
                policy_evidence_path: None,
            })
        }
    }
}

pub(super) async fn create_integrator_pr(
    state: &state::GoalState,
    slice_branches: &[String],
    integrator_branch: &str,
    base_branch: &str,
    policy: GoalDeliveryPolicy,
) -> Result<(
    crate::runtime::goal::delivery::GoalGithubPrDeliveryOutcome,
    GoalGithubPrCommandClient,
)> {
    let title = format!("[Integrator] {}", state.normalized_goal);
    let body = format!(
        "Integrator PR combining {} slice(s) for goal `{}`.\n\nSlices:\n{}",
        slice_branches.len(),
        state.goal_id,
        slice_branches
            .iter()
            .map(|b| format!("- `{}`", b))
            .collect::<Vec<_>>()
            .join("\n")
    );

    let pr_request = GoalGithubPrRequest {
        title,
        body,
        head_branch: integrator_branch.to_string(),
        base_branch: Some(base_branch.to_string()),
        draft: policy == GoalDeliveryPolicy::DraftPr,
        existing_pr_url: None,
    };

    let mut client = GoalGithubPrCommandClient::default();
    let pr_outcome = match client.create_pr(pr_request).await {
        Ok(mutation) => crate::runtime::goal::delivery::GoalGithubPrDeliveryOutcome {
            policy,
            dry_run: false,
            mutated: true,
            operation: Some(mutation.operation),
            pr_url: mutation.url.clone(),
            reason: format!("GitHub PR {} completed", mutation.operation.as_str()),
        },
        Err(e) => anyhow::bail!("integrator PR creation failed: {e}"),
    };

    Ok((pr_outcome, client))
}