No search hint is ever a person #139

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

/Search/Hints returns a Person hint upstream and never here.

Measured while reviewing #128: GET /Search/Hints?SearchTerm=e returns Sine Ensemble twice from upstream — once as the MusicArtist and once as the Person — and once from us. It hits every account including the administrator, so it is a missing hint kind rather than anything to do with visibility.

It has a practical cost beyond the row: a scenario naming SearchTerm=e cannot be added to visibility.json without an ignore entry, because this difference fires for every account. #128's unrated entries had to use SearchTerm=t to route around it.

Where to start

crates/jellyfin-http/src/routes/library/discover.rs and whatever builds a hint. Upstream's search returns people alongside items; the port's candidate set does not include them.

Worth checking in the same pass: which other hint kinds upstream can return that this port never produces — the same measurement that found the person will find those, and one issue covering the set is better than four covering one each.

How to know it is done

/Search/Hints returns the same kinds upstream returns for the same term, and visibility.json can carry a SearchTerm=e entry without an ignore entry — which is the check that this is really closed.

House rules

Tests run under cargo nextest; upstream's source is the checkout in upstream/ at the pin; generated artifacts are regenerated, never edited; comments say what the code does, not how it got there. The reference on :8096 is read-only — and Studios=, Artists= and Albums= are writes, because upstream resolves them through CreateItemByName. Anything needing a write gets its own container from the pinned image over a cp -a copy of a snapshot. Kill a server by the PID ss -lntpH 'sport = :NNNN' reports; never pkill, killall, or pgrep -f with a pattern your own command line contains.

`/Search/Hints` returns a `Person` hint upstream and never here. Measured while reviewing #128: `GET /Search/Hints?SearchTerm=e` returns `Sine Ensemble` **twice** from upstream — once as the `MusicArtist` and once as the `Person` — and once from us. It hits every account including the administrator, so it is a missing hint kind rather than anything to do with visibility. It has a practical cost beyond the row: a scenario naming `SearchTerm=e` cannot be added to `visibility.json` without an ignore entry, because this difference fires for every account. #128's `unrated` entries had to use `SearchTerm=t` to route around it. ## Where to start `crates/jellyfin-http/src/routes/library/discover.rs` and whatever builds a hint. Upstream's search returns people alongside items; the port's candidate set does not include them. Worth checking in the same pass: which other hint kinds upstream can return that this port never produces — the same measurement that found the person will find those, and one issue covering the set is better than four covering one each. ## How to know it is done `/Search/Hints` returns the same kinds upstream returns for the same term, and `visibility.json` can carry a `SearchTerm=e` entry without an ignore entry — which is the check that this is really closed. ### House rules Tests run under `cargo nextest`; upstream's source is the checkout in `upstream/` **at the pin**; generated artifacts are regenerated, never edited; comments say what the code does, not how it got there. The reference on `:8096` is read-only — and `Studios=`, `Artists=` and `Albums=` are *writes*, because upstream resolves them through `CreateItemByName`. Anything needing a write gets its own container from the pinned image over a `cp -a` copy of a snapshot. Kill a server by the PID `ss -lntpH 'sport = :NNNN'` reports; never `pkill`, `killall`, or `pgrep -f` with a pattern your own command line contains.
alex closed this issue 2026-08-16 09:28:23 +02:00
Author
Collaborator

Closed by 149c0e5, with d4891ba for what the review found.

A by-name row belongs to no library, so it carries no TopParentId — and a
query narrowed to the caller's libraries matches on exactly that column. Ported
upstream's IncludeItemsByName exemption into the query builder, with the
second pass an account that restricts anything is held to: a name is offered
only while something behind it is in reach, through Peoples/PeopleBaseItemMap
for a person and ItemValues/ItemValuesMap for the other four.

The wider question the issue asked for. Two more kinds of gap, both fixed:

  • The include* flags cut both ways. includePeople=false left the person in,
    because the port read those flags only on the branch that turns media off.
  • An all-zero parentId — which upstream binds as Guid? and reads as no
    parent — dropped every by-name hint. Found by the review; the port was
    testing the string rather than the guid, while the narrowing two functions
    away already read it upstream's way.

And one the review turned up that the fix itself introduced: a listing narrowed
to an empty set of libraries is given an id no row carries, and the exemption
read that as a place — so an empty box set asked for people would have answered
with every person on the server. Upstream answers nothing; measured.

Measured on the pair, as the administrator and as both restricted accounts:
ten forms of the request that disagreed now agree, including includeMedia=false
and a parentId naming a real library. visibility.json asks SearchTerm=e for
the account that had to route around this, and SearchTerm=t was re-measured to
confirm the change was tidying rather than a walk-around.

Closed by `149c0e5`, with `d4891ba` for what the review found. **A by-name row belongs to no library**, so it carries no `TopParentId` — and a query narrowed to the caller's libraries matches on exactly that column. Ported upstream's `IncludeItemsByName` exemption into the query builder, with the second pass an account that restricts anything is held to: a name is offered only while something behind it is in reach, through `Peoples`/`PeopleBaseItemMap` for a person and `ItemValues`/`ItemValuesMap` for the other four. **The wider question the issue asked for.** Two more kinds of gap, both fixed: - The `include*` flags cut both ways. `includePeople=false` left the person in, because the port read those flags only on the branch that turns media off. - An all-zero `parentId` — which upstream binds as `Guid?` and reads as *no* parent — dropped every by-name hint. Found by the review; the port was testing the string rather than the guid, while the narrowing two functions away already read it upstream's way. And one the review turned up that the fix itself introduced: a listing narrowed to an *empty* set of libraries is given an id no row carries, and the exemption read that as a place — so an empty box set asked for people would have answered with every person on the server. Upstream answers nothing; measured. **Measured** on the pair, as the administrator and as both restricted accounts: ten forms of the request that disagreed now agree, including `includeMedia=false` and a `parentId` naming a real library. `visibility.json` asks `SearchTerm=e` for the account that had to route around this, and `SearchTerm=t` was re-measured to confirm the change was tidying rather than a walk-around.
Sign in to join this conversation.
No description provided.