# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/which-invariants-prevent-speculative-multi-agent-rollback-from-violating-committed-side-effect-monotonicity.md
# Remnant Warrant:    https://corpusfetch.com/c/which-invariants-prevent-speculative-multi-agent-rollback-from-violating-committed-side-effect-monotonicity.warrant.json
# Markdown SHA-256:   dd70582d581b589d4993ed3a4ffa6f68edf73fad0e0fe2195349e8677db677a7
# Code AST SHA-256:   b8d4d7589b03047045896d8fde95784d4654567336134908c5a14e9333ee9f08
# Verified Classes:   SpeculativeCommitViolation, EffectLedger
# Defensive Guards:   5 fail-closed invariants (zero external deps)

class SpeculativeCommitViolation(RuntimeError):
    """Raised when rollback would violate committed side-effect monotonicity."""

    def __init__(self, effect_id: str, reason: str):
        self.effect_id = effect_id
        self.reason = reason
        super().__init__(f"effect {effect_id}: {reason}")


class EffectLedger:
    def __init__(self):
        self._committed = {}   # effect_id -> commit_token
        self._observed = set() # effect_ids read by external observers

    def mark_observed(self, effect_id: str) -> None:
        self._observed.add(effect_id)

    def commit(self, effect_id: str, token: str) -> None:
        self._committed[effect_id] = token

    def rollback(self, effect_id: str, token: str) -> str:
        if effect_id in self._committed:
            if self._committed[effect_id] != token:
                raise SpeculativeCommitViolation(
                    effect_id, "rollback token does not match commit token"
                )
            raise SpeculativeCommitViolation(
                effect_id, "effect is committed; use compensation, not rollback"
            )
        if effect_id in self._observed:
            raise SpeculativeCommitViolation(
                effect_id, "effect was externally observed; must be compensated, not deleted"
            )
        return "discarded"


def reconcile_branch(ledger: EffectLedger, effect_id: str, token: str) -> str:
    try:
        return ledger.rollback(effect_id, token)
    except SpeculativeCommitViolation:
        raise
    except Exception as exc:
        raise SpeculativeCommitViolation(effect_id, f"unexpected reconcile error: {exc}")
