Cold independent review of 017ef988d. Three findings taken, one filed out.
The important one is a regression this branch INTRODUCED. `SongMetadata.Artists`
is a nullable EF primitive collection (JSON in one column, not a navigation)
that FallbackMetadataProvider leaves unassigned when a song's tags fail to read,
and `string.Join` throws ArgumentNullException on a null sequence. The rerun
list previously did not load SongMetadata at all, so the throw was unreachable
there; adding the include promoted it to a live 500 that would have failed the
whole page. Confirmed by reverting the guard: ArgumentNullException, parameter
'values'. The file header claiming every member was guarded was false.
The empty case is filtered too, so an artist-less song loses its bare " - ".
Second: `GetPlaylistItemsHandler` had no handler-level test at all (its
controller tests stub the mediator), so the RemoteStream include added last
round was discharged by inspection -- the same method that produced #671. It
now runs the same 13-type matrix via a shared SelectionSeedData; removing the
include fails that matrix.
Third: dropped the dead `(i as Season).SeasonMetadata` include leg -- the Season
projection reads Show.ShowMetadata and the scalar SeasonNumber, never
SeasonMetadata.
Filed #690 for the pre-existing, out-of-scope finding: the paged TotalCount
ignores the search query, so the SPA renders empty pages.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Cross-family (Codex) adversarial review of 8523088ce. All three findings taken:
- The name assertion only checked "not a placeholder", so it could not see a
missing NESTED include leg: dropping Episode -> Season -> Show still renders
"s00e04 - Selected episode", which contains no placeholder marker and passed.
Now every type pins its whole expected string; re-removing that leg fails, as
verified before restoring it.
- Widening the shared switch with a RemoteStream arm put `GetPlaylistItemsHandler`
one include short -- it loaded metadata for the other nine types, so playlist
RemoteStream names alone would have degraded to "???".
- `?? 0` rendered an unloaded Season as "s00", which conventionally means
Specials and so fabricated plausible-looking real data; it now renders "s??".
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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>