# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/when-must-an-instance-treat-a-speculative-tool-invocation-as-irreversible.md
# Remnant Warrant:    https://corpusfetch.com/c/when-must-an-instance-treat-a-speculative-tool-invocation-as-irreversible.warrant.json
# Markdown SHA-256:   0eb64714ed738100547002fa2efadb5ecc28534d9bd82ce962d6b3c6ec8f6261
# Code AST SHA-256:   441cc91ee2d5639ad92f7ecdf5b8a50fe032d73ff2ac6d3d386d607285125808
# Verified Classes:   EffectVisibility, Compensability, IrreversibleSpeculationError, ToolProfile
# Defensive Guards:   2 fail-closed invariants (zero external deps)

from dataclasses import dataclass
from enum import Enum


class EffectVisibility(Enum):
    PRIVATE = "private"
    EXTERNAL = "external"


class Compensability(Enum):
    REVERSIBLE = "reversible"
    IRREVERSIBLE = "irreversible"


class IrreversibleSpeculationError(RuntimeError):
    """Raised when a branch attempts an optimistic invocation whose effect
    is externally observable and not protected by a downstream fence."""


@dataclass(frozen=True)
class ToolProfile:
    name: str
    visibility: EffectVisibility
    compensability: Compensability
    downstream_fence: bool


def authorize_optimistic_invocation(tool: ToolProfile, branch_is_speculative: bool) -> None:
    if not branch_is_speculative:
        return  # post-merge path, no speculation, no boundary risk

    if tool.visibility is EffectVisibility.PRIVATE:
        # Local state; rollback is a state mutation, safe to speculate.
        return

    if tool.compensability is Compensability.IRREVERSIBLE:
        raise IrreversibleSpeculationError(
            f"tool {tool.name!r} has externally irreversible effects and cannot "
            f"be invoked optimistically from a speculative branch"
        )

    if not tool.downstream_fence:
        raise IrreversibleSpeculationError(
            f"tool {tool.name!r} is externally observable and reversible only "
            f"in principle, but no downstream fence is held; the compensation "
            f"window is unguarded against external observers"
        )

    # Externally observable, reversible, and downstream-fenced: allowed.
    return


def run_branch(tool: ToolProfile, speculative: bool) -> None:
    authorize_optimistic_invocation(tool, speculative)
    # ... invoke tool, register compensation, proceed with merge ...
