Problem
With multiple VS Code windows sharing Zoo Code global storage, one extension host can finish an older delegated child after another host has already interrupted that child and re-delegated the parent to a newer child. The stale completion marks the parent active and clears its delegation pointers, leaving the newer child active but unable to return through attempt_completion.
Deterministic reproduction
A barrier-controlled harness using two production TaskHistoryStore instances against the same storage reproduced this 25/25 times:
- Parent P is delegated to child C.
- Host A passes
reopenParentFromDelegation(P, C) ownership validation.
- Host B interrupts C, resumes P, and delegates P to child D.
- Host A applies C completion from its stale in-memory snapshot.
- D remains active with
parentTaskId = P, while P becomes active with no awaitingChildId and completedByChildId = C.
Formal model
SPIN finds the same counterexample and violates this invariant:
If child D is active and delegated from parent P, P must be delegated and awaiting D.
The corrected model revalidates parent ownership inside the final transition and exhausts with zero assertion violations.
Root cause
reopenParentFromDelegation validates parent.awaitingChildId === childTaskId before message I/O, but its final atomicUpdatePair parent updater does not revalidate that relationship. atomicUpdatePair serializes only within one extension host; cross-process atomicity is explicitly not guaranteed.
Expected behavior
A stale child completion must abort without changing either record if the current parent snapshot no longer awaits that child. A newer delegated child and its parent linkage must remain intact.
TDD acceptance criteria
- Add a deterministic two-store regression test using production persistence and real merge/lock behavior.
- Prove the test fails on current
main by producing the orphaned-child state.
- Revalidate
parent.status and parent.awaitingChildId inside the final pair update.
- Reject stale completion before either child or parent is persisted.
- Preserve normal child completion and interrupted-child resume behavior.
- Run the complete Zoo Code test suite.
Related
Parent issue: #921
Broader task-history concurrency: #920
Original metadata-driven delegation: #9090
In-process atomic handoff: #725
Problem
With multiple VS Code windows sharing Zoo Code global storage, one extension host can finish an older delegated child after another host has already interrupted that child and re-delegated the parent to a newer child. The stale completion marks the parent active and clears its delegation pointers, leaving the newer child active but unable to return through
attempt_completion.Deterministic reproduction
A barrier-controlled harness using two production
TaskHistoryStoreinstances against the same storage reproduced this 25/25 times:reopenParentFromDelegation(P, C)ownership validation.parentTaskId = P, while P becomes active with noawaitingChildIdandcompletedByChildId = C.Formal model
SPIN finds the same counterexample and violates this invariant:
The corrected model revalidates parent ownership inside the final transition and exhausts with zero assertion violations.
Root cause
reopenParentFromDelegationvalidatesparent.awaitingChildId === childTaskIdbefore message I/O, but its finalatomicUpdatePairparent updater does not revalidate that relationship.atomicUpdatePairserializes only within one extension host; cross-process atomicity is explicitly not guaranteed.Expected behavior
A stale child completion must abort without changing either record if the current parent snapshot no longer awaits that child. A newer delegated child and its parent linkage must remain intact.
TDD acceptance criteria
mainby producing the orphaned-child state.parent.statusandparent.awaitingChildIdinside the final pair update.Related
Parent issue: #921
Broader task-history concurrency: #920
Original metadata-driven delegation: #9090
In-process atomic handoff: #725