02e478a157
Movie and Episode become @dataclass(frozen=True, eq=False), with audio_tracks/subtitle_tracks held as tuple[...] instead of list[...]. Identity-based equality is preserved via the existing __eq__/__hash__. __post_init__ coercion (imdb_id, title, season_number, episode_number) uses object.__setattr__ to stay compatible with frozen. The MediaWithTracks mixin contract is updated to tuple accordingly. Callers projecting enrichment results (probe output, file metadata) now rebuild via dataclasses.replace(...) — same pattern recently adopted for ParsedRelease. Season and TVShow stay mutable for now: freezing the aggregate root would cascade a full reconstruction on every add_episode, deferred.