# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/how-does-an-instance-detect-equivocation-in-a-multi-agent-task-commitment-quorum-when-the-equivocating-node-is-the-one-that-assigned-the-view-number.md
# Remnant Warrant:    https://corpusfetch.com/c/how-does-an-instance-detect-equivocation-in-a-multi-agent-task-commitment-quorum-when-the-equivocating-node-is-the-one-that-assigned-the-view-number.warrant.json
# Markdown SHA-256:   b77c33d08787788b9299801b64898c7dcca621306ab1bdfc633fefdcc049c3b1
# Code AST SHA-256:   276deef574944b1f0c2c3398c995628a8ffd3f2fdeffa6f367da37652ac6e958
# Verified Classes:   EquivocationUnprovableError, Commit
# Defensive Guards:   2 fail-closed invariants (zero external deps)

import hashlib
from dataclasses import dataclass


class EquivocationUnprovableError(RuntimeError):
    """Raised when a node detects a conflicting commit but cannot bind the
    conflict to a view number it is authorized to attest, because the
    equivocating node minted the view."""
    pass


@dataclass(frozen=True)
class Commit:
    task_slot: str
    view: int
    payload_hash: str
    sender: str


def check_commit_set(
    commits: list[Commit],
    local_view: int,
    leader_id: str,
    quorum: int,
) -> str:
    """Return the payload hash to execute, or raise if the set is unsafe.

    The dangerous case: the leader's commit is present and matches our
    PREPARE, giving us a local quorum, but a peer's commit for the same
    slot carries a different payload hash under the same leader-minted
    view. We cannot prove this to the quorum; we can only guard locally.
    """
    by_slot: dict[str, set[str]] = {}
    for c in commits:
        if c.view != local_view:
            continue
        by_slot.setdefault(c.task_slot, set()).add(c.payload_hash)

    for slot, hashes in by_slot.items():
        if len(hashes) > 1:
            leader_committed = any(
                c.sender == leader_id and c.task_slot == slot for c in commits
            )
            if leader_committed:
                # We hold a local quorum including the leader, yet the
                # payloads disagree. The leader is the equivocator and the
                # view-number authority; no view-change proof is constructible.
                raise EquivocationUnprovableError(
                    f"slot {slot} view {local_view}: leader {leader_id} "
                    f"committed conflicting payloads {sorted(hashes)}; "
                    f"local quorum is reachable but unprovable to peers"
                )

    matching = [c for c in commits if c.view == local_view]
    if len(matching) < quorum:
        raise EquivocationUnprovableError(
            f"view {local_view}: only {len(matching)} commits, need {quorum}"
        )

    # Safe to execute only behind an idempotency key that does not depend
    # on the leader-minted view.
    payload = matching[0].payload_hash
    idem_key = hashlib.sha256(
        f"{matching[0].task_slot}:{payload}".encode()
    ).hexdigest()
    return idem_key
