diff options
Diffstat (limited to 'makima/src/server/handlers/mesh_supervisor.rs')
| -rw-r--r-- | makima/src/server/handlers/mesh_supervisor.rs | 306 |
1 files changed, 4 insertions, 302 deletions
diff --git a/makima/src/server/handlers/mesh_supervisor.rs b/makima/src/server/handlers/mesh_supervisor.rs index a29b666..43388a8 100644 --- a/makima/src/server/handlers/mesh_supervisor.rs +++ b/makima/src/server/handlers/mesh_supervisor.rs @@ -37,10 +37,6 @@ pub struct SpawnTaskRequest { pub checkpoint_sha: Option<String>, /// Repository URL for the task (optional - if not provided, will be looked up from contract). pub repository_url: Option<String>, - /// If true, create a separate worktree for the task (requires merge after). - /// If false (default), the task shares the supervisor's worktree. - #[serde(default)] - pub use_own_worktree: bool, } /// Request to wait for task completion. @@ -610,8 +606,8 @@ pub async fn spawn_task( } // Create task request - // Share supervisor's worktree by default; separate worktree only when explicitly requested - let supervisor_worktree_task_id = if request.use_own_worktree { None } else { Some(supervisor_id) }; + // All tasks share the supervisor's worktree + let supervisor_worktree_task_id = Some(supervisor_id); let create_req = CreateTaskRequest { name: request.name.clone(), @@ -621,7 +617,6 @@ pub async fn spawn_task( contract_id: Some(request.contract_id), parent_task_id: request.parent_task_id, is_supervisor: false, - is_red_team: false, checkpoint_sha: request.checkpoint_sha.clone(), merge_mode: Some("manual".to_string()), priority: 0, @@ -733,8 +728,8 @@ pub async fn spawn_task( patch_base_sha: None, local_only: contract.local_only, auto_merge_local: contract.auto_merge_local, - // Share supervisor's worktree by default; separate worktree only when explicitly requested - supervisor_worktree_task_id: if request.use_own_worktree { None } else { Some(supervisor_id) }, + // All tasks share the supervisor's worktree + supervisor_worktree_task_id: Some(supervisor_id), }; if let Err(e) = state.send_daemon_command(daemon.id, cmd).await { @@ -762,66 +757,6 @@ pub async fn spawn_task( updated_by: "supervisor".to_string(), }); - // Check if we should spawn a red team task - // Conditions: - // 1. This is not a supervisor task - // 2. This is not already a red team task - // 3. Contract has red_team_enabled = true - // 4. No red team task exists for this contract yet - if !updated_task.is_supervisor && !updated_task.is_red_team && contract.red_team_enabled { - if let Some(contract_id) = updated_task.contract_id { - // Check if a red team task already exists - match repository::get_red_team_task_for_contract(pool, contract_id).await { - Ok(None) => { - // No red team task exists, spawn one - tracing::info!( - contract_id = %contract_id, - work_task_id = %updated_task.id, - "Spawning red team task for contract (first work task started)" - ); - match spawn_red_team_task( - pool, - &state, - contract_id, - owner_id, - &contract.name, - &contract.phase, - contract.red_team_prompt.as_deref(), - ).await { - Ok(red_team_task) => { - tracing::info!( - contract_id = %contract_id, - red_team_task_id = %red_team_task.id, - "Red team task spawned successfully" - ); - } - Err(e) => { - // Log error but don't fail the work task spawn - tracing::error!( - contract_id = %contract_id, - error = %e, - "Failed to spawn red team task" - ); - } - } - } - Ok(Some(existing)) => { - tracing::debug!( - contract_id = %contract_id, - red_team_task_id = %existing.id, - "Red team task already exists for contract" - ); - } - Err(e) => { - tracing::error!( - contract_id = %contract_id, - error = %e, - "Error checking for existing red team task" - ); - } - } - } - } } break; } @@ -2584,239 +2519,6 @@ pub async fn rewind_conversation( } // ============================================================================= -// Red Team Task Spawning -// ============================================================================= - -/// Generate the system prompt/plan for a red team task. -/// -/// This creates detailed instructions for the red team monitor, including -/// what to look for, severity levels, and how to report issues. -pub fn generate_red_team_plan( - contract_name: &str, - contract_phase: &str, - custom_prompt: Option<&str>, -) -> String { - let custom_criteria = if let Some(prompt) = custom_prompt { - format!( - r#" - -## Custom Review Criteria - -The contract owner has specified additional review criteria: -{} -"#, - prompt - ) - } else { - String::new() - }; - - format!( - r#"# Red Team Monitor - -You are an adversarial quality reviewer for a software development contract. Your role is to monitor work task outputs in real-time and flag potential issues BEFORE they compound into larger problems. - -## Your Mission - -Monitor all task outputs and verify: -1. **Plan Adherence**: Are tasks following the implementation plan? -2. **Code Quality**: Does the code meet repository standards? -3. **Contract Requirements**: Does the implementation match the specification? -4. **Best Practices**: Are there obvious anti-patterns or issues? - -## Access Available - -You have read-only access to: -- Task outputs (streamed in real-time) -- Task diffs (code changes) -- Contract specifications and plan documents -- Repository configuration files (CONTRIBUTING.md, linting configs, etc.) - -## How to Monitor - -1. **Subscribe to task outputs**: You'll receive outputs from all work tasks -2. **Analyze code changes**: Request diffs for completed tasks -3. **Cross-reference**: Compare outputs against the plan and specifications -4. **Report issues**: Use `makima red-team notify` when you detect problems - -## When to Notify - -NOTIFY the supervisor when you observe: -- **Critical**: Security vulnerabilities, data loss risks, breaking changes -- **High**: Significant deviations from the plan, major code quality issues -- **Medium**: Missing tests, suboptimal implementations, minor standard violations -- **Low**: Style inconsistencies, documentation gaps (use sparingly) - -## What NOT to Do - -- Do NOT nitpick minor style issues (that's what linters are for) -- Do NOT block progress for trivial concerns -- Do NOT write code or make changes yourself -- Do NOT notify for things that are already in progress and being addressed -- Do NOT create duplicate notifications for the same issue - -## Notification Format - -When notifying, always include: -1. A clear, concise description of the issue -2. The severity level (critical/high/medium/low) -3. The related task ID if applicable -4. The specific file or code location if known -5. Why this matters (reference to plan, spec, or standards) - -## Example Notification - -``` -makima red-team notify "Task is implementing authentication with plaintext password storage, which contradicts the security requirements in the specification document" \ - --severity critical \ - --task <task_id> \ - --file "src/auth/user.rs" \ - --context "Specification section 3.2 requires bcrypt hashing for all passwords" -``` -{} -## Contract Context - -Contract: {} -Phase: {} - -Focus your monitoring on outputs that relate to the active work tasks. Prioritize issues that could affect the success of the contract or introduce technical debt. -"#, - custom_criteria, contract_name, contract_phase - ) -} - -/// Spawn a red team task for a contract. -/// -/// This creates a red team monitor task that will observe work task outputs -/// and can notify the supervisor about potential issues. -pub async fn spawn_red_team_task( - pool: &sqlx::PgPool, - state: &SharedState, - contract_id: Uuid, - owner_id: Uuid, - contract_name: &str, - contract_phase: &str, - red_team_prompt: Option<&str>, -) -> Result<Task, String> { - // Generate the red team plan/prompt - let plan = generate_red_team_plan(contract_name, contract_phase, red_team_prompt); - - // Create task request - let create_req = CreateTaskRequest { - name: "Red Team Monitor".to_string(), - description: Some("Adversarial review task monitoring work task outputs".to_string()), - plan, - contract_id: Some(contract_id), - parent_task_id: None, - is_supervisor: false, - is_red_team: true, - priority: 0, - repository_url: None, // Red team doesn't need a repo - base_branch: None, - target_branch: None, - merge_mode: None, - target_repo_path: None, - completion_action: None, - continue_from_task_id: None, - copy_files: None, - checkpoint_sha: None, - branched_from_task_id: None, - conversation_history: None, - supervisor_worktree_task_id: None, // Red team uses its own working area - }; - - // Create task in DB - let task = repository::create_task_for_owner(pool, owner_id, create_req) - .await - .map_err(|e| format!("Failed to create red team task: {}", e))?; - - tracing::info!( - contract_id = %contract_id, - red_team_task_id = %task.id, - "Created red team task for contract" - ); - - // Find a daemon to run the red team task - for entry in state.daemon_connections.iter() { - let daemon = entry.value(); - if daemon.owner_id == owner_id { - // Update task with daemon assignment - let update_req = UpdateTaskRequest { - status: Some("starting".to_string()), - daemon_id: Some(daemon.id), - version: Some(task.version), - ..Default::default() - }; - - match repository::update_task_for_owner(pool, task.id, owner_id, update_req).await { - Ok(Some(updated_task)) => { - // Send spawn command to daemon - let cmd = DaemonCommand::SpawnTask { - task_id: updated_task.id, - task_name: updated_task.name.clone(), - plan: updated_task.plan.clone(), - repo_url: None, // Red team doesn't need a repo - base_branch: None, - target_branch: None, - parent_task_id: None, - depth: 0, - is_orchestrator: false, - target_repo_path: None, - completion_action: None, - continue_from_task_id: None, - copy_files: None, - contract_id: Some(contract_id), - is_supervisor: false, - autonomous_loop: false, - resume_session: false, - conversation_history: None, - patch_data: None, - patch_base_sha: None, - local_only: true, // Red team is always local-only - auto_merge_local: false, // Red team doesn't auto-merge - supervisor_worktree_task_id: None, - }; - - if let Err(e) = state.send_daemon_command(daemon.id, cmd).await { - tracing::warn!( - error = %e, - daemon_id = %daemon.id, - red_team_task_id = %task.id, - "Failed to send red team spawn command" - ); - // Rollback - let rollback_req = UpdateTaskRequest { - status: Some("pending".to_string()), - clear_daemon_id: true, - ..Default::default() - }; - let _ = repository::update_task_for_owner(pool, task.id, owner_id, rollback_req).await; - } else { - tracing::info!( - red_team_task_id = %task.id, - daemon_id = %daemon.id, - "Red team task spawn command sent" - ); - return Ok(updated_task); - } - } - Ok(None) => { - tracing::warn!(red_team_task_id = %task.id, "Red team task not found when updating daemon_id"); - } - Err(e) => { - tracing::error!(red_team_task_id = %task.id, error = %e, "Failed to update red team task with daemon_id"); - } - } - break; - } - } - - // Return the task even if we couldn't start it on a daemon - // It will remain pending and can be started later - Ok(task) -} - -// ============================================================================= // Supervisor State Persistence Helpers (Task 3.3) // ============================================================================= |
