CLEAN GROUND prints that the four-player cut is three effective attackers and that Ashcroft is not one. Nothing checked it, and a GM reads it aloud to decide who a real player spends four hours being. effective-attackers.mjs measures per attack, not per fight: counted per fight Braithwaite leads on disables, but only because his armour buys him a third more swings -- per attack he is the weakest of the three. Both rates are recorded and only the per-attack one is reasoned from. Asserts exact drift, then the sentence: three clear 5% of attacks disabling, one does not, and that one is Ashcroft. Re-recording does not silence the claim check; verified in a worktree. declared-cast.mjs holds the cast marker reading both scenario guards need, rather than a copy in each. It was briefly named scenario-cast.mjs, which check-scenarios sweeps into the scenario corpus -- its own example marker was read as a real cast. update-readme dropped any guard that exited non-zero, so check-rollable vanished from the README and the count word fell to thirteen while fourteen guards ran. A missing line is now fatal. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
28 lines
1.5 KiB
JavaScript
28 lines
1.5 KiB
JavaScript
/**
|
|
* CLEAN GROUND names an agent who cannot fight, and that sentence must keep being true.
|
|
*
|
|
* The scaling note prints "the four-player cut is three effective attackers, not four.
|
|
* Ashcroft is not one." Give him a sidearm, or change what the column dodges at, and the
|
|
* warning is false while the page goes on printing it — a claim nothing checks, which is
|
|
* the defect this suite exists for and the one R-267 was caught committing inside a guard.
|
|
*
|
|
* Thin on purpose: the measurement lives in effective-attackers.mjs, which is also the
|
|
* tool a reader runs, so the guard and the reading cannot drift apart.
|
|
*/
|
|
import { spawnSync } from "node:child_process";
|
|
|
|
const r = spawnSync(process.execPath, [new URL("effective-attackers.mjs", import.meta.url).pathname, "--check"],
|
|
{ encoding: "utf8" });
|
|
|
|
if (r.status !== 0) {
|
|
process.stdout.write(r.stdout ?? "");
|
|
process.stderr.write(r.stderr ?? "");
|
|
console.error("check-attackers: FAILED — the four-player cut no longer fights the way CLEAN GROUND "
|
|
+ "says it does. Read `node tools/effective-attackers.mjs` before re-recording.");
|
|
process.exit(1);
|
|
}
|
|
// update-readme reads the line beginning with this file's own name.
|
|
const m = r.stdout.match(/three of the cut disable on ([\d.]+)% of their attacks or better, and Ashcroft on ([\d.]+)%/) ?? [];
|
|
console.log(`check-attackers: OK — three of the four-player cut disable on ${m[1] ?? "?"}% of their attacks `
|
|
+ `or better, and one of them on ${m[2] ?? "?"}%`);
|