de7030fa9c
Step 4 of specs/dot_alfred.md — rebuild a TVShow aggregate from disk
by reusing the existing release pipeline (inspect_release) on every
video file in a show folder, then persist via the .alfred repository.
- alfred/application/library/walker.py — pure structural walk
(season folders detected via \bS\d{1,2}\b regex, video files
filtered against kb.video_extensions, no recursion).
- alfred/application/library/rescan.py — orchestrator that ingests
each season folder, infers PACK vs EPISODIC from on-disk file
count + parser output, and assembles via TVShowBuilder. Episode
paths stored relative to show_root. Logs + skips corrupt input
(no season parsed, mixed season numbers, unparseable episodes).
- Season now inherits MediaWithTracks: PACK seasons carry
season-level audio_tracks / subtitle_tracks; EPISODIC seasons
leave them empty (tracks live per-episode). SeasonBuilder gains
set_audio_tracks / set_subtitle_tracks; bridge writes/reads them
in the PACK branch via shared _synth_* helpers.
Out of scope, tracked as tech debt: adjacent .srt capture, multi-
episode (episode_end), TMDB-driven PACK detection (the current
heuristic '1 file == PACK' is a placeholder until ShowTracker lands).
18 new tests (11 walker + 7 rescan integration) on tmp_path with
the Foundation layout. Full suite: 1149 passed.