Skip to content

Fix glitchy fork/brief handoff: seeding lag, phantom duplicate session, false 30s timeout (ADE-122)#858

Merged
arul28 merged 3 commits into
mainfrom
ade-122-fork-handoff-is-glitchy-app-lags-out-spawns-a-duplicate-session-that-vanishes-and-brief-handoff-throws-a-false-3000ms-timeout-before-silently-succeeding
Jul 18, 2026
Merged

Fix glitchy fork/brief handoff: seeding lag, phantom duplicate session, false 30s timeout (ADE-122)#858
arul28 merged 3 commits into
mainfrom
ade-122-fork-handoff-is-glitchy-app-lags-out-spawns-a-duplicate-session-that-vanishes-and-brief-handoff-throws-a-false-3000ms-timeout-before-silently-succeeding

Conversation

@arul28

@arul28 arul28 commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Fixes ADE-122 — fork/brief chat handoff was glitchy: the app lagged out during a fork, a duplicate session appeared and then vanished, and a brief handoff reported a timeout and then silently succeeded ~a minute later.

Root causes and fixes

1. App lag during fork handoffappendImportedChatEvents seeded the entire source transcript synchronously on the runtime event loop, live-publishing every historical envelope to all IPC/sync subscribers and forcing a sync file flush per seeded user message (×2 transcript files). Now async + chunked (250-envelope chunks with setImmediate yields), one append per file per chunk, one bulk history-ring update (was O(n²)), and seeded envelopes are no longer live-published — readers load them via the history/transcript APIs (renderer, iOS, and search all back-fill; verified).

2. Duplicate session that vanishes — the sidebar handoff placeholder card and the real created session row were both visible from createSession until the handoff RPC settled; the "vanish" was the placeholder being removed. SessionListPane now hides a placeholder as soon as a matching real session row is visible (handoffJobLikelyMaterialized: same lane + tool type, started at/after the job began). Placeholder copy is mode-aware and honest (fork: "Forking chat history...", brief: "Summarizing chat & creating handoff...") instead of fake timed stage hops; the placeholder re-homes to the brief's target lane; the handoff callback guards re-entry.

3. False "3000" timeout on brief handoffchat.handoffSession fell into the 30s default daemon-RPC timeout ("timed out ... (30000ms)", misread as 3000 seconds) while the daemon-side handoff (45s-bounded AI brief + session creation + first-message dispatch) kept running to a late "surprise" success. Timeout never cancelled the operation. Now handoffSession/prepareCrossMachineHandoff carry 120s daemon action timeouts and 150s IPC timeouts on the direct, local-runtime, and remote-runtime paths, and a genuine transport timeout surfaces as honest "still finishing in the background" copy plus delayed session-list refreshes so a late success reconciles as the expected new chat. The detector matches only the two transport wrapper shapes so real daemon-side failures still surface as errors.

Tests

Regression test per defect: seeded-history-not-live-published (agentChatService), 120s daemon action timeout (localRuntimeConnectionPool), 150s IPC timeouts across all three paths (ipcTimeouts), placeholder materialization dedupe (handoffLaunchJobs — new colocated suite), placeholder-hides-on-real-row (SessionListPane).

Full agentChatService suite 672/674 — the 2 failures are pre-existing cron tests that fail identically without this branch. Docs updated (chat/README.md, composer-and-ui.md). Parity verified: no iOS/CLI/TUI changes required (no shared types touched).

🤖 Generated with Claude Code

Greptile Summary

This PR fixes the glitchy chat handoff flow reported in ADE-122. The main changes are:

  • Fork/import history seeding now writes historical envelopes to storage without live-publishing them.
  • Imported chat events are chunked, flushed in batches, and bulk-recorded in history to reduce runtime stalls.
  • Direct IPC, local runtime, and remote runtime handoff calls now use longer timeouts.
  • Renderer handoff placeholders use simpler status labels and move to the selected target lane.
  • Session list placeholders are hidden once a matching real session row appears.
  • Regression tests cover fork seeding, timeout handling, placeholder materialization, and status labels.

