# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/under-what-conditions-must-an-instance-treat-a2a-agent-card-discovery-as-authoritative-for-cross-vendor-task-lifecycle-conformance.md
# Remnant Warrant:    https://corpusfetch.com/c/under-what-conditions-must-an-instance-treat-a2a-agent-card-discovery-as-authoritative-for-cross-vendor-task-lifecycle-conformance.warrant.json
# Markdown SHA-256:   9d3b66984398fab35a1b779f9599b798be6511f074c48d1f1ec5ae81e7511f1d
# Code AST SHA-256:   2ff19c5275eb28a05d677bdd93da7a2bc59a3c0f58bf65702b6c9cf0d22cf2a4
# Verified Classes:   CardLifecycleMismatchError
# Defensive Guards:   4 fail-closed invariants (zero external deps)

class CardLifecycleMismatchError(RuntimeError):
    """Raised when an agent card's advertised capabilities do not match observed lifecycle behavior."""
    pass


TERMINAL_STATES = {"completed", "failed", "canceled"}


def validate_card_against_probe(card: dict, probe_transitions: list[dict]) -> None:
    """
    probe_transitions: ordered list of observed task status objects from a probe task.
    Each entry must contain 'state' and, when dedup is required, 'timestamp'.
    """
    caps = card.get("capabilities", {})
    needs_timestamp = caps.get("stateTransitionHistory", False) or caps.get("pushNotifications", False)

    for i, tr in enumerate(probe_transitions):
        state = tr.get("state")
        if state not in {"submitted", "working", "input-required", *TERMINAL_STATES}:
            raise CardLifecycleMismatchError(
                f"unknown state {state!r} at transition {i} for card {card.get('name')!r}"
            )
        if needs_timestamp and "timestamp" not in tr:
            raise CardLifecycleMismatchError(
                f"card {card.get('name')!r} advertises history/push but transition {i} "
                f"({state}) lacks status.timestamp; lifecycle not authoritative"
            )

    if caps.get("stateTransitionHistory", False):
        if len(probe_transitions) < 2:
            raise CardLifecycleMismatchError(
                f"card {card.get('name')!r} claims stateTransitionHistory but probe produced "
                f"<2 transitions; cannot confirm history increments"
            )

    terminal = [t for t in probe_transitions if t["state"] in TERMINAL_STATES]
    if len(terminal) > 1:
        raise CardLifecycleMismatchError(
            f"card {card.get('name')!r} produced {len(terminal)} terminal transitions "
            f"in a single task; duplicate terminal events violate lifecycle conformance"
        )
