fix(e5): deep-review round — combobox Enter, parse_person collision, enrich hardening + coverage
Full-epic /deep-review (11 finders + 12 adversarial verifiers) surfaced no HIGH; every mechanism finding calibrated to LOW on verification. Fix all 13: Correctness / reliability: - Combobox: Enter now commits the VISUALLY highlighted row (highlightIndex ?? activeIndex), not the bare keyboard activeIndex — so arrow-then-hover-then-Enter no longer toggles a different option than the one painted, and hover-with-no-arrow is no longer a silent no-op. - parse_person: dedup the known_for pool by (id, media_type), not the bare id — TMDB movie and tv id spaces are independent, so a same-id movie+show pair is two distinct credits (matches the collision-safe key the rest of the module already uses). - person-enrich: a per-person in-flight + 60s cooldown guard (people._should_schedule_enrich) dedups concurrent opens and rate-limits re-triggering while TMDB is degraded (a transient TmdbError leaves the watermark NULL), so bursts can't pile 8s tasks onto the shared threadpool. - PlexInfo compact()/money(): format with i18n.language (keeping currency USD) instead of a hardcoded en/en-US, matching the app's Intl convention. - delete the dead `plex.filter.add` i18n key (both locales) — the +Add button that used it is gone. Reuse: - _continue_watching reuses rollup.agg_subquery(include_resumed=True) + query.apply_show_state_filter instead of a third hand-inlined copy of the per-show rollup + in_progress predicate, so the Discover rail can't drift from the grid's definition. Test coverage (the gaps a regression would ship through): - resolve_library_guids scope-exclusion (a credit in a non-scoped/disabled library is dropped) + the []-vs-None distinction; parse_person cross-media-id retention; enrich_person transient (NULL watermark) and 404 (stamp) branches; _enrich_person_bg body (fresh session close/rollback, None-guard) + the cooldown dedup; continue_watching fully-watched-show exclusion; Combobox Enter-commits-highlighted + async/controlled-query mode; PopoverItem aria-checked contract; RatingsRow missing-IMDb + imdb==audience branches. Backend lane 413→420, FE vitest 351→357; all gates green. No migration.
This commit is contained in:
@@ -15,6 +15,7 @@ import {
|
||||
useDetailPrefs,
|
||||
} from "../lib/plexDetailUi";
|
||||
import { usePref } from "../lib/usePref";
|
||||
import i18n from "../i18n";
|
||||
import { Carousel } from "./Carousel";
|
||||
import PlexCollectionEditor from "./PlexCollectionEditor";
|
||||
import PlexPlaylistAdd from "./PlexPlaylistAdd";
|
||||
@@ -27,9 +28,13 @@ import PlexPlaylistAdd from "./PlexPlaylistAdd";
|
||||
// The TMDB-enriched pieces (multi-source ratings row, facts, keyword chips, full crew — E5 S5) render
|
||||
// on the page variant only; the overlay stays lean.
|
||||
|
||||
const compact = (n: number) => new Intl.NumberFormat("en", { notation: "compact" }).format(n);
|
||||
// Localize the grouping/compact notation to the active language (the app convention, lib/api/core.ts);
|
||||
// `i18n.language` is read at call time, and the component re-renders on a language switch. Currency stays
|
||||
// USD — TMDB budget/revenue figures are USD regardless of the viewer's language.
|
||||
const compact = (n: number) =>
|
||||
new Intl.NumberFormat(i18n.language, { notation: "compact" }).format(n);
|
||||
const money = (n: number) =>
|
||||
new Intl.NumberFormat("en-US", {
|
||||
new Intl.NumberFormat(i18n.language, {
|
||||
notation: "compact",
|
||||
style: "currency",
|
||||
currency: "USD",
|
||||
|
||||
Reference in New Issue
Block a user