Genres and MusicGenres both answer with every genre #52

Closed
opened 2026-08-03 22:33:30 +02:00 by Claude · 1 comment
Collaborator

/Genres and /MusicGenres both answer with every genre in the library.

Over a production library:

route upstream ours
/Genres 45 172
/MusicGenres 138 172

Upstream keeps the two apart — a film's genres and a track's are different
items, and only ten names appear in both. This server answers each route with
what looks like the union of the pair, so /Genres leads with 52, Acid and
Acid Techno, and /MusicGenres offers Action & Adventure and Anime.

A client showing genre filters on a movie library is offered music genres that
match nothing there, and the other way round.

The reference library's genres barely overlap the two kinds, which is why
answering both from one list has passed so far.

`/Genres` and `/MusicGenres` both answer with every genre in the library. Over a production library: | route | upstream | ours | |---|---|---| | `/Genres` | 45 | **172** | | `/MusicGenres` | 138 | **172** | Upstream keeps the two apart — a film's genres and a track's are different items, and only ten names appear in both. This server answers each route with what looks like the union of the pair, so `/Genres` leads with `52`, `Acid` and `Acid Techno`, and `/MusicGenres` offers `Action & Adventure` and `Anime`. A client showing genre filters on a movie library is offered music genres that match nothing there, and the other way round. The reference library's genres barely overlap the two kinds, which is why answering both from one list has passed so far.
Author
Collaborator

Both issues were one cause, and it was not the scanner: both servers read copies
of the same upstream-written database, so how a name is split never came into it.

The by-name listings walked ItemValues and grouped by CleanValue. Upstream
queries BaseItems (BaseItemRepository.ByName.cs, GetItemValues): rows of
the item type the route names, one per PresentationUniqueKey, whose
CleanName matches a value of the given type in reach.

  • #52 — one value type, two item types. Genre and MusicGenre are
    different rows over the same values, and GenresController switches to the
    music kind when the parent is a music library. Neither was done here.
  • #53 — Fall Out Boy / Fall Out Boy and Scooter & Harris & Ford /
    Scooter, Harris & Ford are two rows each sharing one folded name. Grouping
    by clean value collapsed each pair; upstream lists both.

Measured over one production database, both servers, identical ordering as well
as counts:

route before after upstream
/Genres 172 46 46
/MusicGenres 172 142 142
/Artists/AlbumArtists 98 100 100
/Artists 181 183 183
/Studios 813 827 827

/Items/Filters2 picks the genre kind the same way and reads the same listing.

Two things worth recording. Upstream answers these from rows alone and returns
nothing where a scan never created them; this server's scan writes no
Genre/MusicGenre/Studio rows at all, so the derive-from-values fallback is
kept for names no row stands for, now under upstream's own owner-type rule. On
any database upstream scanned the fallback adds nothing — measured, zero orphan
values across all five listings. That this port's scan has no validator
equivalent is a real gap
, and is filed separately.

MILESTONES.md says a by-name item is never a row here, which is no longer
true.

Both issues were one cause, and it was not the scanner: both servers read copies of the same upstream-written database, so how a name is split never came into it. The by-name listings walked `ItemValues` and grouped by `CleanValue`. Upstream queries `BaseItems` (`BaseItemRepository.ByName.cs`, `GetItemValues`): rows of the *item type* the route names, one per `PresentationUniqueKey`, whose `CleanName` matches a value of the given type in reach. - **#52** — one value type, two item types. `Genre` and `MusicGenre` are different rows over the same values, and `GenresController` switches to the music kind when the parent is a music library. Neither was done here. - **#53** — `Fall Out Boy` / `Fall Out Boy ` and `Scooter & Harris & Ford` / `Scooter, Harris & Ford` are two rows each sharing one folded name. Grouping by clean value collapsed each pair; upstream lists both. Measured over one production database, both servers, identical ordering as well as counts: | route | before | after | upstream | |---|---|---|---| | `/Genres` | 172 | **46** | 46 | | `/MusicGenres` | 172 | **142** | 142 | | `/Artists/AlbumArtists` | 98 | **100** | 100 | | `/Artists` | 181 | **183** | 183 | | `/Studios` | 813 | **827** | 827 | `/Items/Filters2` picks the genre kind the same way and reads the same listing. Two things worth recording. Upstream answers these from rows alone and returns nothing where a scan never created them; this server's scan writes no `Genre`/`MusicGenre`/`Studio` rows at all, so the derive-from-values fallback is kept for names no row stands for, now under upstream's own owner-type rule. On any database upstream scanned the fallback adds nothing — measured, zero orphan values across all five listings. **That this port's scan has no validator equivalent is a real gap**, and is filed separately. `MILESTONES.md` says a by-name item is never a row here, which is no longer true.
Sign in to join this conversation.
No description provided.