Fix lost auto-create lane / background launch on project switch#607
Fix lost auto-create lane / background launch on project switch#607arul28 wants to merge 1 commit into
Conversation
An in-flight draft launch (auto-create-lane or start-in-background) from the new-chat composer could vanish with no trace when switching projects mid-launch — especially between two remote projects. Two root causes: 1. Job state lived in the per-project renderer store, which is torn down when switching to another remote project (only the active remote surface stays mounted), dropping the in-flight job. Hoist draft-launch job state to the root store so it survives surface teardown and re-surfaces on return. 2. The launch routed its mutating IPC via the mutable global project binding, so a mid-launch switch could create a lane/session in the WRONG project (or throw PROJECT_SWITCHING). The launch now captures its originating binding, aborts before any mutating call if the active project drifts, pins rollback deletes to the originating project, and times out after 90s so a dropped remote connection can't wedge the job in a non-terminal state. Adds preload callPinnedRuntimeAction (optional pin on lanes.delete / agentChat.delete), withDraftLaunchTimeout + constants in draftLaunchJobs.ts, regression tests, and internal docs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
Warning Review limit reached
More reviews will be available in 22 minutes and 4 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (3)
📒 Files selected for processing (6)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@copilot review but do not make fixes |
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
| // Re-check before starting the session: a switch during prepare must not | ||
| // start a session in the now-active project. | ||
| assertLaunchProjectActive(); | ||
| const launched = await withDraftLaunchTimeout( | ||
| kind === "chat" | ||
| ? startDraftChatLaunch(prepared, targetLane, launchBinding) | ||
| : startDraftCliLaunch(prepared, targetLane, mode), | ||
| "Session start", |
There was a problem hiding this comment.
assertLaunchProjectActive() checks the root binding, but the following agentChat.create / pty.create calls still go through unpinned preload APIs that resolve the mutable current project binding later. When the user switches projects immediately after this check, the session or PTY can be created in the newly active project with the old lane id/worktree. The rollback pin only applies after a chat session exists, so the creation itself needs to use the same pinned binding or an atomic checked-and-create path.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/components/chat/AgentChatPane.tsx
Line: 7207-7214
Comment:
**Creation remains unpinned**
`assertLaunchProjectActive()` checks the root binding, but the following `agentChat.create` / `pty.create` calls still go through unpinned preload APIs that resolve the mutable current project binding later. When the user switches projects immediately after this check, the session or PTY can be created in the newly active project with the old lane id/worktree. The rollback pin only applies after a chat session exists, so the creation itself needs to use the same pinned binding or an atomic checked-and-create path.
How can I resolve this? If you propose a fix, please make it concise.| targetLane = await withDraftLaunchTimeout(resolveDraftLaunchLane(snapshot, () => { | ||
| patchDraftLaunchJob(jobId, { status: "creating-lane" }); | ||
| }, (message) => { | ||
| patchDraftLaunchJob(jobId, { warning: message }); | ||
| }, (modelId) => { | ||
| patchDraftLaunchJob(jobId, { namingModelId: modelId }); | ||
| }); | ||
| }, assertLaunchProjectActive), "Lane setup"); |
There was a problem hiding this comment.
withDraftLaunchTimeout only rejects the renderer-side wait; it does not cancel resolveDraftLaunchLane. When lane setup times out while naming or branch discovery is still in flight, the catch path marks the job failed with targetLane === null, but the original promise can later continue into window.ade.lanes.create. That creates an auto lane after the failed job has no cleanup path. The same pattern can let a timed-out session start later create/send a chat session after the job is already failed. Add a stale/abort signal that is checked before each mutation, or avoid timing out steps that can still perform irreversible work.
Artifacts
Repro: focused timeout harness
- Contains supporting evidence from the run (text/javascript; charset=utf-8).
Repro: harness output showing failure before late lane create
- Keeps the command output available without making the summary code-heavy.
Repro: attempted Vitest test for the timeout path
- Contains supporting evidence from the run (text/typescript; charset=utf-8).
Repro: Vitest attempt blocked by local Node toolchain incompatibility
- Keeps the command output available without making the summary code-heavy.
Ran code and verified through T-Rex
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/components/chat/AgentChatPane.tsx
Line: 7189-7195
Comment:
**Timeout leaves work running**
`withDraftLaunchTimeout` only rejects the renderer-side wait; it does not cancel `resolveDraftLaunchLane`. When lane setup times out while naming or branch discovery is still in flight, the catch path marks the job failed with `targetLane === null`, but the original promise can later continue into `window.ade.lanes.create`. That creates an auto lane after the failed job has no cleanup path. The same pattern can let a timed-out session start later create/send a chat session after the job is already failed. Add a stale/abort signal that is checked before each mutation, or avoid timing out steps that can still perform irreversible work.
How can I resolve this? If you propose a fix, please make it concise.
Problem
An in-flight draft launch (auto-create-lane or start in background) from the new-chat composer could vanish with no trace when the user switched projects mid-launch — most reliably between two remote projects. No new lane, no chat, no error: "as if it crashed."
Two root causes:
PROJECT_SWITCHING, with the failure swallowed (the originating pane had unmounted).Fix
useRootAppStore/rootAppStoreApi) so it survives surface teardown and re-surfaces (or auto-opens / shows a Restorable failure) on return.assertLaunchProjectActive) if the active project drifted — no lane/session created in the wrong project.lanes.delete/agentChat.delete) to the originating project via a new additivecallPinnedRuntimeAction, so cleanup never misroutes.withDraftLaunchTimeout) so a dropped remote connection can't wedge a job in a non-terminal state.Tests / docs
draftLaunchJobs.test.ts(timeout helper + prune invariant) and two behavioral regressions inAgentChatPane.test.tsx(drift-abort, pinned rollback).pinis preload-internal, never crosses the sync wire).🤖 Generated with Claude Code
Greptile Summary
Confidence Score: 1/5
The draft-launch changes still have multiple project-binding race paths that can create, fetch, clean up, or restore state in the wrong runtime.
Several affected paths involve irreversible mutations across mutable project bindings, and focused runtime checks confirmed multiple failure modes around timeout continuation, cleanup, branch fetch drift, and remote job scoping.
apps/desktop/src/renderer/components/chat/AgentChatPane.tsx and the draft launch job scoping logic need attention before merging.
What T-Rex did
Comments Outside Diff (3)
apps/desktop/src/renderer/components/chat/AgentChatPane.tsx, line 6605-6611 (link)This cleanup path still calls
agentChat.deletewithout the launch pin. During a draft launch,createSessionForLanecan create the origin-project session, the user can switch projects, and thenorchestration.runCreatecan fail. This unpinned delete resolves against the newly active project, leaving the created lead chat behind in the origin project, or deleting a same-id session in the wrong project. Thread the launch pin intocreateSessionForLaneso this cleanup uses the same pinned delete path.Artifacts
Repro: focused cleanup project switch harness
Repro: harness output with structured call trace
Repro: generated focused Vitest component test
Repro: attempted Vitest execution output
Prompt To Fix With AI
apps/desktop/src/renderer/components/chat/AgentChatPane.tsx, line 6915-6919 (link)The active-project check runs only after these branch calls finish. If the user switches projects after naming resolves but before
fetchNewLaneBaseBranchesruns,window.ade.git.fetchandwindow.ade.git.listBranchesuse the now-active project binding while still passing the old project'sprimaryLane.id. This can fetch/list refs in the wrong project and then create the lane with an incorrect base selection or a swallowed branch-list failure.Artifacts
Repro: focused project drift harness
Repro: harness output with structured API trace
Prompt To Fix With AI
apps/desktop/src/renderer/components/chat/AgentChatPane.tsx, line 2930-2937 (link)Draft launch jobs now live in the root store, but this key only includes
projectRoot. For remote projects,selectActiveProjectRootreturnsprojectBinding.rootPath, so two different remote targets or project IDs with the same path, lane id, surface, and draft kind share the same job list. A ready or failed launch from one remote can appear after switching to another remote and can open or restore a stale session id in the wrong runtime.Artifacts
Repro: focused harness for remote draft launch job scope collision
Repro: harness output showing colliding keys and remote A job visible under remote B
Repro: Vitest test attempted for the same remote draft launch scope collision
Repro: Vitest attempt output showing runner startup blocker before dependency install
Prompt To Fix With AI
Prompt To Fix All With AI
Reviews (1): Last reviewed commit: "Fix lost auto-create lane / background l..." | Re-trigger Greptile