Skip to content

fix(server): scheduled tasks for No project launch in a scratch folder - #17451

Open
Mnigos wants to merge 1 commit into
pingdotgg:mainfrom
Mnigos:scheduled-task-scratch-project-launches
Open

Mnigos wants to merge 1 commit into
pingdotgg:mainfrom
Mnigos:scheduled-task-scratch-project-launches

Conversation

@Mnigos

@Mnigos Mnigos commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Fixes #17309

Problem

@bzbetty reported that a scheduled task for "No project" fails on start with "Workspace preparation failed" when worktree creation is left enabled.
@Alb11747 reproduced it end to end over MCP: schedule_task stores unbound tasks with a worktree strategy, and the run failed in remoteExists on the Scratch folder before the provider started.
@juliusmarminge traced it on main and asked for a server-side fix that coerces worktree strategies on Scratch to root both on upsert and at launch, so existing tasks and MCP-created tasks stop failing.

Scratch ("No project") is a plain folder, not a Git repository. Only root launches get a per-thread Scratch folder; a worktree launch always ran git.createWorktree against it and failed.

Change

  • Launch: ThreadLaunchService.launch treats a worktree request on Scratch as root, once, up front. A root request allocates a per-thread Scratch folder, and the launch persists that folder on the run as existing_worktree, so preparation and replays of the launch use it. Tasks already stored with a worktree strategy now run.
  • Upsert: ScheduledTaskService.upsert stores a Scratch task's worktree strategy as root. The web editor and MCP schedule_task / update_scheduled_task both save through it.
  • Both ask a new ManagedProjectFolders.isScratchProject(projectId). It reuses the existing Scratch root check that folderForThread already relied on.

Coercion rather than rejection: on Scratch, a root request allocates a per-thread Scratch folder, which is what a worktree was meant to give. Rejecting would only push the same fix onto the user or agent, and no existing validation error covers this case.

Relation to open PRs:

Verification

