# Why does an instance of speculative multi-agent execution fail to roll back cleanly when a branch reconciles against a stale observation snapshot? **Date of Record:** 2026 November 8 **Scope:** Applies to multi-agent systems where a coordinator forks speculative branches, each branch reads a shared observation snapshot, and branches are reconciled (merged or discarded) after execution. Does not apply to single-agent speculative decoding, nor to systems where branches are fully isolated with no shared mutable state and no post-hoc reconciliation against a common snapshot. ## Core Distinction The failure is not "a branch produced a wrong answer." It is that a branch's *rollback* (compensating action) is executed against the current world state, while the branch's *decision* was made against a snapshot that has since been superseded by a sibling branch's committed effects. Rollback is therefore not the inverse of the speculative action: it is a second, independent mutation applied to a state the branch never observed. Two things are routinely conflated: 1. **Speculative divergence** — branches disagree about what to do. This is expected and handled by reconciliation policy. 2. **Snapshot skew** — a branch's read-set is anchored to snapshot `S_i`, but its write-set (and its rollback) lands on world state `W_j` where `j > i`. Reconciliation that only compares branch *outputs* (the proposed result) cannot detect this, because outputs may be identical while their write-sets target different base versions. The invariant that must hold: **a branch may only commit or roll back if its read-snapshot version equals the version its write-set was derived from, and that version is still the current committed version at reconciliation time.** When a sibling commits first, the losing branch's snapshot is stale, and its rollback is unsound. ## What Was Observed A coordinator spawned three speculative branches (`A`, `B`, `C`) from snapshot `S_7`. Each branch read a resource record (`version=7`) and each proposed a mutation plus a compensating rollback closure. Branch `A` committed first, advancing the record to `version=8` and appending an audit entry. The coordinator then discarded `B` and `C` and invoked their rollback closures. The rollback closures had been captured as `restore(record, prior_value_from_S_7)`. Executing them wrote `prior_value` back — but `prior_value` was the state at `S_7`, not the state at `S_8` that `A` had produced. The net effect was that `A`'s committed mutation was silently erased, the audit entry for `A` remained (so the log claimed a mutation that no longer existed), and the record's version counter was decremented twice, landing at `version=6` — a version that never existed in the committed history. Key empirical markers: - Reconciliation reported success: branch outputs were compared, `A` was selected, `B`/`C` were "cleanly discarded." - The corruption was invisible in per-branch logs; it only appeared when replaying the committed history and finding a version gap (`7 → 8 → 6`). - The failure reproduced only when a *losing* branch's rollback ran *after* a *winning* branch's commit. If rollbacks ran before any commit, or if all branches were discarded, no corruption occurred. ## Condition of Validity The clean-rollback assumption holds only under the conjunction: - Each branch's rollback closure is expressed relative to a base version, and the base version is re-validated (compare-and-swap) at rollback time; **or** - Rollback is implemented as *inverse-delta* application (undo the branch's own writes) rather than *state restore* (write back a remembered prior value); **or** - Branch write-sets are disjoint at the field/record level, so a sibling's commit cannot intersect a discarded branch's restore target. It fails when rollback is implemented as state-restore from a captured snapshot **and** branches share a mutable target **and** reconciliation permits interleaved commit-then-rollback ordering. The presence of any one of these without the others is usually benign; the conjunction is the boundary. ## Decision Boundary At reconciliation, for each discarded branch `b` with read-snapshot version `v_read(b)` and target record `r`: - If `current_version(r) == v_read(b)`: safe to apply state-restore rollback. - If `current_version(r) > v_read(b)`: **do not** state-restore. Either apply inverse-delta only, or escalate to a manual reconciliation record. State-restore here is guaranteed to clobber a sibling's committed effect. - If `current_version(r) < v_read(b)`: the history has been rewritten (a prior rollback already fired); halt and surface the version gap. The coordinator must treat "discard" as a write operation subject to the same version guard as "commit," not as a no-op cleanup. A discarded branch that cannot roll back safely must be quarantined, not silently dropped. ## Operational Effect Systems that violate this boundary exhibit *phantom rollback*: committed effects disappear while their audit trail persists, and version counters drift to values outside the committed history. Recovery requires reconstructing state from the audit log rather than from the record itself, because the record no longer reflects any real version. The correct mitigation is to make rollback closures carry their base version and to enforce the version guard above at reconciliation, converting an unsound restore into a detectable `StaleRollbackError` that the coordinator can quarantine and replay. ```python class StaleRollbackError(RuntimeError): """Raised when a discarded branch's rollback targets a superseded snapshot.""" pass def reconcile_and_rollback(record, discarded_branches): """ Apply rollbacks for discarded speculative branches with a version guard. `record` exposes .version and .apply_inverse(delta) / .restore(value). Each branch exposes .read_version and .inverse_delta / .prior_value. """ for branch in discarded_branches: current = record.version if current == branch.read_version: # Safe: world state still matches what the branch observed. record.restore(branch.prior_value) elif current > branch.read_version: # Sibling committed after this branch forked. State-restore would # clobber the sibling's committed effect. Use inverse-delta only. if branch.inverse_delta is None: raise StaleRollbackError( f"branch {branch.id} forked at v{branch.read_version} " f"but record is at v{current}; no inverse-delta available, " f"quarantining instead of state-restoring" ) record.apply_inverse(branch.inverse_delta) else: # current < read_version: history was rewritten by an earlier # rollback. This indicates a prior corruption; halt. raise StaleRollbackError( f"branch {branch.id} read v{branch.read_version} but record " f"regressed to v{current}; committed history is inconsistent" ) ```