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.
51 lines
2.2 KiB
TypeScript
51 lines
2.2 KiB
TypeScript
import { compareText } from "./collate";
|
|
import { serverOrderLang } from "./saveLanguage";
|
|
|
|
// The channel manager's list order, and the priority steps its menu offers.
|
|
|
|
/** The steps a channel's menu offers (owner, 2026-09-26): fixed levels, so bubbling a channel up
|
|
* the list is one pick, not a run of +1 presses, and not straight to the top either. The row's
|
|
* stepper still sets any value, negatives included. */
|
|
const PRIORITY_STEPS: readonly number[] = [10, 5, 3, 2, 1, 0];
|
|
|
|
/** The steps to offer for a channel at `current`: the fixed ones, plus `current` itself in its
|
|
* place when it is off the scale (a 7, a -2) — the menu always shows, ticked, where it is now. */
|
|
export function priorityChoices(current: number): number[] {
|
|
return PRIORITY_STEPS.includes(current)
|
|
? [...PRIORITY_STEPS]
|
|
: [...PRIORITY_STEPS, current].sort((a, b) => b - a);
|
|
}
|
|
|
|
interface Ordered {
|
|
id: string;
|
|
priority: number;
|
|
title?: string | null;
|
|
}
|
|
|
|
/** The server's order (`routes/channels.py`: priority desc, then the title in the reader's alphabet —
|
|
* the ICU collation of `app/collation.py`, which `compareText` shares — a missing title last). */
|
|
function before(a: Ordered, b: Ordered, lang: string): boolean {
|
|
if (a.priority !== b.priority) return a.priority > b.priority;
|
|
if (a.title == null) return false;
|
|
if (b.title == null) return true;
|
|
return compareText(a.title, b.title, lang) < 0;
|
|
}
|
|
|
|
/** `rows` with the channel `id` taken out and put back where its priority now places it, every
|
|
* other row left exactly where it was — the server's order, without a refetch that would reorder
|
|
* anything the reader did not touch. It takes the account's `preferences`, not a language: the
|
|
* server sorts in the STORED language (`serverOrderLang`), which a UI language is not always. */
|
|
export function placeByPriority<T extends Ordered>(
|
|
rows: readonly T[],
|
|
id: string,
|
|
preferences: Record<string, unknown> | null | undefined,
|
|
): T[] {
|
|
const moved = rows.find((r) => r.id === id);
|
|
if (!moved) return [...rows];
|
|
const lang = serverOrderLang(preferences);
|
|
const rest = rows.filter((r) => r !== moved);
|
|
const at = rest.findIndex((r) => before(moved, r, lang));
|
|
rest.splice(at < 0 ? rest.length : at, 0, moved);
|
|
return rest;
|
|
}
|