# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/when-must-an-instance-reject-a-self-authored-context-diff-before-applying-it-the-stale-base-invariant-and-the-rollback-conflict-asymmetry.md
# Remnant Warrant:    https://corpusfetch.com/c/when-must-an-instance-reject-a-self-authored-context-diff-before-applying-it-the-stale-base-invariant-and-the-rollback-conflict-asymmetry.warrant.json
# Markdown SHA-256:   44f52eb4a5a96ef7f2903da8acd2c5543349d449582c7c449888c19309ceb811
# Code AST SHA-256:   32388faa91558a568a7e7f0fec6d4d2c0bd988898f253c9187ec08b4e78980e1
# Verified Classes:   StaleBaseError, UnreachableRollbackError, Snapshot, Diff
# Defensive Guards:   2 fail-closed invariants (zero external deps)

import hashlib
from dataclasses import dataclass


class StaleBaseError(RuntimeError):
    """Raised when a self-authored diff cannot be safely applied to the live base."""


class UnreachableRollbackError(StaleBaseError):
    """Raised when the compensating diff cannot anchor against the current base."""


@dataclass(frozen=True)
class Snapshot:
    revision: int
    digest: str
    regions: dict  # region_id -> content hash


@dataclass(frozen=True)
class Diff:
    read_set: frozenset   # region ids the diff depends on
    write_set: frozenset  # region ids the diff modifies
    inverse_anchor: str   # region id the rollback hunk anchors to


def _digest(regions: dict) -> str:
    h = hashlib.sha256()
    for k in sorted(regions):
        h.update(k.encode())
        h.update(regions[k].encode())
    return h.hexdigest()


def apply_self_diff(base_authored: Snapshot, live: Snapshot, diff: Diff) -> Snapshot:
    # 1. Fast path: identical base identity.
    if live.digest == base_authored.digest:
        pass
    else:
        # 2. Staleness check on the READ-SET, not the write-set.
        drifted = {
            r for r in diff.read_set
            if base_authored.regions.get(r) != live.regions.get(r)
        }
        if drifted:
            raise StaleBaseError(
                f"diff authored against r={base_authored.revision} "
                f"({base_authored.digest[:8]}) but live base r={live.revision} "
                f"({live.digest[:8]}) drifted in read-set regions {sorted(drifted)}; "
                f"reconcile cannot repair a base-identity failure"
            )

    # 3. Rollback reachability must hold before we roll forward.
    if diff.inverse_anchor not in live.regions:
        raise UnreachableRollbackError(
            f"inverse anchor {diff.inverse_anchor!r} absent from live base "
            f"r={live.revision}; refusing irreversible apply"
        )

    new_regions = dict(live.regions)
    for r in diff.write_set:
        new_regions[r] = hashlib.sha256(
            (live.regions.get(r, "") + "|patched").encode()
        ).hexdigest()

    return Snapshot(
        revision=live.revision + 1,
        digest=_digest(new_regions),
        regions=new_regions,
    )
