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
+12 -12
View File
@@ -3,7 +3,7 @@ import { dispatch, useKeyScope } from "./keymap";
import { scrollParent } from "./listPaging";
import { focusIsUnclaimed } from "./useFocusKeeper";
// ── Keyboard navigation over lists and grids (E11 S4, UX-6) ──────────────────────────────────────
// ── Keyboard navigation over lists and grids (UX-6) ──────────────────────────────────────────────
// Before this, a feed card cost ~10 Tab stops (thumb, play, info, title, channel, five actions), so
// the tenth card sat ~135 Tabs from the top of the page. `j`/`k` step from ITEM to item instead, the
// arrows move around a grid, and Enter opens — the same thing a click on the item does.
@@ -17,10 +17,10 @@ import { focusIsUnclaimed } from "./useFocusKeeper";
// The Tab order is untouched: an item root is NOT a Tab stop. It gets `tabindex="-1"` at the moment
// the keyboard lands on it — one item at a time, the previous one gives it back — so Tab still walks
// the controls inside the cards, a mouse click on a card's blank area still focuses nothing, and the
// player's focus restore (E11 S2) can land back on the card it was opened from.
// player's focus restore can land back on the card it was opened from.
//
// Every page-level list shares ONE window listener, and the lists are walked in DOCUMENT order: `j`
// at the end of one list continues at the start of the next (owner decision D4, "reading order").
// at the end of one list continues at the start of the next (owner decision, "reading order").
// ←→ stay inside the list they are in; ↑ on a list's top row and ↓ on its bottom row go on to the
// neighbouring list — the rail above or below on Home and Discover — landing on the item nearest the
// one you left, so a column of rails reads like one grid.
@@ -50,7 +50,7 @@ const REVEAL_FRAMES = 10;
/** Spread onto an item's ROOT element. `name` is what a screen reader calls the item while the keyboard
* is on it (its title) — pass it where the element Enter opens wraps the whole card (a Plex poster:
* badges, year, rating and summary run together), shows a caption that is not the item's name, or
* holds no text at all (deep-review E11 round 3).
* holds no text at all.
*
* `inset` draws the keyboard ring INSIDE the item. The ring sits 2 px outside by default, which a
* card with a gap round it has room for; an item flush against its neighbours (a log line) or against
@@ -152,8 +152,8 @@ function onFocusIn(e: FocusEvent): void {
// for other content — like a click on <body>, which fires no focusin at all.
else if (focusIsUnclaimed(target)) return;
// Focus went on to page content that is not an item — the search box, a filter chip: the reader
// left the list, and whatever it shows next (new results) is not "the slot they were in" (deep-review
// E11 round 2). A layer opened FROM the item — its menu, a confirm, the Undo toast its removal put
// left the list, and whatever it shows next (new results) is not "the slot they were in".
// A layer opened FROM the item — its menu, a confirm, the Undo toast its removal put
// up — does not count: focus comes back from it, and what it did (a hidden card, a deleted row, the
// card put back) is what the slot is kept for. Removing the focused node itself fires no focusin.
else if (!target?.closest?.('[data-floating-ui-portal], [role="dialog"], [data-toast-region]'))
@@ -178,7 +178,7 @@ function slotOfRemoved(delta: 1 | -1): { list: NavList; index: number } | null {
}
/** What an item is called: its own name when it gives one (`navItemAttrs`), else the open element's
* label or text — a title link's text is the title (deep-review E11 round 3). */
* label or text — a title link's text is the title. */
function itemName(el: HTMLElement): string {
const open = el.querySelector("[data-nav-open]");
return (
@@ -203,7 +203,7 @@ function focusItem(el: HTMLElement, reveal = true): void {
roved = el;
// A card root is a plain <div>: focused, it has no role and no name, and a screen reader read it
// as an unlabelled run of text. While it holds the focus it is a group named after what Enter
// opens (deep-review E11 round 2). A row (<tr>) keeps its own role.
// opens. A row (<tr>) keeps its own role.
const name = itemName(el);
if (
el.tagName === "DIV" &&
@@ -386,7 +386,7 @@ function refocusSlot(list: NavList, index: number, removed: HTMLElement): void {
// ── The item a view was left from ────────────────────────────────────────────────────────────────
// Opening something that switches the page or the view — a Plex title from Home's rail, a channel from
// the Channels table — unmounts the list the keyboard was on, so Back used to hand focus to <body> and
// the next `j` started over at the top (E11 S5 UAT). The history entry being left remembers the
// the next `j` started over at the top (seen in UAT). The history entry being left remembers the
// position (lib/history `rememberNavPosition`) and Back gives focus back to that item once its list is
// on screen again. An overlay (the YouTube player) never unmounts the list; it restores focus itself.
@@ -440,7 +440,7 @@ function restoreTarget(list: NavList, pos: NavPosition): HTMLElement | null {
/** Focus the item at `pos` once its list is on screen again. A NAMED list (a rail) is found by its
* name: a rail that appeared above it in the meantime — "Continue watching", filled by the very title
* watched in between, after the page's cache expired — shifts every place after it, and matching by
* place landed the focus in the wrong rail (deep-review E11 round 2). An unnamed list only by its
* place landed the focus in the wrong rail. An unnamed list only by its
* place, and only once the page has exactly as many lists as when it was left: with more or fewer,
* list N may be another list, and <body> is the honest outcome. Gives up when the time is up, and at
* once when focus is already somewhere (the reader moved on, a dialog took it). The item is focused
@@ -469,8 +469,8 @@ export function restoreNavPosition(pos: NavPosition): () => void {
};
// Not inside the popstate dispatch that landed: a sub-view's own listener (`useHistorySubview`)
// may run after ours and has not switched the view yet — focus still sits in the view being left,
// and "focus is already somewhere" would give up for good (measured in Chrome, deep-review E11
// round 1: Plex show → Back left focus on <body>). One task later the view has rendered.
// and "focus is already somewhere" would give up for good (measured in Chrome:
// Plex show → Back left focus on <body>). One task later the view has rendered.
timer = setTimeout(attempt, 0);
return () => clearTimeout(timer);
}