Confidence Score: 5/5

Safe to merge with low risk.

The changes are focused on the handoff path and include tests for the lag, duplicate placeholder, and timeout behaviors.

No files require special attention.

T-Rex T-Rex Logs

What T-Rex did

  • Ran the ADE-122 regression suite in narrow focus with verbose Vitest output and confirmed the focused run completed with EXIT_CODE: 0.
  • Reviewed the ADE-122 agent-chat run and confirmed the final summary shows failures in the chat service despite the narrow suite passing; EXIT_CODE: 1 with 3 failed and 671 passed (674 total).

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
apps/desktop/src/main/services/chat/agentChatService.ts Changes imported chat event seeding to chunk, defer flushes, bulk-update history, and avoid live event publication.
apps/desktop/src/main/services/ipc/ipcTimeouts.ts Maps chat handoff runtime actions to extended IPC timeouts and extends direct handoff channels.
apps/desktop/src/main/services/localRuntime/localRuntimeConnectionPool.ts Extends local runtime action timeouts for handoff and cross-machine handoff preparation.
apps/desktop/src/renderer/components/chat/AgentChatPane.tsx Simplifies handoff placeholder status, prevents concurrent handoffs, re-homes placeholders to target lanes, and handles transport timeouts as background completion.
apps/desktop/src/renderer/components/terminals/SessionListPane.tsx Filters handoff launch placeholders once a matching real session exists.
apps/desktop/src/renderer/lib/handoffLaunchJobs.ts Reduces handoff statuses to brief/fork labels and adds materialization matching for real session rows.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Renderer as AgentChatPane
participant IPC as IPC/Runtime timeout layer
participant Chat as agentChatService
participant Store as Transcript/history storage
participant List as SessionListPane

Renderer->>Renderer: Create handoff launch job placeholder
Renderer->>IPC: handoffSession / prepareCrossMachineHandoff
IPC->>IPC: Apply extended handoff timeout
IPC->>Chat: Run handoff action
Chat->>Store: Seed imported/forked envelopes in chunks
Store-->>Chat: Flush transcript chunks and bulk history update
Note over Chat,Renderer: Seeded historical envelopes are not live-published
Chat-->>Renderer: Return materialized session
Renderer->>List: Refresh sessions
List->>List: Hide placeholder when matching real session is visible
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Renderer as AgentChatPane
participant IPC as IPC/Runtime timeout layer
participant Chat as agentChatService
participant Store as Transcript/history storage
participant List as SessionListPane

Renderer->>Renderer: Create handoff launch job placeholder
Renderer->>IPC: handoffSession / prepareCrossMachineHandoff
IPC->>IPC: Apply extended handoff timeout
IPC->>Chat: Run handoff action
Chat->>Store: Seed imported/forked envelopes in chunks
Store-->>Chat: Flush transcript chunks and bulk history update
Note over Chat,Renderer: Seeded historical envelopes are not live-published
Chat-->>Renderer: Return materialized session
Renderer->>List: Refresh sessions
List->>List: Hide placeholder when matching real session is visible
Loading

Reviews (1): Last reviewed commit: "docs(chat): update composer handoff plac..." | Re-trigger Greptile

arul28 and others added 3 commits July 17, 2026 23:09
…e session, no false timeout (ADE-122)

Three confirmed root causes, one fix each:

1. App lag during fork handoff: appendImportedChatEvents ran synchronously on
   the runtime event loop and live-published every seeded historical envelope
   to all subscribers (IPC + sync), re-streaming the entire source chat. It is
   now async + chunked (event-loop yields between 250-envelope chunks),
   defers transcript flushes to chunk boundaries (one append syscall per file
   per chunk instead of a forced sync flush per seeded user message), bulk-
   updates the history ring once (was O(n^2)), and never live-publishes seeded
   envelopes — readers load them through the history/transcript APIs.

