Files
kandev/docs/plans/task-launch-error-consolidation/plan.md
T
2026-09-07 11:19:09 +01:00

6.6 KiB

created, status, requirements, system_design, legacy_specs
created status requirements system_design legacy_specs
2026-09-05 completed
REQ-TASKS-TASK-LAUNCH-FAILURE-RECOVERY-001
REQ-TASKS-REMOTE-CONTRIBUTION-TASKS-001
../../specs/tasks/system-design/task-launch-failure-recovery.md
../../specs/tasks/system-design/remote-contribution-tasks.md

Implementation Plan: Task Launch Error Consolidation

Overview

The change first isolates pull-request refs from reused local branch names. Then it makes recovery actions category-specific. The final work order gives one error card ownership of the desktop and phone presentation.

Confirmed root cause

PR #3408 uses feature/unit-7-reject-leg-wa-waj at a76c5d8de780b0b857af8195eab4772bb1a5839b. The shared clone still has the same local branch from PR #3294 at f825122f586978ed5e33fe48d61e401a610318e2.

Neither commit contains the other. The required fetch tried to update the local branch directly. Git rejected the update as non-fast-forward, and preparation stopped before the agent started.

The backend stored one typed launch error. The frontend also derived a previous agent error, a failed preparation row, an empty-turn warning, a generic failed status, and a stopped-session recovery banner from the same failed start.

Scope

In scope

  • Preserve a reused local branch and prepare the exact pull-request head.
  • Classify checkout preparation separately from base-branch errors.
  • Offer only category-valid recovery actions.
  • Render one matching launch-error card on desktop and phone.
  • Keep bounded technical details in one disclosure.
  • Prove the error and recovery flows with unit and Playwright tests.

Out of scope

  • Reconcile provider and local history after an agent starts.
  • Change generic runtime-error recovery after successful agent startup.
  • Add new provider-specific branch pickers.
  • Change pull, push, merge, rebase, or force-push policy.

Technical approach

Pull-request ref isolation

Update apps/backend/internal/worktree/manager_lifecycle.go to fetch a pull-request head into the Kandev-owned refs/kandev/pull/<N>/head ref. Verify that full ref before worktree creation. If a same-named local branch has unrelated history, create a unique task branch from the verified ref using a task-owned suffix and bounded collision retries. Set a source-branch upstream only when its commit matches the verified PR start point.

Keep the named local branch unchanged. Continue to use the existing Git admission, timeout, and non-interactive environment.

Failure category and recovery

Add workspace_checkout_failed and retry_launch to apps/backend/internal/task/models/launch_errors.go. Preserve unknown-value filtering in the task-status projection.

Update apps/backend/internal/orchestrator/executor/launch_failure.go so the failure category selects the action list. A repository row must not add branch actions to a generic error.

Extend task.launch.recover in apps/backend/internal/orchestrator/task_launch_recovery.go and its WebSocket handler. retry_launch must validate the current stamp and relaunch without a base-branch write.

Single frontend owner

Derive one ownership flag in apps/web/components/task/task-chat-panel.tsx from the active error, session identity, and stamp. Pass this flag to the transcript and composer boundaries.

Update TaskLaunchErrorEntry with category-specific titles, cause text, a no-change statement, and a technical-details disclosure. Keep action state and WebSocket requests in the existing component.

When the flag is active, suppress the matching last-agent-error notice, preparation row, empty-turn notice, failed-agent status, stopped-session banner, and focused-task toast. Do not suppress unrelated historical or runtime errors.

Mobile contract

Desktop and phone use the task Chat surface. The phone card stacks full-width actions. All touch actions have at least a 44-pixel hit area.

The task transcript owns scrolling. The details disclosure wraps its bounded content without an inner scroll region. Base-branch selection keeps the existing MobilePickerSheet behavior.

Tests

  • apps/backend/internal/worktree/manager_pr_head_collision_test.go covers two pull requests that reuse one branch name with divergent histories.
  • apps/backend/internal/orchestrator/executor/executor_launch_failure_classification_test.go covers category-specific actions.
  • apps/backend/internal/orchestrator/task_launch_recovery_test.go covers authorized, stale, and failed retry_launch requests.
  • Frontend tests cover one-owner arbitration, the details disclosure, action payloads, launch-error ownership in the composer, recovery-state reset, and preservation of unrelated runtime errors.

E2E tests

  • apps/web/e2e/tests/task/launch-failure-recovery.spec.ts proves one desktop error card, one retry action, and no matching duplicate surfaces.
  • apps/web/e2e/tests/task/mobile-launch-failure-recovery.spec.ts proves the same result on mobile-chrome, 44-pixel actions, and no horizontal overflow.

These tests map to AC-TASKS-TASK-LAUNCH-FAILURE-RECOVERY-001.2, AC-TASKS-TASK-LAUNCH-FAILURE-RECOVERY-001.7, and AC-TASKS-TASK-LAUNCH-FAILURE-RECOVERY-001.8.

Work orders

Verification results

  • Backend focused race coverage passed: 1,212 tests across worktree, task models, status summary, and executor packages, plus 11 targeted task-launch recovery tests.
  • Frontend focused coverage passed: 10 Vitest files and 152 tests.
  • Review-remediation frontend coverage passed: 7 Vitest files and 75 tests, including task-wide launch-error visibility, composer ownership, and recovery-state reset.
  • pnpm run typecheck, pnpm run lint, pnpm run i18n:check, and pnpm run i18n:ratchet passed.
  • Managed Playwright coverage passed: desktop launch-failure recovery 3/3 and mobile launch-failure recovery 2/2.
  • The broader orchestrator package run was attempted but exceeded its timeout in an existing SQLite/concurrency test; the focused race and recovery suites passed independently.

Risks

  • A ref-selection error can discard local-only commits. Tests must prove that the existing branch remains unchanged.
  • Error events can arrive in a different order from task-status updates. The owner logic must converge after either event order.
  • Old persisted generic errors can contain branch actions. Projection and UI normalization must not show actions that conflict with the current category.