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
+15 -15
View File
@@ -4,7 +4,7 @@ import { createStore } from "./store";
import type { Page } from "./urlState";
// ── The app's ONE keyboard map ────────────────────────────────────────────────────────────────
// Before E10 S3 six surfaces each owned a private `keydown` listener with its own key literals and
// Earlier, six surfaces each owned a private `keydown` listener with its own key literals and
// its own idea of "am I typing?" — and they had drifted: `PlexPlayer` matched `case "a"` without
// checking modifiers (so Ctrl+A, select-all, cycled the audio track) and its typing guard missed
// `<select>` and `contentEditable`, which the other two surfaces already covered. The classic
@@ -22,7 +22,7 @@ import type { Page } from "./urlState";
/** Which surface a shortcut belongs to. `global` is live app-wide; the rest only while that surface
* is mounted. The help sheet shows `global` plus the registered scopes.
*
* `page`, `search` and `list` are the PAGE-LEVEL scopes (E11 S4): they act on the page underneath
* `page`, `search` and `list` are the PAGE-LEVEL scopes: they act on the page underneath
* every overlay, so `dispatch` keeps them quiet while a layer that owns the keyboard is open. That is
* also what keeps them clear of the players' bare letters — the Plex player's `s` and `k` only ever
* run with the player's own layer up. */
@@ -78,7 +78,7 @@ export interface Shortcut {
// focused button reports `key === " "` inconsistently across engines). A SPACE separates the two
// steps of a sequence: `g h` is `g`, then `h` within SEQUENCE_MS.
//
// Owner rule (E11 D1): no new binding may need a modifier on the Hungarian QWERTZ layout — so no `/`
// Owner rule: no new binding may need a modifier on the Hungarian QWERTZ layout — so no `/`
// or `?` (both Shift chords there). Letters, digits, `-`, `,`, `.`, Esc/Enter/arrows only. `keyMatches`
// compares `e.key`, so a letter follows the printed legend (the HU Z/Y swap included).
export const SHORTCUTS = [
@@ -86,11 +86,11 @@ export const SHORTCUTS = [
// `h`, not `?`: on a Hungarian layout `?` is a Shift chord, and the one help key people already
// have in their fingers here is the Plex player's `h`. Making it app-wide costs no relearning.
// `allowInInput` because the palette AUTOFOCUSES its search field: without it the typing guard ate
// the second Mod+K, so the toggle only ever fired one way and Chrome took the chord instead
// (E10 review round 1). Its handler preventDefaults, so nothing leaks to the browser either way.
// the second Mod+K, so the toggle only ever fired one way and Chrome took the chord instead.
// Its handler preventDefaults, so nothing leaks to the browser either way.
{ id: "palette", scope: "global", keys: ["Mod+k"], labelKey: "keys.palette", allowInInput: true },
{ id: "help", scope: "global", keys: ["h"], labelKey: "keys.help" },
// Shift+W and not a bare `w` (E24): the Plex player binds bare letters (a s d f h i k m) and `w`
// Shift+W and not a bare `w`: the Plex player binds bare letters (a s d f h i k m) and `w`
// sits directly above `s`, so a blind reach for the subtitle key would yank you out of the film
// and onto the landing page. A chord makes it the deliberate "I'm stuck — answer the question".
{ id: "home", scope: "global", keys: ["Shift+w"], labelKey: "keys.home" },
@@ -143,7 +143,7 @@ export const SHORTCUTS = [
// --- the row context menu (wherever useContextMenu is wired) ---------------------------------
// Its OWN scope, not `global`: only the surfaces that actually call `useContextMenu` register it,
// so the sheet stops advertising "Open the context menu" on the feed, Plex, Downloads and Settings
// — where nothing answers the key (E10 review round 1). Same honest-states rule `plexBrowse` obeys.
// — where nothing answers the key. Same honest-states rule `plexBrowse` obeys.
{
id: "contextMenu",
scope: "contextMenu",
@@ -229,7 +229,7 @@ export type ShortcutId<S extends KeyScope> = Extract<
{ scope: S; handledLocally?: undefined }
>["id"];
/** True while focus sits somewhere that swallows plain keys. The ONE definition: before S3 the
/** True while focus sits somewhere that swallows plain keys. The ONE definition: before it the
* players disagreed about `<select>` and `contentEditable`, so the same keystroke was a shortcut in
* one and text in the other. Reads `e.target` (the focused node for a keydown) and falls back to
* `document.activeElement` for synthetic events that carry no target. */
@@ -272,11 +272,11 @@ export function matches(e: KeyboardEvent, chord: string): boolean {
* matched at the element level (Shift+F10 belongs to whichever row has focus, not to the window),
* but it must still go through `matches` or the table's `keys` become decoration. They had: the
* context menu hand-rolled `e.key === "F10" && e.shiftKey`, so Ctrl+Shift+F10 opened it too and
* editing the row changed the help sheet and nothing else (E10 review round 1).
* editing the row changed the help sheet and nothing else.
*
* Keyed on scope AND id, both as literal types: ids are only unique WITHIN a scope (`back` is on
* both players), so a bare `ROWS.find(s => s.id === id)` would answer for whichever came first, and
* a typo'd string would silently never match (round 2). */
* a typo'd string would silently never match. */
export function matchesShortcut<S extends KeyScope>(
e: KeyboardEvent,
scope: S,
@@ -306,7 +306,7 @@ function liveSequence(e: KeyboardEvent): typeof pending {
return null;
}
if (MODIFIER_KEYS.has(e.key)) return null;
// A chord with a modifier cannot be a second step (no binding may need one, D1): it abandons the
// A chord with a modifier cannot be a second step (no binding may need one): it abandons the
// sequence and is matched as itself, or `g` then Mod+K would open the browser's search, not ours.
if (e.ctrlKey || e.metaKey || e.altKey || e.shiftKey) {
pending = null;
@@ -332,7 +332,7 @@ export function dispatch<S extends KeyScope>(
if (sequenceEvents.has(e)) return false;
// A key a focused widget already handled is not a shortcut: every listener here is on `window`,
// so a tablist or a keyboard drag (dnd-kit, on the document) has acted on it and prevented its
// default first. The player's settings tabs switched tab AND sought the video 10 s (E28 UAT).
// default first. The player's settings tabs switched tab AND sought the video 10 s (seen in UAT).
if (e.defaultPrevented) return false;
// An Escape a layer already took (a menu that just closed) is spent: a page or a player reacting to
// it too is the double close the layer stack exists to prevent.
@@ -417,8 +417,8 @@ export function useActiveScopes(): KeyScope[] {
const stack = scopeStack.useValue();
// DEDUPED: a scope can be registered by more than one live component (the Playlists page and its
// rail each mount a `useContextMenu`), and `helpLines` appends a row's chords once per occurrence —
// so without this the sheet rendered "⇧ F10 Menu ⇧ F10 Menu" under a duplicated React key
// (E10 review round 2). Innermost registration wins the ordering.
// so without this the sheet rendered "⇧ F10 Menu ⇧ F10 Menu" under a duplicated React key.
// Innermost registration wins the ordering.
const live = [...new Set([...stack].reverse())];
// The page-level scopes go in a FIXED order after the surfaces, not in registration order: App
// registers `page` in its own effect, which React runs after every child's — so by mount order
@@ -474,7 +474,7 @@ export const usePaletteOpen = (): boolean => paletteOpen.useValue();
* `enabled` must track where those overlays (and the pages Shift+W jumps to) are actually MOUNTED.
* Bound unconditionally it swallowed `h` and Mod+K on the loading/Welcome/setup screens — the
* browser shortcut was preventDefault'ed, nothing appeared, and the flipped module-level store then
* popped the overlay open by itself the moment the signed-in shell mounted (E10 review round 1). */
* popped the overlay open by itself the moment the signed-in shell mounted. */
export function useGlobalKeymap(
enabled: boolean,
onNavigate: (page: Page) => void,