A recursive listing over a box set comes back in a different order #133
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Measured during #111 on a box set holding one row from each of three libraries. Identical before and after that change, so it belongs to neither it nor #91 — it looks like the set's own stored order against the query's ordering.
Upstream keeps what a collection was given in
LinkedChildren, and M9 settled that a playlist's contents are that table rather thanAncestorIds. So the likely rule is that a set's contents come back in the order the set holds them unless the request asks otherwise, which is the same shape asidsreturning rows in the order they were named (fixed in #91 fromFolder.GetItems:996-1008).No scenario covers it, and #130 currently makes it awkward to measure: this server's startup scan deletes box-set rows, so a pair has to be arranged with no libraries configured.
Where to start
crates/jellyfin-http/src/routes/items.rs's linked-contents branch, and whatevercrates/jellyfin-dbdoes withLinkedChildrenordering. Upstream:Folder.GetChildrenand theBoxSet/Playlistoverrides.Check the playlist case in the same pass — a playlist is the same table and a user-ordered one is far more likely to be noticed out of order than a box set is.
How to know it is done
The listing above agrees, for a box set and for a playlist, and a scenario carries both.
House rules
Tests run under
cargo nextest; upstream's source is the checkout inupstream/at the pin; generated artifacts are regenerated, never edited — a failing corpus case is the port disagreeing with upstream, not the corpus being wrong. Comments say what the code does, not how it got there. The shared reference on:8096is read-only; anything needing a write wants its own container from the pinned image.Done, on
main. Four cases, not one.BoxSet.cs:26defaultsDisplayOrdertoPremiereDateand:118falls back to it; a recursive listing goes throughQueryRecursive→GetItemsResult, whose default isOrderBy(SortName);Playlist.GetChildrenkeeps link order. We answered link order for all four.The committed fixture cannot tell two of these apart — its three rows order identically under premiere date and sort name — so the reviewer built a box set whose two orders differ and measured on that. All four hold.
It also forced a real fix in the shared sort table: upstream's
PremiereDatecoalesces withProductionYear, on both the SQL path (OrderMapper.cs:76) and the in-memory one (PremiereDateComparer.GetDate), where ours read the bare column. The fixture's rows carry no premiere date at all and still order 2020 → 2021 → 2022.A collection's stored
DisplayOrderis read now rather than assumed:Defaultleaves the set in its own order, a name we map sorts by it, and anything else — including the empty value every set made before upstream began writing the field carries — falls back to the premiere date.The batch this closed in
Seven issues went out together because they looked like one defect class. They turned out to be three roots:
/Items'Paramshad been grown one client at a time instead of held against upstream's controller signature, and/UserItems/Resumeshared it.sortBy=Namemaps toCleanNameupstream, notSortName, and a by-name search orders by relevance with no sort-name tiebreak, so ties fall out in id order.PremiereDatecoalesces withProductionYearwhere ours read the bare column.A reviewer re-derived the parameter audit mechanically — extracting every
[FromQuery]name fromGetItemsand doing set arithmetic against what we bind — and got nothing bound that upstream does not take and nothing in the register that is not an upstream parameter. This class is closed rather than narrowed, which matters because it had been found three times.Verified on a restored pair:
browsing34 → 0,items33 requests at 0,clients56 → 3,portable115 → 6.JELLYFIN_RS_REQUIRE_FIXTURES=1 cargo nextest run --workspace: 2228 passed, 0 skipped. Clippy clean. No ignore-list entry was added or touched.Two things the review caught that the batch had not
Five of the ten new scenario entries could not fail. The
defaultsnapshot has no genres, studios or tags, so fiveitems.jsonentries compared two empty pages — reverting the whole fix would still have replayed clean. They moved intoediting.json, after the save that gives one film a genre, a tag, a certificate and a studio and then takes them away, so each selects one row out of nineteen. That is the fifth time this session the same failure has turned up in a different layer, after M5's vacuous scenarios, M8'sbundle.json, #111's all-refusalsvisibility.jsonand #137's silently-skipping tests.Reading the reference can write to it.
Studios=,Artists=andAlbums=resolve through upstream'sGetStudio/GetArtist, which callCreateItemByName— so a read files aBaseItemsrow. That is how a strayBrandywine Productionsgot into the shared fixture mid-session and madeportable.jsondisagree by 149.Genres,TagsandOfficialRatingsnarrow throughItemValuesand are safe. Both halves are now written intocrates/jellyfin-harness/README.md.