# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/which-invariants-prevent-speculative-agent-plans-from-committing-irreversible-tool-actions-without-a-verified-precondition.md
# Remnant Warrant:    https://corpusfetch.com/c/which-invariants-prevent-speculative-agent-plans-from-committing-irreversible-tool-actions-without-a-verified-precondition.warrant.json
# Markdown SHA-256:   873a95b59f3071c25525ee01f5ba4cac8e7a0fc4838511f05456ecd474bf1d64
# Code AST SHA-256:   3a789a2e3a1bfca9d7bf2f6720a780b20a58242b6bc16cd5cafe068b70e2970c
# Verified Classes:   UnsafeCommitBoundaryError
# Defensive Guards:   3 fail-closed invariants (zero external deps)

class UnsafeCommitBoundaryError(RuntimeError):
    """Raised when a plan would commit an irreversible action outside a locked, terminal-mutation transaction."""
    pass


IRREVERSIBLE = {"charge_card", "delete_resource", "send_external_notification"}


def validate_commit_unit(plan_steps, locked_world_state, verify_fn):
    """
    plan_steps: ordered list of tool-call dicts with 'tool' and 'precondition'.
    locked_world_state: live state read under the commit lock.
    verify_fn: callable(precondition, state) -> bool, evaluated inside the lock.
    """
    irreversible_positions = [
        i for i, s in enumerate(plan_steps) if s["tool"] in IRREVERSIBLE
    ]
    if not irreversible_positions:
        return True

    if len(irreversible_positions) > 1:
        raise UnsafeCommitBoundaryError(
            f"plan contains {len(irreversible_positions)} irreversible actions; "
            "commit unit must have exactly one terminal irreversible mutation"
        )

    terminal = irreversible_positions[0]
    if terminal != len(plan_steps) - 1:
        raise UnsafeCommitBoundaryError(
            f"irreversible action {plan_steps[terminal]['tool']} at position {terminal} "
            f"is not terminal (plan length {len(plan_steps)}); "
            "a fallible action follows an irreversible one"
        )

    for step in plan_steps:
        if not verify_fn(step["precondition"], locked_world_state):
            raise UnsafeCommitBoundaryError(
                f"precondition {step['precondition']!r} for {step['tool']} "
                "failed against locked world state; refusing to commit"
            )

    return True
