Problem
During a subtask transition, the webview can render a ready child task and then regress to the Home/Recent Tasks screen when an older empty-message state snapshot completes later. Multiple overlapping publications can appear as an automatic Home/child loop.
Root cause
ClineProvider.postStateToWebview() and postStateToWebviewWithoutTaskHistory() increment clineMessagesSeq only after awaiting getStateToPostToWebview().
Snapshot construction is asynchronous. A request that captured the child while clineMessages was empty can finish after a newer ready-child request. The stale request then receives the higher sequence number, so the webview's stale-state guard accepts the empty messages as newer.
Child startup is particularly exposed because Task.startTask() intentionally clears clineMessages, posts state, and only then adds the child's first message.
Evidence
TLA+ TLC, Alloy 6, and SPIN independently produced the same counterexample:
- Capture child state with empty messages.
- Child publishes its first message.
- Deliver the ready-child snapshot.
- Deliver the older empty snapshot with the higher completion-order sequence.
- Webview accepts it and renders Home while the child remains current.
A focused Vitest reproduction against the production methods confirmed the ordering: the newer ready snapshot posted first with sequence 1, then the older empty snapshot posted with sequence 2.
Expected result
Message-state sequence numbers represent publication initiation order, or message-bearing publications are serialized, so a delayed older snapshot cannot replace newer child messages.
Acceptance criteria
- Add a regression test that delays an older empty snapshot while a newer ready-child snapshot posts.
- Verify the delayed snapshot has an older sequence and cannot replace the ready child messages.
- Preserve existing state-post await semantics and non-message state merging.
- Run the full Zoo Code test suite.
Related
Problem
During a subtask transition, the webview can render a ready child task and then regress to the Home/Recent Tasks screen when an older empty-message state snapshot completes later. Multiple overlapping publications can appear as an automatic Home/child loop.
Root cause
ClineProvider.postStateToWebview()andpostStateToWebviewWithoutTaskHistory()incrementclineMessagesSeqonly after awaitinggetStateToPostToWebview().Snapshot construction is asynchronous. A request that captured the child while
clineMessageswas empty can finish after a newer ready-child request. The stale request then receives the higher sequence number, so the webview's stale-state guard accepts the empty messages as newer.Child startup is particularly exposed because
Task.startTask()intentionally clearsclineMessages, posts state, and only then adds the child's first message.Evidence
TLA+ TLC, Alloy 6, and SPIN independently produced the same counterexample:
A focused Vitest reproduction against the production methods confirmed the ordering: the newer ready snapshot posted first with sequence
1, then the older empty snapshot posted with sequence2.Expected result
Message-state sequence numbers represent publication initiation order, or message-bearing publications are serialized, so a delayed older snapshot cannot replace newer child messages.
Acceptance criteria
Related