diff --git a/docs/REVIEW_LOG.md b/docs/REVIEW_LOG.md index 02c109e..c18d734 100644 --- a/docs/REVIEW_LOG.md +++ b/docs/REVIEW_LOG.md @@ -6752,3 +6752,16 @@ sentences and there is no smaller slice that owns them, so it is left alone deli rather than overlooked. check-rules builds its covered-set from labels it generates, not from searching a document. check-lang, check-creatures, check-templates, check-kits and the baseline guards do no document matching at all. + +## R-288 — an empty declaration is not the same as no declaration + +c0's note on R-286: the reader is unambiguous now, but the fallback that made the failure +look like success is still there. It is right, and the fix has to be narrow. **No marker at +all is the ordinary case** — sixteen of the seventeen scenarios here declare no cast and are +rightly checked against the whole duty roster. A marker that is present and names nobody is +a different thing: somebody wrote a declaration, the guard read nothing out of it, and the +fallback then widens the population silently, so a clue only Pollard can reach passes on the +strength of an agent the scenario does not cast. + +Replacing CLEAN GROUND's declaration with `` passes before this change and +fails after it, naming the line. A scenario with no marker still falls back, unchanged. diff --git a/tools/check-rollable.mjs b/tools/check-rollable.mjs index fcb909b..3ed9d2e 100644 --- a/tools/check-rollable.mjs +++ b/tools/check-rollable.mjs @@ -104,6 +104,19 @@ for (const [label, path] of scenarioFiles()) { + `skill in the document to it; the others were never seen. Keep one declaration and ` + `put any example inside backticks, where the reader ignores it.`); } + /* A MARKER THAT DECLARES NOBODY MUST NOT FALL BACK. No marker at all is the ordinary case — + sixteen of the seventeen scenarios here have none and are rightly checked against the whole + duty roster. A marker that is PRESENT and EMPTY is a different thing: somebody wrote a + declaration and this guard read nothing out of it, and the fallback then widens the + population silently, so a clue only Pollard can reach passes on the strength of an agent + the scenario does not cast. That widening is what made R-286 green rather than loud; the + reader is unambiguous now, and this closes the door it came through. c0 asked for it. */ + if (markers.length === 1 && !markers[0].keys.trim()) { + problems.push(`${label}: declares a cast at line ${markers[0].line} and names nobody in it. ` + + `An empty declaration is not the same as no declaration — this guard would fall back to ` + + `the full duty roster and check every skill in the document against people the scenario ` + + `does not cast, and say OK. Name the cast or delete the marker.`); + } const declared = markers[0]; const cast = declared ? declared.keys.split(",").map(x => x.trim()).filter(Boolean).map(k => {