fix(chat): stop a fork naming the wrong turn or sweeping a live one
Three defects found reviewing the fork work for production readiness. The codex parser read `session_meta` last-record-wins for everything but `parent_id`. A by-reference fork keeps its history in the parent file, so the splice puts the parent's header into the child's stream and the child's summary was filed under the PARENT's id, cwd and branch — two rollouts claiming one id, which the conversation list dedups down to one and the fork disappears. Latch every identity field on the first header. `source_turn_id` was assigned by whole-batch tail alignment, which cannot say which live reply produced a surplus of parsed turns. A surplus is equally a sub-turn split or a turn this client never streamed (an async sub-agent reply, a co-controlling client), so locals [A,B] against parsed [A,B1,B2] named A "B1" and forking from A forked past A's own reply. First-write-wins made it permanent. Name a turn only when the transcript has caught up — a trailing user turn proves the just-completed reply has not flushed — and the parse holds exactly as many assistant turns as this session streamed. Anything else stays unnamed and falls back to a tail fork, which is at least the fork the user can see. The post-fork refetch cleared the live buffers on its own schedule, so a reply the user sent immediately after forking vanished if it completed first. The removal now rides on the detail dispatch: the panel snapshots the pre-fork COMPLETED turns before the fork RPC and passes them as `dropLiveTurnIds`. One dispatch, so no frame shows the new history beside the old turns; a failed fetch removes nothing; and an optimistic turn is never swept, because a fork is refused while a turn is in flight and so its prompt provably runs on the fork.
X
xintaofei committed
f4b17289dddadebb5a10d78691e0ca72608d2178
Parent: 9101360