Anti-corruption boundary tightened on the TMDB adapter:
* TmdbMovieInfo / TmdbShowInfo now carry domain VOs (TmdbId, ImdbId,
MovieTitle, ReleaseYear, ShowStatus) instead of raw scalars —
validation happens at the boundary, not three layers later.
* ShowStatus enum added (domain/tv_shows/value_objects) with a
from_tmdb() mapper that falls back to UNKNOWN + logs a warning on
unrecognized values. TVShow.status is now ShowStatus, not str.
* MovieTitle cap raised from 100 to 150 chars.
* MediaResult / ExternalIds dropped. Replaced by per-media search
DTOs: TmdbMovieSearchResult and TmdbShowSearchResult. Neither
carries imdb_id — search no longer enriches with external_ids
(callers needing imdb_id follow up with get_movie_info /
get_tv_show_info on the chosen tmdb_id).
* TMDBClient: search_multi / search_media / _parse_result removed.
search_movies (/search/movie) and search_shows (/search/tv) added,
each parsing hits into VO-typed DTOs.
* SearchMovieUseCase returns a list of MovieHit (flattened to
primitives for the agent). New symmetric SearchShowUseCase +
ShowHit / SearchShowResponse DTOs.
* agent/tools/api.py: find_media_imdb_id → search_movies +
search_shows wrappers.
* FileEntry moved from domain/shared/ports/filesystem_scanner.py to
domain/shared/file_entry.py (it's a DTO, not a Protocol); size_kb
(float) → size (int bytes). Scanner and SubtitleIdentifier
updated.
Tests: 79/79 pass on tests/infrastructure/api/ +
tests/application/test_search_movie.py +
tests/application/test_search_show.py.
Symmetric to TmdbShowInfo / get_tv_show_info — gives the upcoming
sync_movie orchestrator a typed cache snapshot for the v2 movie
library index.
* TmdbMovieInfo(tmdb_id, imdb_id, title, release_year)
* parse_movie_info(details, external_ids) — pure builder, parses
release_year from the first 4 chars of release_date (None on
missing/empty/non-numeric)
* TMDBClient.get_movie_info(tmdb_id) — aggregates
/movie/{id} + /movie/{id}/external_ids and feeds the parser
Tests cover happy path, missing/null/empty imdb_id, every
release_year edge (none/empty/short/non-numeric/missing key),
and the two required-field errors (id, title).