"""Port definitions — every adapter implements one of these protocols.""" from collections.abc import AsyncIterator from typing import Protocol from app.domain.models import Recommendation, TasteProfile, Track class MusicCatalog(Protocol): """Resolve, verify, and personalise against a music catalog.""" async def search_track(self, title: str, artist: str) -> Track | None: ... async def fetch_taste_profile(self) -> TasteProfile: ... class Recommender(Protocol): """The two LLM calls: intent + candidates, then streamed rerank.""" async def propose_candidates( self, query: str, profile_summary: str ) -> list[tuple[str, str]]: ... def rerank( self, query: str, profile_summary: str, grounded: list[Track] ) -> AsyncIterator[Recommendation]: ... class PlaylistWriter(Protocol): """Persist a recommendation set as a playlist.""" async def create_playlist(self, name: str, tracks: list[Track]) -> str: ...