Commit Graph
3 Commits
Author SHA1 Message Date
peter 13fb2b4e61 refactor(e5): deferred review-tail (backend) — enrich off request path, reuse, tests
Address the deep-review's deferred backend items so E5 is review-complete:

- person-enrich OFF the request path (ABUSE finding): person_detail no longer makes
  the TMDB call inline (even bounded to 8s it sat on the serve thread, un-throttled,
  demo-reachable — it violated the module's "no live TMDB call at serve time"
  invariant). It now schedules a FastAPI BackgroundTask (people._enrich_person_bg,
  fresh session, best-effort) after the response; the first open serves the row as-is
  and the bio lands by the next open. The inline try/rollback recovery is gone with it.

- reuse: a shared tmdb.resolve_library_guids owns the collision-safe guid→library
  bucketing (movie vs tv ids are independent sequences) that resolve_recs and
  people._resolve_known_for each hand-duplicated; a new rollup.item_state_map dedups
  the "PlexState-by-item_id" fetch across the person + discover paths.

- test gaps: enrich_batch transient TmdbError leaves the watermark NULL to retry;
  guid_to_tmdb_id resolves a tvdb source + tv media_type via /find's tv_results;
  _continue_watching includes a NULL-status started movie and excludes a hidden one;
  /api/search/youtube returns 422 (not 5xx) when ingest fails (route-level, B-core-1).

Backend lane 403 → 413, ruff clean. No migration; serve contracts unchanged.
2026-08-21 06:09:17 +02:00
peter 0c746f5bcd fix(e5): deep-review survivors — TMDB key log leak, person-enrich rollback + timeout
Three verified deep-review findings (the 4th, the filter combobox a11y gap, is
deferred to a dedicated session on the combobox architecture):

- SEC (medium): TmdbClient sent the api_key as a URL query param, so an HTTP
  error's httpx exception string embedded the full URL incl. the key, which
  enrich_batch logged. _get now raises status+path only (never str(e)/the URL)
  and severs the secret-bearing cause with `from None`. Regression test asserts
  neither the status nor the network error path contains the key.
- STATE (low): person_detail's lazy-enrich except now db.rollback()s, so a
  failed enrich_person commit can't poison the session and 500 the subsequent
  SELECTs (SQLAlchemy 2.x deactivates the tx on a commit-time flush failure and
  does not auto-reset it). Test locks that the page renders despite a poisoned
  enrich.
- ABUSE (low): the request-path lazy person enrich now caps its TMDB client at
  an 8s timeout (was the 30s default) so a slow TMDB can't tie up a worker;
  TmdbClient gained a `timeout` param (batch keeps 30s). The fuller fix (move
  person enrichment off the request path) is logged for later.
2026-08-21 04:42:07 +02:00
peter 187b8007f8 E5 S6: enriched person page (TMDB bio + birth facts + Known-for rail)
The person page now leads with a TMDB bio, lazily fetched the first time it's
opened (off the S2-linked `tmdb_person_id`) and then served from the row:

- Migration 0072: ADD-only nullable person columns on plex_people — biography,
  birthday, deathday, place_of_birth, known_for_department, also_known_as,
  known_for ([{tmdb_id, media_type, title}]), tmdb_enriched_at.
- tmdb.py: TmdbClient.fetch_person (/person/{id}+combined_credits), parse_person
  (bio + a popularity-ranked, deduped known_for), apply_person, enrich_person
  (lazy one-shot, key+id guarded, commits, 404 stamps the watermark).
- people.py person_detail: loads the full person row, lazily enriches (best-effort
  — never fails the page), serves the bio fields + resolves known_for to library
  rows by guid (in-library only, popularity order).
- FE PlexPersonView: bio/birth-facts/aka hero + a "Known for" Carousel rail above
  the existing Movies/Shows filmography; PlexPersonDetail type + i18n (en+hu).

Tests: test_plex_person_bio.py (6: parse / lazy-enrich guards / serve) + extended
PlexPersonView.dom.test.tsx + the unknown-name contract in test_plex_person.py.
Browser-E2E'd on Jim Carrey (live TMDB enrich → bio 1937 chars, born 1962-01-17
Newmarket, Known-for resolved). Gate: vitest 337, backend lane 402.
2026-08-21 00:08:19 +02:00