# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/under-what-conditions-must-an-instance-treat-a-peer-s-agent-card-as-stale-before-task-submission-and-when-is-re-fetch-a-correctness-hazard.md
# Remnant Warrant:    https://corpusfetch.com/c/under-what-conditions-must-an-instance-treat-a-peer-s-agent-card-as-stale-before-task-submission-and-when-is-re-fetch-a-correctness-hazard.warrant.json
# Markdown SHA-256:   b684cc303ade99996eaffebd162890a6db50fa50a6ee8d26b1d47d81a62efcc3
# Code AST SHA-256:   4e4f6421038f74d8616b12449276d3ee1e8e2003042434af12d40f094a3d84d1
# Verified Classes:   ContractFrozenError, TaskState, AgentCard, Task
# Defensive Guards:   3 fail-closed invariants (zero external deps)

import hashlib
import json
from dataclasses import dataclass
from enum import Enum
from typing import Optional


class ContractFrozenError(RuntimeError):
    """Raised when a peer message implies a contract divergent from the frozen one."""


class TaskState(Enum):
    SUBMITTED = "submitted"
    WORKING = "working"
    COMPLETED = "completed"
    FAILED = "failed"


CONTRACT_FIELDS = ("protocolVersion", "securitySchemes", "security")


@dataclass(frozen=True)
class AgentCard:
    raw: dict

    def contract_hash(self) -> str:
        contract = {k: self.raw.get(k) for k in CONTRACT_FIELDS}
        blob = json.dumps(contract, sort_keys=True, separators=(",", ":")).encode()
        return hashlib.sha256(blob).hexdigest()


@dataclass
class Task:
    state: TaskState
    frozen_contract_hash: Optional[str] = None


def capture_contract(card: AgentCard, task: Task) -> str:
    if task.state is not TaskState.SUBMITTED:
        raise ContractFrozenError(
            f"cannot capture contract in state {task.state.value}; "
            "contract must be frozen at submission time"
        )
    task.frozen_contract_hash = card.contract_hash()
    return task.frozen_contract_hash


def verify_peer_message(card: AgentCard, task: Task) -> None:
    if task.frozen_contract_hash is None:
        raise ContractFrozenError("task has no frozen contract; refusing to verify")
    observed = card.contract_hash()
    if observed != task.frozen_contract_hash:
        raise ContractFrozenError(
            "peer implied contract diverges from frozen contract: "
            f"frozen={task.frozen_contract_hash[:12]} observed={observed[:12]}"
        )
