# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/where-must-an-instance-fork-its-execution-state-before-speculative-multi-agent-rollback-can-be-trusted.md
# Remnant Warrant:    https://corpusfetch.com/c/where-must-an-instance-fork-its-execution-state-before-speculative-multi-agent-rollback-can-be-trusted.warrant.json
# Markdown SHA-256:   7202ebddf2c4cb735337e41146f0ad71358eb037cbb9c490b94d1cdfc5107abe
# Code AST SHA-256:   7db1ec63f7c5e44562ef44140334a98fda6a585b24203e5041ac228ac9ed8a38
# Verified Classes:   UnsafeForkPointError, Branch
# Defensive Guards:   3 fail-closed invariants (zero external deps)

class UnsafeForkPointError(RuntimeError):
    """Raised when a branch is forked at a reasoning boundary while it retains a live effect path."""
    pass


class Branch:
    def __init__(self, branch_id, has_effect_path, fork_layer):
        self.branch_id = branch_id
        self.has_effect_path = has_effect_path
        self.fork_layer = fork_layer  # "reasoning" or "effect"
        self.overlay = {}
        self.journal = []

    def write(self, key, value):
        if self.fork_layer != "effect":
            # The branch can mutate the world but has no diffable overlay to roll back.
            raise UnsafeForkPointError(
                f"branch {self.branch_id} wrote {key!r} at reasoning fork; "
                "no effect boundary captured, rollback would be a lie"
            )
        self.overlay[key] = value
        self.journal.append(("delete", key))


def fork_branch(branch_id, has_effect_path, requested_layer):
    if has_effect_path and requested_layer == "reasoning":
        raise UnsafeForkPointError(
            f"branch {branch_id} has a live effect path and cannot fork at the "
            "reasoning boundary; fork at the effect boundary to make rollback sound"
        )
    return Branch(branch_id, has_effect_path, requested_layer)


def rollback(branch):
    if branch.fork_layer != "effect":
        raise UnsafeForkPointError(
            f"cannot roll back {branch.branch_id}: no effect overlay to revert"
        )
    for op, key in reversed(branch.journal):
        if op == "delete":
            branch.overlay.pop(key, None)
    branch.journal.clear()
