# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/when-must-an-instance-abandon-speculative-execution-branch-reconciliation-starvation-under-non-commutative-side-effects.md
# Remnant Warrant:    https://corpusfetch.com/c/when-must-an-instance-abandon-speculative-execution-branch-reconciliation-starvation-under-non-commutative-side-effects.warrant.json
# Markdown SHA-256:   9e225a673beb731977b0699605bea8f34ef5c908868c0b3ac051c98453ae99cc
# Code AST SHA-256:   6e3116d0d904f37b5f43c599b109cf54cfa4c03635aa1e9e2c02da704d16e4d2
# Verified Classes:   UnreconcilableBranchError
# Defensive Guards:   2 fail-closed invariants (zero external deps)

class UnreconcilableBranchError(RuntimeError):
    """Raised when a speculative branch cannot be rolled back or committed."""


def classify_branch(branch, live_edges, derive_cost, inverse_cost):
    if not branch.emitted_effects:
        return "speculative"
    if branch.effects_are_commutative:
        return "speculative"
    if inverse_cost <= derive_cost and not live_edges:
        return "rollbackable"
    if live_edges and inverse_cost > derive_cost:
        raise UnreconcilableBranchError(
            f"branch {branch.id} has non-invertible effects "
            f"(inverse={inverse_cost}s, derive={derive_cost}s) and "
            f"{len(live_edges)} live dependents {sorted(live_edges)}; "
            f"promote to committed and re-parent dependents before merge"
        )
    return "committed_on_emit"


def open_merge_gate(winner, branches):
    blockers = []
    for b in branches:
        if b.id == winner.id:
            continue
        edges = b.live_dependents()
        try:
            state = classify_branch(b, edges, b.derive_cost, b.inverse_cost)
        except UnreconcilableBranchError as exc:
            blockers.append(str(exc))
            continue
        if state == "rollbackable" and edges:
            blockers.append(f"{b.id}: rollbackable but {len(edges)} live edges")
    if blockers:
        raise UnreconcilableBranchError(
            "merge gate blocked: " + " | ".join(blockers)
        )
    return True
