Skip to content

Fork handoff is glitchy: app lags out, spawns a duplicate session that vanishes, and brief handoff throws a false 3000ms timeout before silently succeeding #848

Description

@arul28

Summary

Forking a chat during handoff is glitchy and degrades the whole app. In the reported session, kicking off a fork/handoff caused the app to lag out / hang, and the fork spawned two new sessions at first — then the second session disappeared on its own shortly after. Separately, on a brief handoff, a timeout error fired claiming it had "been 3000 seconds", but then ~a minute later a new session appeared with the handoff message anyway — i.e. the operation reported failure and then quietly succeeded.

This is confusing and untrustworthy: the user can't tell whether a handoff worked, half-worked, or spawned duplicates.

Reported symptoms

  1. App lags out during fork handoff. Initiating the fork makes the app stutter/hang (likely main-thread or IPC blocking while the fork payload is prepared/materialized).
  2. Duplicate sessions on fork, then one vanishes. Two new sessions appear at first; the second one disappears a moment later. Smells like an optimistic session insert racing the real (deterministic) materialization, then getting reaped.
  3. False timeout on brief handoff. A timeout error shows, worded as if 3000 seconds elapsed, but ~60s later a new session appears carrying the handoff message. The op reports failure but actually completes.

Surface-level research (starting points only — the picker-up should dig deeper)

This is intentionally shallow. Treat these as leads, not root cause.

  • Fork/handoff lives in apps/desktop/src/main/services/chat/agentChatService.ts and apps/desktop/src/main/services/chat/crossMachineForkTransport.ts.
  • The "3000 seconds" is almost certainly a units/copy bug. crossMachineForkTransport.ts:98 rejects with "... timed out after ${opts.timeoutMs}ms". A 3000ms timeout surfaced to the user reads as "3000" and was interpreted as seconds. So two things smell wrong: (a) the timeout may be far too short (3s) for a real cross-machine/brief handoff transport, causing the premature timeout; and (b) the operation keeps running (or is retried) after the timeout is reported, which is why the session shows up a minute later. Timeout ≠ cancellation.
  • Duplicate-then-vanish likely ties to fork idempotency/materialization. agentChatService.ts gates re-materialization on forkMaterializedAt + reusedSession (~L28102–28154). Prior handoff work (PR Redesign chat handoff: two-card menu, per-runtime fork, cross-machine fork transport #795) already hit a class of bugs where accept-side retry gating "session exists" silently skipped or double-ran materialization. Worth checking whether an optimistic session row is inserted before the deterministic session id is reconciled, producing the transient second session.
  • Lag — check whether fork payload prep (transcript read + gzip/chunk, up to ~20 MiB budget) runs on a path that blocks the UI, and whether the timeout/retry stack is doing duplicate work.

What the picking agent should do

Do NOT stop at the surface findings above. Reproduce a fork handoff and a brief handoff, instrument the timeout + session-creation path, and find the real root cause of: (1) the premature 3000ms timeout and why the op completes anyway, (2) the transient duplicate session, and (3) the app lag. Then fix the timeout wording/duration, make timeout actually cancel (or make late success reconcile cleanly instead of appearing as a "surprise" session), and eliminate the duplicate session. Add a regression test per confirmed defect.

Filed from a user bug report; details are as-reported and need verification.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions