derive_series_status identified specials by looking the episode's
season up in a parallel seasons slice, so a caller passing an
incomplete slice silently reverted to pre-#118 behaviour. The season
number now rides on each episode and the slice is gone.
COMPLETE before the season tag was weak junk, so it stayed in
the title and exact-title matching failed silently (#135). It
now closes the boundary wherever it lands.
S01-S01 produced no claim because the dash-range branch required
last > season; a degenerate range is one season's pack, matching
the rule match_episode lifted.
In-library hits now read as whatever they are: movies open the release
deck as before, series hits render display-only until issue 129's detail
view gives them a link target, and an episode hit reads as its series
plus SxxEyy plus the episode title. TMDB results show TV alongside film,
and the add panel filters roots by kind; a series adds the one §4.1
add-time choice, auto_track, stated plainly: future seasons are tracked
automatically, past seasons are not.
Own route beside library and queues. Roots edit kind, audience, path
and their policy; policies get a form over the real fields — size
bands as number inputs, score and source weights as numbers,
resolution preference and audio/HDR rules as validated lists. Delete
arms before firing; a 409 from a referenced policy or occupied root
surfaces its message.
Policies and roots were editable only via SQL inside the container.
Full CRUD over both, validated against the vocabulary the policy
engine knows — unknown resolutions or sources answer 422 naming the
field, malformed JSON answers 422, deleting a referenced policy or an
occupied root answers 409. Closes#116 (API half).