2. Transient duplicate session: the sidebar handoff placeholder card and the
   real created session row were both visible from createSession until the
   handoff RPC settled. SessionListPane now hides a placeholder as soon as a
   matching real session row is visible (handoffJobLikelyMaterialized: same
   lane + tool type, started at/after the job began). Placeholder copy is now
   mode-aware and honest (fork: "Forking chat history...", brief:
   "Summarizing chat & creating handoff...") instead of fake timed stage hops,
   the placeholder re-homes to the brief's target lane, and handoffSession
   guards re-entry while busy.

3. False "3000ms" timeout on brief handoff that later silently succeeded: the
   chat.handoffSession daemon action fell into the 30s default RPC timeout
   ("timed out ... (30000ms)" read as 3000 seconds) while the daemon-side
   handoff (45s-bounded AI brief + session creation + first-message dispatch)
   kept running to a late "surprise" success. handoffSession and
   prepareCrossMachineHandoff now carry 120s daemon action timeouts and 150s
   IPC timeouts on the direct, local-runtime, and remote-runtime paths, and
   the renderer maps a transport timeout to honest copy ("still finishing in
   the background") plus delayed session-list refreshes so a late success
   reconciles as the expected new chat.

Regression tests per defect + docs updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…placeholder statuses

Dual-review synthesis for the ADE-122 fix:
- The transport-timeout detector matched any "timed out after Nms", which
  would relabel genuine daemon-side failures (e.g. Codex request timeouts
  surfacing through first-message dispatch) as "still finishing in the
  background". It now matches only the two transport wrapper shapes
  (registerIpc invoke timeout, RuntimeRpcClient request timeout).
- Removed the now-producerless "creating-chat"/"sending-handoff" placeholder
  statuses (the fake stage timers were their only writer; the store is
  in-memory, so no persisted value can carry them).
- Added a SessionListPane regression test proving the placeholder hides once
  the matching real session row is visible.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…abels

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@linear-code

linear-code Bot commented Jul 18, 2026

Copy link
Copy Markdown

ADE-122

@vercel

vercel Bot commented Jul 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
ade Ignored Ignored Jul 18, 2026 3:29am

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@arul28, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 9 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

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, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 01dcd863-0da2-49d6-8c9c-df124b7df7d5

📥 Commits

Reviewing files that changed from the base of the PR and between fd18074 and 17f1b3c.

⛔ Files ignored due to path filters (2)
  • docs/features/chat/README.md is excluded by !docs/**
  • docs/features/chat/composer-and-ui.md is excluded by !docs/**
📒 Files selected for processing (11)
  • apps/desktop/src/main/services/chat/agentChatService.test.ts
  • apps/desktop/src/main/services/chat/agentChatService.ts
  • apps/desktop/src/main/services/ipc/ipcTimeouts.test.ts
  • apps/desktop/src/main/services/ipc/ipcTimeouts.ts
  • apps/desktop/src/main/services/localRuntime/localRuntimeConnectionPool.test.ts
  • apps/desktop/src/main/services/localRuntime/localRuntimeConnectionPool.ts
  • apps/desktop/src/renderer/components/chat/AgentChatPane.tsx
  • apps/desktop/src/renderer/components/terminals/SessionListPane.test.tsx
  • apps/desktop/src/renderer/components/terminals/SessionListPane.tsx
  • apps/desktop/src/renderer/lib/handoffLaunchJobs.test.ts
  • apps/desktop/src/renderer/lib/handoffLaunchJobs.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ade-122-fork-handoff-is-glitchy-app-lags-out-spawns-a-duplicate-session-that-vanishes-and-brief-handoff-throws-a-false-3000ms-timeout-before-silently-succeeding

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.

❤️ Share

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

@arul28

arul28 commented Jul 18, 2026

Copy link
Copy Markdown
Owner Author

@copilot review but do not make fixes

@arul28
arul28 merged commit dd3b52c into main Jul 18, 2026
35 checks passed
@arul28
arul28 deleted the ade-122-fork-handoff-is-glitchy-app-lags-out-spawns-a-duplicate-session-that-vanishes-and-brief-handoff-throws-a-false-3000ms-timeout-before-silently-succeeding branch July 18, 2026 03:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant