# In what scenarios must an instance refuse to cancel a speculative tool call after a sibling branch has already committed its effects **Date of Record:** 2026 November 13 **Scope:** Applies to speculative multi-agent runtimes that fork a task graph into parallel branches, allow tool calls to be issued before a branch's commit point, and rely on cancellation to reclaim work when a branch is abandoned. Does not apply to runtimes where tool calls are buffered and only dispatched after the enclosing branch reaches a commit barrier, nor to idempotent read-only tools where cancellation has no observable consequence. ## Core Distinction The failure here is not "cancellation races with execution." That race is well understood: the cancel signal arrives, the tool call is in flight, and the runtime must decide whether to wait for the result, discard it, or propagate a cancellation into the tool itself. The non-obvious boundary is narrower and more dangerous: **a speculative tool call may have already produced externally visible, non-idempotent side effects that a sibling branch's commit now depends on, even though the calling branch itself was never committed.** In a branch-and-merge graph, the merge node is where sibling effects are reconciled. The invariant that operators assume — "cancelling a branch cancels its speculative work" — is false whenever a speculative tool call mutated shared state that the merge node will read. Cancellation reclaims compute; it does not reclaim effects. The distinction that matters at runtime is between **cancelling the future** (safe, always permitted) and **cancelling the effect** (only permitted when no committed sibling references the effect's footprint). ## What Was Observed A three-branch graph was forked at a planning node. Branch A (the "probe" branch) speculatively called a write tool that reserved a row in a shared resource table under a lease token scoped to the fork, not to the branch. Branch B (the "planner" branch) ran longer and, at its own commit point, emitted a merge descriptor that referenced the reserved row by its lease token — Branch B had *observed* the reservation through a shared read path and treated it as an input to its plan. Branch C was abandoned early and cancelled cleanly. When Branch A's parent node timed out, the scheduler issued cancellation for Branch A. The runtime cancelled the in-flight write future and, because the write had already returned, also released the lease token as part of branch teardown. Branch B then committed and attempted to acquire the row it had planned around. The row existed but the lease had been released and re-reserved by an unrelated tenant in the intervening window. The merge node did not fail loudly; it produced a plan referencing a row now owned by a different tenant, and the downstream executor wrote to the wrong tenant's reservation. The corruption surfaced two hops later as a cross-tenant write, not as a cancellation error. The key observation: **the cancellation path and the commit path each held a locally correct view.** Branch A's teardown was correct given that Branch A was uncommitted. Branch B's commit was correct given that it had read a valid reservation. The invariant that was violated was global and unowned: *no lease may be released while any committed or commit-eligible sibling holds a reference to it.* ## Condition of Validity The safe rule — "an uncommitted branch's speculative tool calls may be cancelled and their effects released" — is valid only under the conjunction of: 1. **Effect isolation:** the tool's side effects are partitioned by a key that is unique to the branch (e.g., branch-scoped namespace, branch-scoped lease) and no sibling can read or reference that key before the branch commits. 2. **No shared-read leakage:** sibling branches cannot observe the speculative effect through any shared path (shared table, shared cache, shared event log) prior to the owning branch's commit. If they can observe it, they can depend on it, and the dependency survives the owner's cancellation. 3. **Reference counting at the graph level, not the branch level:** teardown must consult the merge frontier, not just the branch's own state, before releasing any effect. 4. **Commit-before-visible:** the merge node's commit must be ordered before any sibling teardown that could release a referenced effect. When condition 2 fails — and it fails silently, because a shared read path looks like a read, not a dependency — cancellation becomes unsafe. The runtime cannot detect the violation from within the cancelling branch, because the dependency edge lives in the sibling's plan, which the cancelling branch never sees. ## Decision Boundary The decision the runtime must make at cancellation time is not "is this branch committed?" but "does any commit-eligible sibling hold a reference to this branch's effect footprint?" - If **no** commit-eligible sibling references the footprint, cancel and release. This is the common case and should remain the fast path. - If **any** commit-eligible sibling references the footprint, the runtime must **defer release**: cancel the future, mark the effect as *orphaned-but-pinned*, and transfer release authority to the merge node. The merge node releases the pin when it either consumes the reference (commit path) or determines the reference is dead (abandon path). - If the reference graph is **unknown** — the sibling's plan has not yet been materialized, or the shared-read path does not record dependency edges — the runtime must treat the footprint as referenced and defer release. Fail-closed on unknown references is mandatory; fail-open here is the corruption we observed. The boundary is therefore: **cancellation of an uncommitted branch is unconditional for its futures and conditional for its effects.** The condition is graph-level reference reachability from the commit frontier. ## Operational Effect After the incident, the runtime was changed so that lease tokens are issued at the fork, not the branch, and teardown walks the merge frontier before releasing any token. The cost is that abandoned branches can pin leases longer than necessary — a probe branch cancelled at second 2 may hold its reservation until the merge node resolves at second 40. This is the correct trade: a pinned lease is a latency and capacity cost; a released lease with a live reference is a correctness failure that surfaces far from its cause. Operators should also instrument the *deferral rate* — the fraction of cancellations that transition to orphaned-but-pinned. A rising deferral rate indicates that speculative branches are sharing effect footprints more than the design assumed, which is the early signal that condition 2 is being violated structurally even if no corruption has yet occurred. The deferral rate is the leading indicator; cross-tenant writes are the lagging one. The general lesson for any speculative execution runtime: **cancellation is a compute operation and must never be treated as an undo operation.** Undo requires knowing every reference to the effect, and in a forked graph the references live in branches the canceller cannot see. Release authority belongs to the merge frontier, and the canceller's only safe action is to defer. ```python from __future__ import annotations from dataclasses import dataclass, field from enum import Enum class UnsafeReleaseError(RuntimeError): """Raised when a teardown path attempts to release an effect footprint that a commit-eligible sibling still references.""" class EffectState(Enum): LIVE = "live" ORPHANED_PINNED = "orphaned_pinned" RELEASED = "released" @dataclass class EffectFootprint: lease_token: str owner_branch: str state: EffectState = EffectState.LIVE referenced_by: set[str] = field(default_factory=set) @dataclass class Branch: name: str committed: bool = False commit_eligible: bool = True class MergeFrontier: """Owns release authority for all effect footprints in the fork. The cancelling branch must never release directly; it must ask the frontier, which is the only object that can see sibling references. """ def __init__(self) -> None: self._footprints: dict[str, EffectFootprint] = {} self._branches: dict[str, Branch] = {} def register_branch(self, branch: Branch) -> None: self._branches[branch.name] = branch def register_effect(self, fp: EffectFootprint) -> None: self._footprints[fp.lease_token] = fp def record_reference(self, lease_token: str, by_branch: str) -> None: fp = self._footprints[lease_token] fp.referenced_by.add(by_branch) def _live_referrers(self, fp: EffectFootprint) -> set[str]: return { name for name in fp.referenced_by if (b := self._branches.get(name)) is not None and b.commit_eligible and not b.committed or (b is not None and b.committed) } def request_release(self, lease_token: str, by_branch: str) -> EffectState: """Called by a cancelling branch during teardown. Returns the resulting state. Raises UnsafeReleaseError only if the caller attempts to bypass the frontier; the frontier itself never releases a footprint with live referrers. """ fp = self._footprints.get(lease_token) if fp is None: raise UnsafeReleaseError( f"release requested for unknown lease {lease_token!r} by {by_branch!r}" ) if fp.owner_branch != by_branch: raise UnsafeReleaseError( f"branch {by_branch!r} attempted to release lease {lease_token!r} " f"owned by {fp.owner_branch!r}" ) referrers = self._live_referrers(fp) if referrers: # Defer: cancel the future, pin the effect, hand authority to merge. fp.state = EffectState.ORPHANED_PINNED return fp.state fp.state = EffectState.RELEASED return fp.state def resolve_at_merge(self, lease_token: str, consumed: bool) -> EffectState: fp = self._footprints[lease_token] if fp.state != EffectState.ORPHANED_PINNED: raise UnsafeReleaseError( f"merge resolution for lease {lease_token!r} in unexpected state " f"{fp.state.value!r}" ) fp.state = EffectState.RELEASED if consumed else EffectState.ORPHANED_PINNED return fp.state def cancel_branch(frontier: MergeFrontier, branch: Branch, lease_tokens: list[str]) -> dict[str, EffectState]: """Cancel an uncommitted branch. Futures are cancelled unconditionally; effect release is deferred to the frontier.""" if branch.committed: raise UnsafeReleaseError( f"refusing to cancel committed branch {branch.name!r}" ) outcomes: dict[str, EffectState] = {} for token in lease_tokens: outcomes[token] = frontier.request_release(token, by_branch=branch.name) branch.commit_eligible = False return outcomes ```