chore(comments): drop epic, sprint and review-round ids from the code

The code cited its plan instead of saying why: `E28 review J4`, `(R6 S3b)`, `S1 justified…`,
`deep-review round 5`. That plan lives in the private ops repo, so for every reader of this one the
citation was noise, and a sentence whose subject was the plan step ("round 2 showed…") hid its
lesson behind an id. Each one is gone and the "why" kept: a bare citation is deleted, a sentence
carrying a lesson is reworded around it ("a later attempt showed…").

Measured (`scripts/audit_metrics.py`, product code): 652 lines in 270 files carried an epic code by
the definition the next commit holds (507 / 241 by the old, two-digit-only one) -> 0. Across all
code, tests, scripts and configs: ~1100 epic-code lines plus ~320 sprint/round ids.

Behaviour unchanged, checked mechanically: every changed .py file has the same AST once docstrings
are blanked; css/sh/toml/yml/json files are identical once comments are stripped; the only
non-comment changes in TS/JS are test titles, one description string in a contract table, and five
ESLint messages, whose text is all the gates snapshot diff holds. Not touched: Markdown (docs and
the changelog keep their history), Alembic migrations, TV episode notation (`S2 · E5`), DESIGN.md
ids (`C1`, `B4`, `S3h`), tracker ids (`SEC-16`, `DX-17`).

