3542d6f717
Both blockers from the adversarial review of #83, both in the mode this PR rewrote, both producing a pass while the gate did not do what its prose said. 1. cargo_test_names reduced every listed path to its last segment. Six leaf names collide in this workspace and two are cited in evidence, so a heading was satisfiable by a test in another module answering another question -- renaming ui::project::tests::a_load_that_fails_is_not_a_rebase, the one its entry describes, left the checker at exit 0 with the ui::host namesake answering for it. Paths are kept whole; a bare leaf resolves only when unique, and an ambiguous one is REFUSED with both candidates named. _RUST_NAME accepts `::`, so a qualified heading is a claim rather than prose, and a citation is matched on the leaf so qualifying a heading cannot orphan its own test. The two colliding entries are qualified. Neither half suffices alone: rename one of a colliding pair and the leaf becomes unique again, which is why qualification is the fix and the refusal is what forces it. 2. --rust-tests called cargo_test_names with one argument, so the --ignored subtraction never ran, and it printed a byte-identical success line. It now requires --rust-tests-ignored (one alone exits 2) and the line names its source. Also, from the same review: a missing context/test-evidence/ exited 0 while 170 citations pointed at nothing (early return, now gone); the doc-site "runs last" check accepted a trailing `echo` that merely NAMED the generator, so it asks for an invocation; bundle_freedom gains an arm for a transitive `import "../app.js"`, which reaches the bundle while naming nothing forbidden; and two prose overclaims are corrected -- the prose-heading count is a convenience rather than a guard (git diff is the mechanism), and the ratio rule says "above the run MEDIAN", which is defensible where "above the others" is false against second place. scripts/check-ci-graph.py makes claim 6's rule a gate: pages-deploy must `needs` every other job in ci.yml. The rule was stated in the last commit and a zz-new-check: job added during review was still ungated with nothing noticing. README now states the rule and lists no jobs, the second copy being what went stale twice. Every fault re-injected and observed; figures in context/test-evidence/tooling.md rather than only here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
60 lines
2.6 KiB
JavaScript
60 lines
2.6 KiB
JavaScript
// The `js` CI job must never need a built wasm bundle. See
|
|
// context/code/clients.md; the split is what keeps it seconds, not ~4m30s.
|
|
|
|
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { readFileSync, readdirSync } from "node:fs";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const dir = fileURLToPath(new URL(".", import.meta.url));
|
|
|
|
/// Built by concatenation so this file carries no literal of the thing it
|
|
/// forbids, and is therefore checked by itself rather than exempt from itself.
|
|
const FORBIDDEN = "p" + "kg";
|
|
|
|
/// Comments may name the directory — that is what the header above does. Only
|
|
/// what the code reaches for is a dependency, so strip comments first, exactly
|
|
/// as render_surface.test.js does.
|
|
const code = (name) =>
|
|
readFileSync(dir + name, "utf8")
|
|
.replace(/\/\*[\s\S]*?\*\//g, " ")
|
|
.replace(/(^|[^:"'`])\/\/.*$/gm, "$1");
|
|
|
|
test("no test in web/tests/ reaches for a built bundle", () => {
|
|
const siblings = readdirSync(dir).filter((f) => f.endsWith(".test.js"));
|
|
assert.ok(siblings.length > 1, `found ${siblings.length} test files — the glob moved`);
|
|
assert.ok(siblings.includes("bundle_freedom.test.js"), "this file must check itself");
|
|
|
|
const offenders = siblings.filter((f) => code(f).includes(FORBIDDEN));
|
|
assert.deepEqual(
|
|
offenders,
|
|
[],
|
|
`these belong in web/tests/bundle/, which the browser job runs: ${offenders}`,
|
|
);
|
|
});
|
|
|
|
test("no test in web/tests/ imports a module that reaches the bundle", () => {
|
|
// The check above is lexical and DIRECT-only: `import "../app.js"` needs the
|
|
// bundle transitively and names nothing forbidden. app.js and worker.js are
|
|
// the two entry points that load it; shell.js and serial.js do not.
|
|
const siblings = readdirSync(dir).filter((f) => f.endsWith(".test.js"));
|
|
const reaches = /^\s*import\b[^;]*["']\.\.\/(app|worker)\.js["']/m;
|
|
const offenders = siblings.filter((f) => reaches.test(code(f)));
|
|
assert.deepEqual(
|
|
offenders,
|
|
[],
|
|
`importing ../app.js or ../worker.js executes the bundle loader: ${offenders}`,
|
|
);
|
|
});
|
|
|
|
test("the subdirectory that MAY use a bundle is not the one being checked", () => {
|
|
// Reading it proves the exemption is a real directory rather than a
|
|
// convention nobody kept, and that this check is scoped to the flat listing.
|
|
const nested = readdirSync(dir + "bundle").filter((f) => f.endsWith(".test.js"));
|
|
assert.ok(nested.length > 0, "web/tests/bundle/ is empty — the split lost its other half");
|
|
assert.ok(
|
|
nested.some((f) => readFileSync(dir + "bundle/" + f, "utf8").includes(FORBIDDEN)),
|
|
"no bundle test reaches for a bundle, so this check has nothing to be scoped against",
|
|
);
|
|
});
|