The paged list handler eager-loaded nothing, so `ProjectToViewModel` read four
unloaded navigations and every row of every collection type projected a null
selection. Because the selected id and the display name are read off the SAME
navigation, this dropped the id too -- the harm is not an unlabelled badge but
an editor that round-trips a null and clears the user's stored selection.
The by-id handler loaded metadata for only four of the ten selectable media
types: Song/OtherVideo/Image/RemoteStream returned a null-ish selection and
Episode/MusicVideo threw an NRE that surfaced as a 500.
Fixed at the boundary rather than per call site:
- `RerunCollectionQueryExtensions.IncludeSelectionDetails()` is now the single
include chain, called by both handlers, joining the existing
`ProgramScheduleItemQueryExtensions.IncludeScheduleItemDetails()` precedent
(#229). Artwork legs are deliberately omitted -- this projection reads only
ids and titles.
- The media-item switch was duplicated verbatim for RerunCollection and
PlaylistItem; both now call one `ProjectMediaItemToViewModel`, which handles
`RemoteStream` (via a new `ProjectToNamedViewModel`, since the existing
`ProjectToViewModel(RemoteStream)` returns an unrelated type) and never falls
through to null -- an unknown subtype keeps its id and takes a conspicuous
name, because throwing would fail a whole paged GET over one bad row.
- Every metadata navigation in `MediaItems.Mapper` is now read through
`Optional(...).Flatten()`, so an un-included nav degrades to "???" instead of
being a latent 500 for whichever caller loads least.
Tests enumerate all 13 supported CollectionTypes for both handlers, with the
matrix derived from `IsSupportedSelectionType` so a newly-supported type joins
it automatically, plus a completeness guard on the set. Each mechanism was
removed in turn and confirmed red first.
fixes#671
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>