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.
110 lines
4.3 KiB
TypeScript
110 lines
4.3 KiB
TypeScript
// @vitest-environment jsdom
|
|
//
|
|
// A scheduler job's result in the reader's language, through the REAL catalog. The server's own
|
|
// one-liner was "recent={'channels_processed': 0, …}, deep={…}" — English keys and a Python repr.
|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
import i18n, { setLanguage } from "../i18n";
|
|
import { jobFailureText, jobResultText, jobRunText, parseSummary } from "./jobResult";
|
|
|
|
afterEach(() => setLanguage("en"));
|
|
|
|
describe("a job's result", () => {
|
|
it("names each count, and a phase's own counts inside it", () => {
|
|
setLanguage("hu");
|
|
const t = i18n.getFixedT("hu");
|
|
expect(jobResultText(t, { new: 3, failed: 0 }, "hu")).toBe("új videó: 3 · sikertelen: 0");
|
|
expect(
|
|
jobResultText(
|
|
t,
|
|
{
|
|
recent: { channels_processed: 0, videos_added: 0, reason: "no service user" },
|
|
deep: { channels_processed: 2, videos_added: 5, reconciled_full: 1 },
|
|
},
|
|
"hu",
|
|
),
|
|
).toBe(
|
|
"friss (feldolgozott csatorna: 0 · hozzáadott videó: 0 · indok: nincs szolgáltatásfiók) · " +
|
|
"mély (feldolgozott csatorna: 2 · hozzáadott videó: 5 · teljesen egyeztetve: 1)",
|
|
);
|
|
});
|
|
|
|
it("names a skip reason; an upstream error stays its own text", () => {
|
|
const t = i18n.getFixedT("hu");
|
|
expect(jobResultText(t, { enriched: 0, skipped: "tmdb_api_key not set" }, "hu")).toBe(
|
|
"dúsítva: 0 · kihagyva: nincs TMDB API-kulcs",
|
|
);
|
|
expect(jobResultText(t, { error: "Plex returned 500" }, "hu")).toBe("hiba: Plex returned 500");
|
|
});
|
|
|
|
it("shows a key or word it does not know as it is, readable", () => {
|
|
const t = i18n.getFixedT("hu");
|
|
expect(jobResultText(t, { brand_new_count: 3, skipped: "moon is full" }, "hu")).toBe(
|
|
"brand new count: 3 · kihagyva: moon is full",
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("an older notice's one-liner", () => {
|
|
it("reads back into a result when flat", () => {
|
|
expect(parseSummary("new=403, failed=396, fallback=375")).toEqual({
|
|
new: 403,
|
|
failed: 396,
|
|
fallback: 375,
|
|
});
|
|
expect(parseSummary("enriched=0, skipped=tmdb_api_key not set")).toEqual({
|
|
enriched: 0,
|
|
skipped: "tmdb_api_key not set",
|
|
});
|
|
// enrich's bare count, as the server's `_result_data` names it
|
|
expect(parseSummary("42")).toEqual({ enriched: 42 });
|
|
});
|
|
|
|
it("does not when a phase is nested, or it is no summary at all", () => {
|
|
expect(parseSummary("recent={'channels_processed': 0}, deep={'videos_added': 1}")).toBeNull();
|
|
expect(parseSummary("sync paused")).toBeNull();
|
|
expect(parseSummary(null)).toBeNull();
|
|
});
|
|
});
|
|
|
|
// The audit log showed a failed RSS poll as the server's English sentence ("RSS poll failed for
|
|
// all 399 channels — first: …") under a Hungarian UI. A failure the job names rides along as data.
|
|
describe("a failed run", () => {
|
|
const run = {
|
|
job_id: "rss_poll",
|
|
status: "error",
|
|
summary:
|
|
"RSS poll failed for all 399 channels — first: UCx: RSS fetch for UCx returned HTTP 404",
|
|
result: { failure: "rss_all_failed", total: 1399, channel: "UCx", cause: "http_404", read: 0 },
|
|
};
|
|
|
|
it("says the failure the job named in the reader's language", () => {
|
|
const t = i18n.getFixedT("hu");
|
|
expect(jobRunText(t, run, "hu").body).toBe(
|
|
"Az RSS-hírcsatorna egyik csatornánál sem válaszolt (1399) — az első: UCx, HTTP 404. " +
|
|
"Az API-n át beolvasva helyette: 0.",
|
|
);
|
|
expect(jobFailureText(t, { ...run.result, cause: "transport" }, "hu")).toContain(
|
|
"UCx, nem érhető el.",
|
|
);
|
|
});
|
|
|
|
// The server raises it for an instance with one subscription too ("none of the 1 channels").
|
|
it("reads one channel as one, and keeps its stop", () => {
|
|
const t = i18n.getFixedT("en");
|
|
expect(jobFailureText(t, { ...run.result, total: 1 }, "en")).toBe(
|
|
"The RSS feed did not answer for the one channel, UCx: HTTP 404. Read through the API instead: 0.",
|
|
);
|
|
expect(jobFailureText(t, run.result, "en")).toMatch(
|
|
/^The RSS feed answered for none of the 1,399 channels .*: 0\.$/,
|
|
);
|
|
});
|
|
|
|
it("keeps any other failure's own text", () => {
|
|
const t = i18n.getFixedT("hu");
|
|
expect(jobRunText(t, { ...run, summary: "Plex returned 500", result: null }, "hu").body).toBe(
|
|
"Plex returned 500",
|
|
);
|
|
expect(jobFailureText(t, { failure: "moon_is_full" }, "hu")).toBeNull();
|
|
});
|
|
});
|