check-cited: a citation marker nothing reads now fails the build
A misplaced marker failed open. CITE requires the comment to sit immediately after its figure; put one word between them and the citation is silently skipped while the run still reports OK with the same count as a clean tree: The longest fight seen ran **67** rounds.<!-- cite: fight-tail cut.longest --> check-cited: OK — 25 cited figures ... That marker names a field the guard is supposed to refuse outright, and the guard never saw it. Worse than an absent citation, because whoever wrote it believes they added a check — and worse still in a guard written yesterday to catch exactly this shape of defect. Every `<!-- cite:` occurrence is now counted and compared against what the parser actually read; any difference fails and prints the offending line. Verified on both placement failures: a marker one word from its number, and a marker on its own line with no number at all. The failure headline was also wrong for this class -- it claimed a figure mismatched its artifact -- and now covers both. Found by a peer session writing a bad citation by accident while testing. npm run check: 16 guards, exit 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
8279cdfda8
commit
4d7d93abc8
+23
-1
@@ -72,6 +72,8 @@ function resolve(json, dotted) {
|
|||||||
/* The number immediately before the marker, allowing for markup and a trailing unit:
|
/* The number immediately before the marker, allowing for markup and a trailing unit:
|
||||||
"**40**", "25.5%", "1.4x". Anchored to the end so it is the nearest one. */
|
"**40**", "25.5%", "1.4x". Anchored to the end so it is the nearest one. */
|
||||||
const CITE = /([\d]+(?:\.[\d]+)?)\s*(?:%|x)?\**\s*(?:—|-|–)?\s*<!--\s*cite:\s*([\w-]+)\s+([\w.]+)\s*-->/g;
|
const CITE = /([\d]+(?:\.[\d]+)?)\s*(?:%|x)?\**\s*(?:—|-|–)?\s*<!--\s*cite:\s*([\w-]+)\s+([\w.]+)\s*-->/g;
|
||||||
|
/* Every marker, however badly placed. The two counts must agree — see below. */
|
||||||
|
const ANY_CITE = /<!--\s*cite:[^>]*-->/g;
|
||||||
|
|
||||||
let checked = 0;
|
let checked = 0;
|
||||||
const problems = [];
|
const problems = [];
|
||||||
@@ -81,6 +83,26 @@ const rows = [];
|
|||||||
citations live. The raw file is the thing being checked. */
|
citations live. The raw file is the thing being checked. */
|
||||||
for (const [rel, abs] of scenarioFiles()) {
|
for (const [rel, abs] of scenarioFiles()) {
|
||||||
const text = readFileSync(abs, "utf8");
|
const text = readFileSync(abs, "utf8");
|
||||||
|
|
||||||
|
/* A MARKER THIS GUARD CANNOT READ IS WORSE THAN NO MARKER AT ALL, because whoever wrote
|
||||||
|
it believes they added a check. CITE requires the comment to sit immediately after its
|
||||||
|
number; put one word between them and the citation is silently skipped while the run
|
||||||
|
still reports OK with the same count as a clean tree. Found by a peer session writing
|
||||||
|
a bad citation by accident. So every occurrence is counted and the totals must agree. */
|
||||||
|
const seen = (text.match(ANY_CITE) ?? []).length;
|
||||||
|
const read = [...text.matchAll(CITE)].length;
|
||||||
|
if (seen !== read) {
|
||||||
|
const unread = text.split("\n")
|
||||||
|
.map((l, i) => [i + 1, l])
|
||||||
|
.filter(([, l]) => ANY_CITE.test(l) && (ANY_CITE.lastIndex = 0) === 0
|
||||||
|
&& [...l.matchAll(CITE)].length < (l.match(ANY_CITE) ?? []).length);
|
||||||
|
problems.push(` ${rel}: ${seen - read} citation marker(s) not attached to a number, so `
|
||||||
|
+ `nothing checks them — a marker that looks like a citation and is never read is the `
|
||||||
|
+ `defect this guard exists for. The comment must follow its figure immediately `
|
||||||
|
+ `(\`**40**<!-- cite: ... -->\`), with nothing but markup between.`);
|
||||||
|
unread.forEach(([n, l]) => problems.push(` line ${n}: ${l.trim().slice(0, 110)}`));
|
||||||
|
}
|
||||||
|
|
||||||
for (const m of text.matchAll(CITE)) {
|
for (const m of text.matchAll(CITE)) {
|
||||||
const [, printed, name, dotted] = m;
|
const [, printed, name, dotted] = m;
|
||||||
checked++;
|
checked++;
|
||||||
@@ -127,7 +149,7 @@ if (!checked) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (problems.length) {
|
if (problems.length) {
|
||||||
console.error("check-cited: FAILED — a scenario prints a figure its artifact no longer holds");
|
console.error("check-cited: FAILED — a scenario's cited figures do not match their artifacts");
|
||||||
problems.forEach(p => console.error(p));
|
problems.forEach(p => console.error(p));
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user