Files
RingBRP/tools/check-attackers.mjs
slaguru666andClaude Opus 5 0b86c5ffc3 R-268: guard the sentence that names a player's character
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>
2026-09-13 09:56:01 +01:00

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] ?? "?"}%`);