Repository navigation
fix(server): scheduled runs record their real outcome and refuse a stale project-folder workspace - #71
Conversation
…ale project-folder workspace A scheduled run read as succeeded as soon as its launch was accepted, so a run that then failed workspace preparation showed succeeded until (and unless) the outcome follower flipped it, and a server restart lost that follower. Runs now record "started" on dispatch and "succeeded" or "failed" (with the error) once the run ends. Restarts resume following started runs. An unbound task MCP saved to run in its project folder because the folder was not a repository kept running there after `git init` or a clone (#69). The launch now refuses with a clear error, and an MCP update re-derives the workspace. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review Summary: ❌ FailedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Substitute review (Claude Opus 5.5), done in place of the hosted Codex reviews, which are blocked by a usage limit. Head 3f78bf9. Verdict: merge after fixes. The #69 half is sound; the new High 1: a new literal in an RPC contract
High 2: a guard rollback poisons the rows
Medium
Low
Confirmed correct
Tests to add
The integration tests should wait for the final outcome, and the restart test should time out rather than hang. The PR's Compatibility section should be corrected to match the above. The #69 half could be split out and merged on its own. 🤖 Generated with Claude Code |
…stored status The `started` literal broke clients and older builds that decode the four known statuses strictly. Stored and wire statuses are back to the four; an accepted run writes back the status from before it, and an optional `runInProgressSince` (never stored) marks a run still in progress. MCP still reports `started` through its own status schema. A restart finds pending runs again from their message ids. Also: a soft-deleted thread, a missing thread or a removed run records a failed outcome; a recorded missed slot is not overwritten by an older pending run; edits keep the stored creationSource so MCP-derived workspaces stay rechecked; the #69 refusal names the `.git` it found and warns when it is in a parent folder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Substitute re-review (Claude Opus 5.5) of the fixes 3f78bf9..c720472 (the head ffe675e adds only empty CI commits). Verdict: merge after fixing N1. Fixed: High 1, High 2, M3, M4 and L5. The compatibility check passed: the fork's N1 (Medium, blocking): each restart erases missed-slot failures (
Low:
Tests still missing: a second restart after a missed slot, and a "stored status already matches" case. The restart test lost coverage of the 🤖 Generated with Claude Code |
…utcome replaces it - A recorded miss moves last_run_at to now and clears the webhook delivery id, so a restart no longer finds the earlier run again and records its success. - markRunning reads the status it replaces in its own transaction. - A restart skips only a run already recorded as a clean success. - Web hides the previous error while a run is in progress and disables Run now from the displayed status. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… into fix/scheduled-task-status-and-root-recheck
69dad80
into
integration/mcp-events-20261109
Two scheduled-task bugs, fixed together because they share the launch path. Updated after the substitute review: the stored and wire statuses are the four existing ones again.
1. A run no longer reads as succeeded before it has finished
Problem.
runTaskwrotelast_run_status = succeededas soon as the launch was accepted, andrun_scheduled_task_nowreturnedsucceededat that moment too. A run that then failed workspace preparation read as succeeded while it was preparing. On 2026-11-12 the Jarvis inbox heartbeat (17:44 UTC) showed succeeded for 26 minutes before it failed withWorkspace preparation failed during provision worktree: … Failed to resolve the VCS driver. The outcome follower from pingdotgg#34815 lived only in memory, so a restart (every deploy) dropped it. It also returned early in several cases without writing anything.Fix.
Accept. An accepted run writes back the status the task had before the run (
neverfor a first run), together with that status's error. It no longer writessucceeded.In progress. Accepted runs whose outcome is pending are held in memory. Results leaving the service carry an optional
runInProgressSince, which is never stored. Web shows such a task asrunning(scheduledTaskRunDisplayStatus). MCP reportsstartedthrough its ownOrchestratorMcpScheduledTaskRunStatus, sorun_scheduled_task_nowreturnsstarted.Outcome. The follower writes
succeededfor a completed run. Any other terminal status writesfailed, with the root provider failure (for example the preparation error) or a generic reason. The write is guarded bylast_run_at = ? AND last_run_status <> 'running', and also requires the run to still be the task's pending one in memory.Every path ends. These cases now record
failed:deletedAt) thread;ThreadNotFoundorRunNotFoundduring the wait;A steered message is followed into the run it joined; the comparison also accepts the restart continuation id. A run still active after 24 h keeps its previous status.
Restart. At startup each task's latest run is found again by rebuilding its message id from
last_run_atand the trigger (scheduled,manual, or the webhook delivery id).Missed slot. A missed-slot failure recorded while an older run is pending stands; that run's outcome no longer overwrites it.
No migration.
2. #69: a saved project-folder workspace in a folder that became a repository
Problem. MCP stores
{type:"root"}for an unbound task whose folder is not a repository (#40). Aftergit initor a clone there, the task kept running directly in what is now a shared checkout.Fix: fail closed. Before an unbound task launches,
refuseStaleRootWorkspacechecks its project folder withfindGitEntry. The check applies when the task has a root strategy,creationSource: "mcp"(MCP always derives the workspace), and is not in a scratch project. If a.gitentry exists, the run fails with an error naming the.gitthat was found. When it is in a parent folder, the error warns that an update would make a worktree of that parent repository. The way out: an MCPschedule_taskupdate re-derives an unbound MCP root workspace even when the binding does not flip.Edits now keep the stored
creationSource, as mobile already did. So renaming an MCP task in Settings no longer exempts it from the recheck.I chose to fail closed instead of switching to a worktree automatically. Switching at launch needs base-ref resolution, which lives in the MCP layer. It would also start creating per-run branches and worktrees in a folder someone has just cloned or initialised without asking.
Bound tasks are unchanged.
Known limits.
Compatibility
runInProgressSinceis an optional key, and older decoders drop it. Upstream desktop and store mobile clients, and a guard rollback to an older server build, all read these rows unchanged.startedexists only in MCP output, which is encoded for models and not decoded by clients. Themcp-tool-useeval was not run; the only model-facing change is that enum value, and the tool description already says "Success means started, not finished."running.succeededandfailedstay due-eligible, so a run longer than its interval can overlap the next one. That is unchanged from before.Tests
runNowreturns the previous status withrunInProgressSince, then the row records:succeeded;succeeded;failed.starting), so final outcomes are covered at the unit level.vp run check:changedpasses: 89 files, 2313 tests.Model and harness: Claude Opus 5.5 in Claude Code (T3 Code).
🤖 Generated with Claude Code