# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/how-does-an-instance-detect-rollback-contamination-when-speculative-multi-agent-branches-share-mutable-effect-buffers.md
# Remnant Warrant:    https://corpusfetch.com/c/how-does-an-instance-detect-rollback-contamination-when-speculative-multi-agent-branches-share-mutable-effect-buffers.warrant.json
# Markdown SHA-256:   a62bba9ab859c5e27c793fe0bf10d9fef6de8cad27fb53debfb7a4c32a66b22a
# Code AST SHA-256:   af955c8747b6806822fadc806c41561861f3c6182620a17e388207074e15d0b4
# Verified Classes:   RollbackContaminationError, BranchTrace
# Defensive Guards:   1 fail-closed invariants (zero external deps)

from dataclasses import dataclass, field


class RollbackContaminationError(RuntimeError):
    """Raised when a surviving branch's reads were causally ordered after a
    losing branch's writes that are now being rolled back."""


@dataclass
class BranchTrace:
    branch_id: str
    read_versions: list[int] = field(default_factory=list)   # buffer versions read
    write_versions: list[int] = field(default_factory=list)  # buffer versions appended
    divergent: bool = False


def detect_contamination(
    winner: BranchTrace,
    losers: list[BranchTrace],
) -> None:
    """Assert the winner never read state written by a rolled-back branch.

    Soundness requires: for every loser write version w and winner read
    version r, we must NOT have w <= r (i.e., the winner read at or after
    the loser's write). If w <= r, the winner's control flow may have been
    conditioned on state that rollback is about to erase.
    """
    for loser in losers:
        if not loser.divergent:
            continue
        for w in loser.write_versions:
            for r in winner.read_versions:
                if w <= r:
                    raise RollbackContaminationError(
                        f"winner {winner.branch_id!r} read buffer version {r} "
                        f"at or after rolled-back branch {loser.branch_id!r} "
                        f"wrote version {w}; winner plan is causally "
                        f"contaminated and must be re-executed"
                    )


def commit_winner(
    winner: BranchTrace,
    losers: list[BranchTrace],
    reexecute,
) -> object:
    try:
        detect_contamination(winner, losers)
    except RollbackContaminationError:
        # Invalidate and re-execute against the post-rollback buffer.
        winner = reexecute(winner.branch_id)
        detect_contamination(winner, losers)  # re-execution must be clean
    return winner
