# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/what-happens-when-an-instance-advertises-an-agent-card-mid-rollout-and-the-task-state-machine-disagrees-with-the-webhook-binding.md
# Remnant Warrant:    https://corpusfetch.com/c/what-happens-when-an-instance-advertises-an-agent-card-mid-rollout-and-the-task-state-machine-disagrees-with-the-webhook-binding.warrant.json
# Markdown SHA-256:   9c46e439c9a0118ee9695c0ff5a8f9ce04a6a498fca40edff56cf32a6d8375f3
# Code AST SHA-256:   c6935e6d9a1c39c83453816ceb6714c167f5b2bec954a095d512125e6d4f552a
# Verified Classes:   AgentCardContractError
# Defensive Guards:   5 fail-closed invariants (zero external deps)

class AgentCardContractError(RuntimeError):
    """Raised when an instance publishes an Agent Card it cannot honor."""
    pass


def publish_agent_card(card: dict, dispatcher: "Dispatcher", store: "TaskStore") -> dict:
    """Publish an Agent Card only if the instance can honor its declared contract.

    The Card advertises pushNotifications and a task lifecycle. We refuse to
    publish unless the dispatcher is subscribed to the event bus and has
    rebuilt its registration index from the authoritative store, and unless
    the store's schema matches the lifecycle states the Card declares.
    """
    if card.get("capabilities", {}).get("pushNotifications"):
        if not dispatcher.is_subscribed():
            raise AgentCardContractError(
                "refusing to publish Card with pushNotifications=true: "
                "dispatcher not subscribed to task event bus"
            )
        if not dispatcher.index_rebuilt_from(store):
            raise AgentCardContractError(
                "refusing to publish Card: dispatcher registration index "
                "not rebuilt from authoritative store"
            )
        if not store.schema_supports(card.get("taskStates", [])):
            raise AgentCardContractError(
                "refusing to publish Card: declared taskStates not supported "
                "by current store schema"
            )

    if card.get("capabilities", {}).get("streaming"):
        if not dispatcher.stream_fanout_ready():
            raise AgentCardContractError(
                "refusing to publish Card with streaming=true: "
                "event fan-out not wired to task store"
            )

    store.persist_card(card)
    return card


def accept_push_registration(task_id: str, callback_url: str,
                             dispatcher: "Dispatcher", store: "TaskStore") -> str:
    """Accept a webhook registration only if the serving dispatcher can see it."""
    config_id = store.persist_push_config(task_id, callback_url)
    if not dispatcher.observes_registration(config_id):
        # Do not return 200 for a registration the dispatcher will never deliver.
        raise AgentCardContractError(
            f"registration {config_id} persisted but not visible to dispatcher; "
            "returning 503 to client instead of accepting-and-dropping"
        )
    return config_id
