docs(changelog): Phase 4 Step 5 — record dot_alfred v2 Phase 4 work

Append Phase 4 entry under [Unreleased]:
* Added: rescan_show v2 signature + new rescan_movie + PACK empty-
  episodes semantics + Settings.tmdb_cache_ttl_days + library-index
  anchor-mismatch warning
* Removed: v1 dot_alfred stack (bridge/repository/serializer/sidecar),
  abstract domain ports (TVShowRepository / MovieRepository),
  application/library/ package, two Phase-3 quarantine test files
* Internal: 1233 → 1237 passing, 10 → 8 skips; MediaWithTracks
  mixin parked for Phase 5

Phase 3 entries left intact (historically accurate at commit time).
This commit is contained in:
2026-05-25 21:17:23 +02:00
parent cc334a7951
commit fe9857aaed
+63
View File
@@ -15,6 +15,69 @@ callers).
## [Unreleased] ## [Unreleased]
### Added
- **`.alfred` v2 — Phase 4: v2-shaped `rescan_show` + new
`rescan_movie` + index anchor-warning + `tmdb_cache_ttl_days`
setting.** Fourth and final structural phase of
`specs/dot_alfred_v2.md` on branch `refactor/dot-alfred-v2`. The TV
+ movie rescan orchestrators now write v2 release aggregates
(`SeriesRelease` / `MovieRelease`) via the concrete v2
repositories; the library index keeps auto-healing from the new
sidecars on its next read (no TMDB call from rescan — that stays
Phase 5).
- **`rescan_show`** moves from `alfred/application/library/` to
`alfred/application/tv_shows/` (symmetry with the new
`alfred/application/movies/`). New signature:
`(show_root, *, tmdb_id: TmdbId, imdb_id: ImdbId | None = None,
series_repo, scanner, prober, kb) -> SeriesRelease`.
- **`rescan_movie`** (new — `alfred/application/movies/rescan.py`)
locates the main video via `find_video_file`, runs
`inspect_release` once, and writes the per-movie `.alfred`
sidecar. `added_at = datetime.now(UTC)` on every rescan (the
sidecar records reconciliation time, not filesystem mtime).
Raises `MovieRescanFailed` when no video is found in the folder.
- **PACK semantics in `rescan_show`**: a single-video + no-episode
season becomes `SeasonRelease(mode=PACK, folder=…, episodes=())`.
The slot map stays empty until the Phase 5 TMDB sync supplies
`episode_count` — no fabricated `EpisodeRange` lands in the
sidecar.
- **`Settings.tmdb_cache_ttl_days: int = 14`** — placeholder for the
Phase 5 TTL policy on library-index entries (`fetched_at + TTL`
drives refresh decisions).
- **Library-index anchor-mismatch warning** — both
`DotAlfredTVShowLibraryIndex` and `DotAlfredMovieLibraryIndex` now
cross-check each entry's `metadata.path` against the on-disk
folder layout right after a successful parse. Drift is logged as a
`WARNING` (one per missing folder, with `tmdb_id`); the heal path
stays silent by construction (it always synthesizes from real
folder names).
### Removed
- **v1 dot_alfred stack and its abstract domain ports.** Deleted
`alfred/infrastructure/persistence/dot_alfred/{bridge,repository,
serializer,sidecar}.py`, plus the
`alfred/domain/{tv_shows,movies}/repositories.py` ABCs
(`TVShowRepository` / `MovieRepository`) — zero callers after
Phase 4. `dot_alfred/__init__.py` is rewritten as a v2-only
re-export (four concrete repositories + `ShowFolderUnknown`).
- **`alfred/application/library/` package** (rescan + walker moved
to `alfred/application/tv_shows/`).
- The two Phase 3 module-level test skips
(`test_repository.py`, `test_serializer.py`) are lifted by
deleting the quarantined files.
### Internal
- **Suite**: 1233 → 1237 passing; 10 → 8 skips (only LLM-not-running
skips remain — the Phase 3 quarantines are gone with their files).
- The `MediaWithTracks` mixin in `alfred.domain.shared.media` is
orphaned after Phase 3 (no aggregate inherits it). **Parked for
Phase 5**, which will either mount it on `MovieRelease` /
`SeasonRelease` (both already carry `audio_tracks` +
`subtitle_tracks`) or remove it for good.
### Changed ### Changed
- **`.alfred` v2 — Phase 3: `TVShow` / `Movie` aggregates become - **`.alfred` v2 — Phase 3: `TVShow` / `Movie` aggregates become