One stale claim fixed on the way: test_hls_reaper's docstring said the player checkpoints "every
10 s whether or not it is playing", which plex/stream.py calls wrong; it now says what the code does.
This commit is contained in:
2026-10-05 00:19:39 +02:00
parent c73d8be094
commit 4aaaaa7860
669 changed files with 1831 additions and 1904 deletions
+27 -28
View File
@@ -114,7 +114,7 @@ const PLAYER_MENU =
"rounded-xl border border-white/15 bg-media-chrome/95 text-sm text-white shadow-2xl";
const PLAYER_ROW = "block w-full rounded-lg px-2 py-1.5 text-left hover:bg-white/10";
// A track choice: the chosen one wears the tick in the leading slot (DESIGN "one of several"), which
// the highlight's white text cannot wash out the way it did the accent-coloured label (round 2, P6).
// the highlight's white text cannot wash out the way it did the accent-coloured label.
const TRACK_ROW =
"flex w-full min-h-9 items-center gap-2 rounded-lg px-2 py-1.5 text-left hover:bg-white/10";
const TAP_SKIP_S = 10;
@@ -139,12 +139,12 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
// rebuilt loadSession → re-ran the detail effect → reloaded the session from the STALE saved resume
// position (losing live progress). See the detail effect's deps.
const tRef = useLatest(t);
// E30: a track named in the reader's language (lib/vocab), not in the Plex server's ("English (AC3 5.1)").
// A track named in the reader's language (lib/vocab), not in the Plex server's ("English (AC3 5.1)").
const audioName = (a: PlexTrackNaming) => trackLabel(t, a, "audio", i18n.language);
const subtitleName = (x: PlexTrackNaming) => trackLabel(t, x, "subtitle", i18n.language);
const qc = useQueryClient();
const [id, setId] = useState(itemId);
// Serve the player's title/summary/rich detail in the active language (E5 S6), matching the grid.
// Serve the player's title/summary/rich detail in the active language, matching the grid.
const lang = plexLang(i18n.language);
const detailQ = useQuery({
queryKey: qk.plexItem(id, lang),
@@ -160,7 +160,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
const aliveRef = useRef(true);
const wrapRef = useRef<HTMLDivElement>(null);
// A control that goes while it holds the focus — Next onto the last item or a series finale —
// hands it to its neighbour instead of <body> (round 2, P5). The player is portaled outside the
// hands it to its neighbour instead of <body>. The player is portaled outside the
// page scroller, whose keeper does not watch it.
useFocusKeeper(wrapRef);
const sessionStartRef = useRef(0); // absolute offset the current HLS/direct session begins at
@@ -185,7 +185,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
// Whether the session being asked for plays once it can — null while none is out. Set from
// loadSession's `resumePlay` and then the viewer's to change: until the answer attaches, the media
// is the OUTGOING one, and a play() there sounded the old stream while the new one still attached
// paused (E28 review round 4). `said`: the viewer changed it, so it is what they now see.
// paused. `said`: the viewer changed it, so it is what they now see.
const pendingPlayRef = useRef<{ play: boolean; said?: boolean } | null>(null);
// The key of the last press that landed on faded bands, while it is held (see onKey).
const blindKeyRef = useRef<string | null>(null);
@@ -279,7 +279,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
videoRef,
});
// The pointer resting on either band holds the controls up (F22), and so does a keyboard focus in
// one (E6) — not the focus a click leaves on a button, which would pin the bar until the next click;
// one — not the focus a click leaves on a button, which would pin the bar until the next click;
// `:focus-visible` is the browser's own "this focus came from the keyboard". Both bands wear these.
const holdWhileHovered = {
"data-player-band": "", // what a key on a faded-out control is told apart by (onKey, below)
@@ -294,7 +294,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
// It renders inside the player, whose Tab trap spans it; the ⋯ counts as inside, since the ⋯ is
// what closes it (below).
useDismiss(menuOpen, () => setMenuOpen(false), [menuRef, menuTriggerRef]);
// The ⋯ and the tracks list are real menus on the popover engine (E28 review D3): roving arrows,
// The ⋯ and the tracks list are real menus on the popover engine: roving arrows,
// Home/End, Escape as a layer, and the focus back on the trigger however they close. They were
// hand-built <div>s — no roles, no arrows, and Escape left the focus on <body>. The engine portals
// them into the fullscreen element when there is one, so they show in fullscreen too.
@@ -335,8 +335,8 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
const helpOpen = useKeyboardHelpOpen();
const helpOpenRef = useLatest(helpOpen);
// On-screen confirmation for a KEYBOARD track switch. A/S have cycled audio and subtitles since
// E5, but silently — you changed the track and the only way to see what you landed on was to open
// On-screen confirmation for a KEYBOARD track switch. A/S have long cycled audio and
// subtitles, but silently — you changed the track and the only way to see what you landed on was to open
// the tracks menu, which is exactly the modal round-trip the shortcut exists to avoid. The menu
// itself needs no OSD: it shows the selection where you clicked.
const [osd, setOsd] = useState<string | null>(null);
@@ -358,7 +358,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
// "D" toggles the stats-for-nerds debug overlay (active mode, codec, dropped frames, buffer…).
const [statsOpen, setStatsOpen] = useState(false);
const statsOpenRef = useLatest(statsOpen);
// Up-next end-card: shown at episode end (with a next item) instead of an instant jump (S4).
// Up-next end-card: shown at episode end (with a next item) instead of an instant jump.
const [upNextOpen, setUpNextOpen] = useState(false);
const upNextOpenRef = useLatest(upNextOpen);
const upNextPrefRef = useLatest(prefs.upNext);
@@ -540,7 +540,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
// server also answers 404 for "that segment is not there YET" — indistinguishable from "the
// session is gone" on the wire — so a transcode that falls behind realtime, or two viewers of
// one item taking turns reclaiming its session, restarted ffmpeg forever behind a spinner
// that never became an error (deep-review round 5). A couple of reclaims is what a genuine
// that never became an error. A couple of reclaims is what a genuine
// reap needs; past that the honest answer is that playback failed.
hls.on(Hls.Events.ERROR, (_e, data) => {
// Fatal ones are what the user saw fail; the recoverable ones hls.js retries by itself
@@ -568,8 +568,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
// longer than half the window satisfied the reset on every second loss, so the budget
// never reached its bound and the reclaim loop it exists to end ran forever (measured:
// 200 losses 70s apart → 200 reclaims, never an error; 5s apart → 2 and an error, which
// is why the committed test, spacing its cases 0s and 10min apart, could not see it —
// deep-review round 7).
// is why the committed test, spacing its cases 0s and 10min apart, could not see it).
if (now - restartsRef.current.at > RECLAIM_WINDOW_MS) restartsRef.current.n = 0;
restartsRef.current.at = now;
if (restartsRef.current.n < MAX_SESSION_RECLAIMS) {
@@ -652,7 +651,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
// reconnect (Wi-Fi blips, the query is stale after 30 s and every checkpoint moved the position),
// the in-player info panel invalidates it after a watched toggle, a language switch fetches it
// again. Keyed on its identity, each of those restarted the film at the last saved checkpoint — or
// at 0 after marking it watched (deep-review round 4). The trade-off: a detail that was stale in
// at 0 after marking it watched. The trade-off: a detail that was stale in
// the cache when the player opened is not corrected by the refetch that follows; the player's own
// leave-patch (usePlexProgress) keeps the cache honest for everything played here.
const startedForRef = useRef<string | null>(null);
@@ -878,7 +877,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
if (otherId && otherId === id) {
// The item already playing (the info overlay's collection strip lists the film itself):
// nothing to switch to. The switch below would pause it and stop trusting its clock, and
// `setId` to the same id loads nothing — a frozen 0:00 (E28 review round 2, P1). The play
// `setId` to the same id loads nothing — a frozen 0:00. The play
// intent goes INTO the seek: a paused film whose session starts past 0 restarts the session,
// and a play() beside that resumed the outgoing stream while the new one stayed paused.
if (fromZero) seekTo(0, true);
@@ -927,7 +926,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
: detail?.next_id;
// Whether the row has a Next. An episode's next is in its detail, unknown while the next episode
// loads; the slot keeps its last answer meanwhile (a disabled Next), because the button unmounting
// took the focus that had just pressed it to <body> (E28 review E4). Adjusted during render.
// took the focus that had just pressed it to <body>. Adjusted during render.
const nextKnown = queue || !detailQ.isPending ? !!nextId : undefined;
const [nextSlot, setNextSlot] = useState(false);
if (nextKnown !== undefined && nextKnown !== nextSlot) setNextSlot(nextKnown);
@@ -952,7 +951,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
null,
);
// A tap that brings the bands back keeps them out of the pointer's way until a double-tap can no
// longer follow (E28 review E5): the second tap of a skip at the bottom would otherwise land on the
// longer follow: the second tap of a skip at the bottom would otherwise land on the
// band the first one just revealed — the seek bar, a seek to wherever the finger was.
const [tapShield, setTapShield] = useState(false);
const tapShieldTimer = useRef<number | undefined>(undefined);
@@ -1082,7 +1081,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
// the server refuses the mark, in which case `finish` takes itself back (see usePlexProgress).
finishProgress(watchedWrite);
// With a next item and the up-next pref on, surface the end-card (poster + countdown + Cancel)
// and let IT advance — binge stays in the viewer's control (S4/D6-A). The card only appears here,
// and let IT advance — binge stays in the viewer's control. The card only appears here,
// on play-to-the-end; credits-auto-skip advances earlier and this handler never fires for it.
if (nextId && upNextPrefRef.current) setUpNextOpen(true);
else if (nextId) go(nextId);
@@ -1145,7 +1144,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
// Its toast host's rank among open overlays (see ui/Toaster).
const overlayOrder = useOverlayOrder();
// This player is a dismissable layer: register it so a Modal or popover opened ABOVE it (its own
// settings/tracks menus included) takes Escape first and this player defers (R8 S3).
// settings/tracks menus included) takes Escape first and this player defers.
const layerIdRef = useRef<number | null>(null);
useEffect(() => {
const id = pushLayer();
@@ -1185,7 +1184,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
// Keyboard use also reveals the controls — but typing in a player field is not "using the
// remote", and `dispatch` still lets Escape through from inside a field (the only key that
// opts in), which is why this is a guard around `wake` rather than an early return.
// A slider is not a text field: its arrows are the remote too (E28 review E6).
// A slider is not a text field: its arrows are the remote too.
if (!isTypingTarget(e) || (e.target as Element | null)?.matches?.('input[type="range"]'))
wake();
if (swallow) {
@@ -1196,7 +1195,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
// The shared dialog Tab trap. This player paints an opaque full-viewport layer over the app,
// so Tab leaving it lands on a control nobody can see, where the ring is invisible and the
// next Enter fires something blind. Every other overlay in the tree traps (ui/Modal,
// PlayerModal, OnboardingWizard, Welcome); this one never did, and deep-review round 4 caught
// PlayerModal, OnboardingWizard, Welcome); this one never did, and a review caught
// it when the recorder's step prompt — which docks in this player's toast host — handed its
// own trap to "the dialog below" and found none. Only while nothing that owns the keyboard is
// layered above: a Modal opened over the player traps for itself. `wake()` above has already
@@ -1257,10 +1256,10 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
// Back button (shared cascade).
// Who owns ⌫ when something is open over the player. Modal stopPropagation()s Escape ONLY
// and its focused close button is not a typing target, so the key reaches us regardless.
// Two wrong answers so far: deferring to nothing at all (round 1's bug — the cheat sheet
// Two wrong answers so far: deferring to nothing at all (the first bug — the cheat sheet
// took ⌫ and the player stopped underneath it), then deferring to `anyLayerAbove` outright
// (round 1's fix, round 2's bug — the player's OWN gear/tracks popovers push layers too, so
// ⌫ stopped closing them), then naming just the sheet and palette (round 2's fix, round 3's
// (the first fix, the second bug — the player's OWN gear/tracks popovers push layers too, so
// ⌫ stopped closing them), then naming just the sheet and palette (the second fix, the third
// bug — the app-wide ErrorDialog is neither, so ⌫ tore the player down under it).
// The rule that holds: the player's own panels answer first, because `handleBack`'s cascade
// is what closes them; anything else layered above us takes the key.
@@ -1465,7 +1464,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
leaving the viewer to conclude that switching subtitles "does nothing" (bug hunt 2026-09,
item 8). A failure is said even over a mounted window (see `subNotice`). It sits one rung
above the track-switch OSD so the two never overlap. Both notices are `z-base`, under the
settings and tracks popovers (`z-menu`): an open menu is never drawn over (E28 audit). */}
settings and tracks popovers (`z-menu`): an open menu is never drawn over. */}
<div
className="pointer-events-none absolute inset-x-0 bottom-36 z-base flex justify-center px-4"
aria-live="polite"
@@ -1490,8 +1489,8 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
The REGION is always mounted and only the bubble is conditional: a polite region has to
pre-exist in the accessibility tree for a later insertion to be announced, so one created
together with its own first message is unreliably read — and since `osd` clears after 2.2s,
conditioning the wrapper re-created it for every switch, not just the first (E10 review
round 1). Toaster.tsx carries the same rule and the same shape. */}
conditioning the wrapper re-created it for every switch, not just the first.
Toaster.tsx carries the same rule and the same shape. */}
<div
className="pointer-events-none absolute inset-x-0 bottom-24 z-base flex justify-center px-4"
aria-live="polite"
@@ -1953,7 +1952,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
detail={detail}
variant="overlay"
onClose={() => setInfoOpen(false)}
// A collection sibling plays right here (E28 review D1), as Next would.
// A collection sibling plays right here, as Next would.
onPlayItem={(other, fromZero) => {
setInfoOpen(false);
go(other, undefined, fromZero);