mirror of
https://github.com/zernie/vigiles.git
synced 2026-09-14 20:53:57 +08:00
4f0a01b2f9
Five changes from a measured review of the CLI surface and of a consumer's CI. 1. BEHAVIOUR — a positional target that matches nothing now FAILS. Bare discovery finding nothing still exits 0: an empty repo is a legitimate place to stand, but a path or glob you NAMED that matched nothing is stale, wrong, or never reached. Collapsing the two cost a real repo three days of green CI verifying zero files. Jest and Vitest fail on no-tests-found and make you opt in with --passWithNoTests; pytest exits 5. --min=0 is the opt-out here, so no flag is added. 2. HELP — the four checkers (audit/lint/test/eval) all read as "check my stuff". They are now grouped by READ vs RUN, and each line states its own consequence positively. The success criterion was checkable and is met: "NOT a CI step — use vigiles lint in CI" is deleted, because nothing needs defending. A help line that says what a command ISN'T is a description that failed. Per-verb flag detail moves into the per-verb help; audit's four wrapped lines naming nine flags were most of the felt crowding. Verb count is unchanged at 8 — the smallest of every tool measured (vitest 8 verbs and 164 flags, cargo 48, docker 57, git 166), and none of them thinned their surface by removing verbs. 3. DOCBLOCK — src/cli.ts listed four of the eight commands, having quietly stopped growing. Replaced by a pointer to the single source; a new test asserts every verb appears in the RENDERED help exactly once, because a constant is what drifted. 4. AUDIT — new Tested finding: "N surfaces counted as covered by PLACEMENT only — no run on record ever exercised one". Colocated evidence is a claim about the filesystem and the provenance line already admits it; nobody reads a provenance line. Measured in a consumer: 26 colocated and 0 executed, while its CI skipped every one of those harnesses and reported success. The corpus-wide threshold is a stated limit in the code, not a silence. 5. DOCS + SKILL — the Action reference now explains why there is no test input (the Action never runs npm ci; harnesses import the library), and the test-harness skill gained a six-line CI pointer: an Action exists, init wires it, inputs are documented there. It REFERENCES rather than explains, because copied explanations rot — three measured proofs, one of them inside this product. Gates, in order: vitest, lint, prettier, api:check, build — via the check script, 18 of 18. Co-authored-by: Claude <noreply@anthropic.com>
76 lines
2.4 KiB
TypeScript
76 lines
2.4 KiB
TypeScript
/**
|
|
* The top-level help, asserted as a CONTRACT rather than eyeballed.
|
|
*
|
|
* Two of these assertions exist because the old help failed them. It described `audit`
|
|
* with "NOT a CI step — use `vigiles lint` in CI" — a sentence that says what a command
|
|
* ISN'T, which is a description admitting it failed; deleting that sentence was the
|
|
* checkable success criterion of the 2026-08-18 rewrite, and this test is what keeps it
|
|
* deleted. And the module docblock listed four of the eight verbs, having quietly stopped
|
|
* growing — so the coverage assertion below reads the RENDERED output, not a constant,
|
|
* because a constant is the thing that drifted.
|
|
*/
|
|
import { test } from "vitest";
|
|
import assert from "node:assert/strict";
|
|
import { execFileSync } from "node:child_process";
|
|
|
|
const help = execFileSync("node", ["dist/cli.js", "--help"], {
|
|
encoding: "utf-8",
|
|
});
|
|
|
|
test("every user-facing verb appears in the grouped help exactly once", () => {
|
|
for (const verb of [
|
|
"init",
|
|
"compile",
|
|
"eject",
|
|
"audit",
|
|
"lint",
|
|
"test",
|
|
"eval",
|
|
"generate",
|
|
]) {
|
|
const hits = help
|
|
.split("\n")
|
|
.filter((l) => l.trimStart().startsWith(`vigiles ${verb} `));
|
|
assert.equal(
|
|
hits.length,
|
|
1,
|
|
`expected exactly one help line for \`${verb}\`, got ${hits.length}`,
|
|
);
|
|
}
|
|
});
|
|
|
|
test("the four checkers are grouped by whether they READ or RUN", () => {
|
|
const read = help.indexOf("Check your harness");
|
|
const run = help.indexOf("Run your harness");
|
|
assert.ok(
|
|
read > 0 && run > read,
|
|
"both group headings must be present, read before run",
|
|
);
|
|
const between = (a: number, b: number, verb: string) => {
|
|
const at = help.indexOf(`vigiles ${verb} `, a);
|
|
assert.ok(at > a && at < b, `\`${verb}\` must sit inside its own group`);
|
|
};
|
|
between(read, run, "audit");
|
|
between(read, run, "lint");
|
|
between(run, help.length, "test");
|
|
between(run, help.length, "eval");
|
|
});
|
|
|
|
test("no command is described by what it is NOT", () => {
|
|
assert.doesNotMatch(
|
|
help,
|
|
/NOT a CI step/,
|
|
"a help line that must disclaim what a command isn't is a description that failed — " +
|
|
"state the consequence positively instead (audit: 'fails nothing')",
|
|
);
|
|
});
|
|
|
|
test("per-verb flag detail stays OUT of the top-level list", () => {
|
|
assert.doesNotMatch(
|
|
help,
|
|
/--no-html/,
|
|
"flag detail belongs in `vigiles <verb> --help`",
|
|
);
|
|
assert.match(help, /Flags live in `vigiles <command> --help`/);
|
|
});
|