Files
siftlode/frontend/src/lib/reactEngine.contract.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

70 lines
3.4 KiB
TypeScript

import { readFileSync } from "node:fs";
import { expect, it } from "vitest";
// The third contract test, after `nodeEngine` and `pythonEngine`, and for the same reason: a version
// that is spelled in two places drifts, and the drift is silent until something downstream breaks.
//
// Here the two places are `package.json`'s React pin and `reactPlugin.ts`'s `target`, which tells
// babel-plugin-react-compiler which React runtime to emit memoisation against. The rule was first
// written as a comment — "`target` follows the installed React major and must move with it" — and
// the house rule this codebase was built on says a rule stated in a comment must also be enforced
// in code. So it is enforced here.
//
// The compiler does validate the option itself (an unknown target throws at build time), which
// bounds the damage: the failure mode is not a corrupt bundle but a STALE target — React moves to a
// new major and the compiler keeps emitting for the old one, with no lane saying so, because tsc
// never sees Babel's output.
//
// To move React: bump `react`, `react-dom` and `@types/react` in package.json, then follow this
// test's failures.
const readFrontend = (rel: string) =>
readFileSync(new URL(`../../${rel}`, import.meta.url), "utf8");
const pkg = JSON.parse(readFrontend("package.json")) as {
dependencies: Record<string, string>;
devDependencies: Record<string, string>;
};
/** The major in a version range, whether it is exact (`19.3.0`) or a caret (`^19.3.0`). */
function major(range: string, where: string): number {
const m = /^\D*(\d+)\./.exec(range);
expect(m, `could not read a major from ${where}: ${range}`).not.toBeNull();
return Number(m![1]);
}
const pinned = major(pkg.dependencies["react"]!, "react");
it("pins a plausible React major", () => {
expect(pinned).toBeGreaterThanOrEqual(19);
});
it("keeps react-dom on the same major as react", () => {
expect(major(pkg.dependencies["react-dom"]!, "react-dom")).toBe(pinned);
});
it("keeps the types on the same major as the runtime", () => {
// Types a major ahead of the runtime make tsc green over APIs the shipped React does not have.
expect(major(pkg.devDependencies["@types/react"]!, "@types/react")).toBe(pinned);
expect(major(pkg.devDependencies["@types/react-dom"]!, "@types/react-dom")).toBe(pinned);
});
it("compiles for the React that is actually installed", () => {
const src = readFrontend("reactPlugin.ts");
const m = /target:\s*"(\d+)"/.exec(src);
// A rename or a moved line lands here. Re-point the test — the contract did not go away with it.
expect(m, 'no `target: "<major>"` in reactPlugin.ts').not.toBeNull();
expect(
Number(m![1]),
`reactPlugin.ts compiles for React ${m![1]} while package.json pins ${pinned}. The React ` +
`Compiler emits against the runtime named by \`target\`; move it with the pin.`,
).toBe(pinned);
});
it("keeps react-i18next on a line that supports the pinned React", () => {
// The 14 line predates React 19: its <Trans> read `element.ref` (removed in 19) and its
// `withTranslation` types were built on the GLOBAL JSX namespace that @types/react 19 no longer
// declares — both latent only because this app happens to use neither export. 15 is the first
// line that handles both, so the floor is a real contract, not a tidiness preference.
expect(major(pkg.dependencies["react-i18next"]!, "react-i18next")).toBeGreaterThanOrEqual(15);
});