diff --git a/apps/backend/agents/coder.py b/apps/backend/agents/coder.py index b498ff86f3..e23c94d703 100644 --- a/apps/backend/agents/coder.py +++ b/apps/backend/agents/coder.py @@ -190,6 +190,24 @@ def _validate_and_fix_implementation_plan() -> tuple[bool, list[str]]: print(f"Continuing build: {highlight(spec_dir.name)}") print_progress_summary(spec_dir) + # Fix for #509: Transition from human_review to in_progress after approval + # When continuing a build that was approved, ensure we transition out of human_review + plan = load_implementation_plan(spec_dir) + if plan and plan.status == "human_review" and plan.planStatus == "review": + from review.state import ReviewState + review_state = ReviewState.load(spec_dir) + if review_state.is_approval_valid(spec_dir): + # User approved the plan - transition to in_progress now that execution begins + plan.status = "in_progress" + plan.planStatus = "in_progress" + plan_file = spec_dir / "implementation_plan.json" + plan.save(plan_file) + print_status("Transitioned from human_review to in_progress after approval", "success") + else: + # Plan changed after approval or not approved - stay in human_review + print_status("Plan requires re-approval before execution can continue", "warning") + return + # Check if already complete if is_build_complete(spec_dir): print_build_complete_banner(spec_dir) diff --git a/apps/backend/implementation_plan/plan.py b/apps/backend/implementation_plan/plan.py index 01518f245b..ace67214fd 100644 --- a/apps/backend/implementation_plan/plan.py +++ b/apps/backend/implementation_plan/plan.py @@ -167,7 +167,17 @@ def update_status_from_subtasks(self): all_subtasks = [s for p in self.phases for s in p.subtasks] if not all_subtasks: - # No subtasks yet - stay in backlog/pending + # No subtasks yet - check if this is a failed planning state + # Fix for #1149: If status is human_review but no phases/subtasks exist, + # planning crashed - reset to backlog instead of preserving invalid state + if self.status == "human_review" and not self.phases: + # Planning failed - don't show as human_review with Resume button + self.status = "backlog" + self.planStatus = "pending" + self.recoveryNote = "Planning phase failed - no implementation plan created" + return + + # Normal case: No subtasks yet - stay in backlog/pending if not self.status: self.status = "backlog" if not self.planStatus: diff --git a/apps/frontend/src/main/ipc-handlers/agent-events-handlers.ts b/apps/frontend/src/main/ipc-handlers/agent-events-handlers.ts index c20fb79dad..7add23404f 100644 --- a/apps/frontend/src/main/ipc-handlers/agent-events-handlers.ts +++ b/apps/frontend/src/main/ipc-handlers/agent-events-handlers.ts @@ -282,15 +282,35 @@ export function registerAgenteventsHandlers( } } else { notificationService.notifyTaskFailed(taskTitle, project.id, taskId); - persistStatus("human_review"); - // Include projectId for multi-project filtering (issue #723) - safeSendToRenderer( - getMainWindow, - IPC_CHANNELS.TASK_STATUS_CHANGE, - taskId, - "human_review" as TaskStatus, - projectId - ); + // FIX (ACS-71, #1149): Only set human_review if subtasks exist + // If planning crashed before creating phases, don't set human_review + // This prevents tasks from getting stuck in "needs resume" state + const hasSubtasksOnFail = task.subtasks && task.subtasks.length > 0; + if (hasSubtasksOnFail) { + persistStatus("human_review"); + // Include projectId for multi-project filtering (issue #723) + safeSendToRenderer( + getMainWindow, + IPC_CHANNELS.TASK_STATUS_CHANGE, + taskId, + "human_review" as TaskStatus, + projectId + ); + } else { + // No subtasks - planning failed before creating phases + // Keep task in backlog so user can retry + console.warn( + `[Task ${taskId}] Process failed but no subtasks created - resetting to backlog` + ); + persistStatus("backlog"); + safeSendToRenderer( + getMainWindow, + IPC_CHANNELS.TASK_STATUS_CHANGE, + taskId, + "backlog" as TaskStatus, + projectId + ); + } } } } catch (error) {