Files
siftlode/frontend/src/lib/releaseNotes.test.ts
T
peter 4aaaaa7860 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.
2026-10-05 00:19:39 +02:00

54 lines
2.4 KiB
TypeScript

import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
import en from "../content/release-notes/en.json";
import hu from "../content/release-notes/hu.json";
import { type ReleaseEntry } from "./releaseNotes";
const EN = en as ReleaseEntry[];
const HU = hu as ReleaseEntry[];
// DX-6: the app version is hand-maintained in two places that MUST agree — the repo-root VERSION file
// (the single source baked into the image + served at /api/version) and the newest release note
// (what the in-app "What's new" shows). A release that bumps one but forgets the other ships a wrong
// changelog or a mismatched banner. This locks them together so the gate catches the drift.
describe("release version consistency", () => {
it("the newest note's version matches the VERSION file", () => {
const version = readFileSync(new URL("../../../VERSION", import.meta.url), "utf-8").trim();
expect(EN[0]?.version).toBe(version);
});
it("release notes are ordered newest-first with unique versions", () => {
const versions = EN.map((r) => r.version);
expect(new Set(versions).size).toBe(versions.length);
const num = (v: string) => v.split(".").map(Number) as [number, number, number];
for (let i = 1; i < versions.length; i++) {
const [a, b] = [num(versions[i - 1]!), num(versions[i]!)];
const newer = a[0] - b[0] || a[1] - b[1] || a[2] - b[2];
expect(newer, `${versions[i - 1]} before ${versions[i]}`).toBeGreaterThan(0);
}
});
});
// Owner rule: internal work never ships on its own — it waits for a release a user can see. So the
// release being cut always says what changed for the user.
it("the newest release has something a user notices", () => {
expect(EN[0]!.new.length + EN[0]!.fixed.length).toBeGreaterThan(0);
});
// A note is a sentence or two (owner's call): the old paragraphs were what made the dialog slow and
// unread. The ceiling is generous for Hungarian, whose words run longer.
it("every item is short", () => {
const long = [...EN, ...HU].flatMap((r) =>
[...r.new, ...r.fixed].filter((s) => s.length > 260).map((s) => `${r.version}: ${s}`),
);
expect(long).toEqual([]);
});
it("the Hungarian notes are the English ones, item for item", () => {
const shape = (all: ReleaseEntry[]) =>
all.map((r) => [r.version, r.date, r.sha ?? "", r.new.length, r.fixed.length].join(" "));
expect(shape(HU)).toEqual(shape(EN));
});