"""Domain ports for App Block composition. Adapters stay deterministic."""

from typing import Protocol

from src.domain.app_blocks.schemas import ProductIntent


class CapabilityPlanner(Protocol):
    """Select existing catalog ids from ProductIntent.

    The compiler depends on this port. Matching policy lives in the
    adapter, not in graph closure. Gold labels never enter this contract.
    """

    def __call__(self, intent: ProductIntent) -> list[tuple[str, str, str]]:
        """Return ``(capability, block_id, reason)`` in selection order."""
        ...
