R-291 follow-up: one tag pattern, so the two readers cannot disagree

R-291 measured check-scenarios' tagsIn against this file's readers and found
them apart on three spellings. tagsIn was widened for case and spacing around
the colon; outcome-coverage's strict half still carried the case-sensitive
literal, so `[cus: Spot — x]` was READ by one guard and reported unparseable
by the other. The build failed, which is the safe direction, but it failed
saying the tag could not be read while another guard had just read it.

beatsIn and beatLikeIn now share one TAG pattern, widened to agree with
tagsIn. Measured across seven spellings: the five both strict readers accept
now agree in all three, and `[CUS Spot]` and `[CUS= Spot]` are still refused
by both and still named by the loose counter, so the canary keeps its teeth.

Verified on the real document that this is a spelling fix and nothing else —
beats 21, quoted 1, unparsed 0, stated 18/6/6, session figures unchanged, so
the baseline is untouched. A lowercase tag planted in the acts is now read by
check-outcomes, check-scenarios and check-rollable alike; the file was
restored byte-identical after the test. R-291's own assertion still passes.

Found by the peer session measuring my file rather than trusting it, which is
the fourth reader this session to be caught describing or reading its own
format wrongly.

npm run check: 19 guards pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
slaguru666
2026-09-13 15:52:11 +01:00
co-authored by Claude Opus 5
parent ed851b76e3
commit 8a051f7f2b
+13 -2
View File
@@ -37,6 +37,17 @@ export const BASELINE = path.join(ROOT, "tools", "outcome-coverage-baseline.json
/* ------------------------------------------------------------------ the beats */
/* ONE PATTERN FOR BOTH HALVES OF THIS FILE, and it agrees with check-scenarios' `tagsIn`
deliberately. R-291 measured the two apart: `tagsIn` was widened to tolerate case and
spacing around the colon, this file's strict half was not, and `[cus: Spot — x]` was then
READ by one guard and reported unparseable by the other. The build failed, which is the
safe direction, but it failed saying the tag could not be read while another guard had
just read it. Widened to match; `beatLikeIn` below still refuses `[CUS Spot]` and
`[CUS= Spot]`, which neither strict reader accepts, so the canary keeps its teeth.
check-behaviour asserts the two readers agree — that assertion is the thing that must
not be deleted, not this comment. */
const TAG = /\[\s*CUS\s*:\s*([^\]—]+?)\s*(?:—|\])/gi;
const indentOf = l => { const m = l.match(/^(\s*)(?:[-*]|\d+\.)\s/); return m ? m[1].length : null; };
const isHeading = l => /^#{1,6}\s/.test(l);
@@ -55,7 +66,7 @@ export function beatsIn(text) {
if (/^\s*```/.test(l)) { inFence = !inFence; return; }
if (inFence) return;
const quoted = /^\s*>/.test(l);
for (const m of l.matchAll(/\[CUS:\s*([^\]—]+?)\s*(?:—|\])/g)) {
for (const m of l.matchAll(TAG)) {
if (quoted) { out.push({ line: i + 1, skill: m[1].trim(), quoted: true }); continue; }
let owner = i;
for (let j = i; j >= 0; j--) {
@@ -84,7 +95,7 @@ export function beatsIn(text) {
/** A `[CUS …]` that this reader cannot parse is worse than no tag: somebody thinks it is
one. Asymmetric with beatsIn on purpose — R-286's castLikeIn, same reasoning. */
export function beatLikeIn(text) {
const good = [...text.matchAll(/\[CUS:\s*([^\]—]+?)\s*(?:—|\])/g)].map(m => [m.index, m.index + m[0].length]);
const good = [...text.matchAll(TAG)].map(m => [m.index, m.index + m[0].length]);
return [...text.matchAll(/\[\s*CUS\b[^\]]*\]/gi)]
.filter(m => !good.some(([a, b]) => m.index >= a && m.index < b))
.map(m => ({ raw: m[0].slice(0, 70), line: text.slice(0, m.index).split("\n").length }));