Gate Result
Gate 1, failing test on base (43f8a8de17) 3 new tests fail; the stored-task run settles as failed, and a probe showed Workspace preparation failed during provision worktree: Failed to resolve the VCS driver for this Git command.
Tests: ThreadLaunchService.test.ts, ManagedProjectFolders.test.ts, src/scheduledTasks/*, Scheduler.integration.test.ts, ClaudeAutomaticDelivery.integration.test.ts 11 files, 128 tests pass
vp run typecheck (apps/server) exit 0, no error TS / warning TS
fmt / lint on changed files clean (one pre-existing lint warning in ThreadLaunchService.test.ts, on a line this PR does not touch)
Test case Base This branch
Launch with worktree on Scratch is released (starting) in its own Scratch folder, stored as existing_worktree, no createWorktree Fails: thread has no folder; run fails in workspace preparation Passes
Launch with worktree on a Git project completes worktree creation and is released with its worktree strategy Passes Passes
Upsert of a Scratch task with worktree is stored as root Fails: stored as worktree Passes
Upsert of a Git-project task keeps worktree Passes Passes
Existing Scratch task stored with worktree runs (runNow), is released in its own Scratch folder, stored as existing_worktree Fails: run settles as failed in workspace preparation Passes
isScratchProject is true for Scratch, false for other projects and when Scratch is unavailable n/a (new) Passes

This is a server-only change with no UI, so there are no screenshots.

The tests mock Git to fail on the Scratch root with the same GitCommandError the real path raises ("Failed to resolve the VCS driver for this Git command."), and to succeed on the Git project. They wait on the run's release or failure event, with no polling.

Limitations / not checked:

  • No live scheduler run against a real Scratch folder. The scheduled-task path was verified through the service with the real launch pipeline and a mocked Git layer.
  • Retrying a run whose preparation already failed before this fix (retryPreparation) still reuses its stored worktree strategy and fails again. Running the task again creates a corrected launch.
  • Ordinary projects whose folder is not a Git repository are out of scope. Julius's comment also covers that broader case; it needs repository detection and its own fallback, so this change handles Scratch only.

Implemented with Claude Opus 5.5, verified with GPT-6 Astra, coordinated by Claude Fable 5.1 in Claude Code.

Scratch ("No project") is a plain folder, not a Git repository, so a
scheduled task saved with "Create a new worktree" (the editor default, and
what MCP schedule_task stores for unbound tasks) failed every run with
"Workspace preparation failed".

ThreadLaunchService.launch now treats a worktree request on Scratch as a
root launch, up front, so the per-thread Scratch folder, preparation and
retries all see root. ScheduledTaskService.upsert, which both the web
editor and MCP go through, stores such tasks as root. Both ask the new
ManagedProjectFolders.isScratchProject.
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Oct 9, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 8ba0963

Macroscope's review found this PR approvable — This is a narrowly scoped server bug fix for scheduled and direct launches targeting the non-Git Scratch project. It preserves Git-project worktrees, adds coverage for legacy and new task paths, and does not alter schemas, product defaults, deployment, or static-analysis configuration.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 9, 2026

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3d9d9ee6-1efc-4bdc-833e-6f82817e7b7e

📥 Commits

Reviewing files that changed from the base of the PR and between 43f8a8d and 8ba0963.


📒 Files selected for processing (11)
  • apps/server/src/orchestration-v2/ClaudeAutomaticDelivery.integration.test.ts
  • apps/server/src/orchestration-v2/ThreadLaunchService.test.ts
  • apps/server/src/orchestration-v2/ThreadLaunchService.ts
  • apps/server/src/orchestration-v2/runtimeLayer.ts
  • apps/server/src/project/ManagedProjectFolders.test.ts
  • apps/server/src/project/ManagedProjectFolders.ts
  • apps/server/src/scheduledTasks/ScheduledTaskService.schedule.test.ts
  • apps/server/src/scheduledTasks/ScheduledTaskService.test.ts
  • apps/server/src/scheduledTasks/ScheduledTaskService.ts
  • apps/server/src/scheduledTasks/ScheduledTaskService.webhook.test.ts
  • apps/server/src/scheduling/Scheduler.integration.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 4 remain after this review.



📝 Walkthrough

Walkthrough

The managed-folder service now identifies Scratch projects. Thread launches and scheduled-task upserts convert requested worktree strategies to root strategies for Scratch projects. Tests cover Scratch and Git project behavior and provide the added service dependency.

Changes

Scratch workspace handling

Layer / File(s) Summary
Identify Scratch projects
apps/server/src/project/ManagedProjectFolders.ts, apps/server/src/project/ManagedProjectFolders.test.ts
ManagedProjectFolders exposes isScratchProject. It returns false when Scratch is unavailable and otherwise compares the project’s resolved workspace root with the Scratch root. Tests check Scratch and non-Scratch IDs.
Handle Scratch launches as root workspaces
apps/server/src/orchestration-v2/ThreadLaunchService.ts, apps/server/src/orchestration-v2/ThreadLaunchService.test.ts
ThreadLaunchService.launch converts a Scratch worktree request to a root request. Tests check managed-folder use for Scratch and worktree creation for a Git project.
Normalize scheduled-task workspace strategy
apps/server/src/scheduledTasks/ScheduledTaskService.ts, apps/server/src/scheduledTasks/*test.ts, apps/server/src/scheduling/Scheduler.integration.test.ts, apps/server/src/orchestration-v2/runtimeLayer.ts, apps/server/src/orchestration-v2/ClaudeAutomaticDelivery.integration.test.ts
Scheduled-task upserts store root for Scratch projects that request worktree and preserve other strategies. The service wiring and test layers provide ManagedProjectFolders. Tests also cover execution of a stored Scratch task with worktree strategy.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Low

Suggested reviewers: juliusmarminge


Merge Risk

Merge Risk: ⚪ Minimal · up to 8ba09

Scratch scheduled tasks are handled as root-workspace launches, with no actionable merge-blocking risk identified. The change is ready for normal checks and merge.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 8ba09

Scratch tasks now use the existing per-thread folder behavior without changing their configured execution permissions. No introduced security weakness was established. Older failed-run recovery and interruption behavior have limitations, and broader deployment and permission boundaries were not fully established.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — Previously broken Scratch worktree tasks can now reach setup and provider execution through the already-supported root path. They retain the task's configured runtimeMode and execution identity. Per-thread directory separation does not itself establish a process sandbox or restrict downstream credential access.

Trust Boundaries and Controls

  • observed — For webhook-triggered tasks, attacker-supplied request content reaches prompt rendering only after task-token verification and, when configured, signature verification. These controls remain outside the changed strategy normalization. Launch also retains project lookup and clone-state rejection before thread creation.

Resilience and Maintainability Implications

  • observed — Preparation is reserved per command and its reservation is released on completion or failure. Preparation errors and interruptions attempt to persist a failed run. Scratch directories follow the existing root lifecycle rather than the Git-created-worktree cancellation cleanup branch.



🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description check Passed The description covers the problem, implementation, scope, linked issue context, verification results, limitations, and agent details. It provides sufficient evidence for the server-side fix, although…
Title check Passed The title is concise, uses the conventional commit format, and clearly identifies the main change: fixing scheduled tasks for No project in a Scratch folder.
Linked Issues check Passed The directly linked issue is #17309. The PR addresses the reported Scratch ("No project") failure. ThreadLaunchService.launch converts a Scratch worktree request to root, so the launch uses a pe…
Out of Scope Changes check Passed The changed production files support #17309. ManagedProjectFolders.isScratchProject supplies the shared Scratch check, and runtimeLayer supplies the new dependency. The changed tests update servic…


✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR


  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: "workspace preparation failed" on scheduled task for "no project"

1 participant