diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4ae277f..bbdd9f5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,6 +32,17 @@ jobs: - name: Install Python validator dependencies run: pip install "jsonschema>=4,<5" regex + # Prose gate (make prose-check): ms-check over docs/ + README with the + # rule set from pyproject.toml - em-dashes (the STYLE.md ban) and + # invisible characters (the W-INVISIBLE-CHAR class, applied to our own + # prose; its first run found a raw U+0000 in a proposal code example). + # Pinned like every other gate dependency: a floating linter version is + # a gate whose rules change under the repo. + - name: Prose gate (manuscript-tools ms-check) + run: | + pip install manuscript-tools==0.11.0 + make prose-check + - name: Lesson-types drift gate (regenerate from schema, expect no diff) run: node scripts/generate-lesson-types.mjs --check diff --git a/CHANGELOG.md b/CHANGELOG.md index e400b7e..569d5f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,33 @@ All notable changes to `learn-content-engine`. The format is inspired by ## [Unreleased] +### Prose gate: manuscript-tools ms-check over docs/ + README + +The sibling library `manuscript-tools` (PyPI, pinned 0.11.0) already +carries the invisible-characters check this engine's lint was seeded +from, plus the em-dash ban the blog STYLE rules demand - so the docs +prose is now gated by it instead of by convention. `make prose-check` +(and CI) runs `ms-check` with two rules active (`no-dashes`, +`no-invisible-chars`; the German-prose and whitespace heuristics are +disabled via `pyproject.toml` because they are wrong for an English +Markdown corpus). Guards learned today, applied here: the gate proves +the file set is non-empty before trusting a green run (`ms-check` exits +0 on an empty set, manuscript-tools#9), `STYLE.md` is excluded because +it SHOWS the banned characters, and the CHANGELOG stays out because old +entries describe a point in time. + +The gate earned its keep on its first measured run: a raw U+0000 sat in +a code example of `docs/proposals/author-ergonomics-app-track.md` (a +join separator quoted as the real byte instead of its escape - the same +pattern engine#135 removed from the sources, third instance today). Now +spelled as the escape. Seeded probes: an em-dash and a zero-width space +each turn the gate red; an empty docs set trips the floor. + +The comparison also went the other way: manuscript-tools' checker and +sanitizer are both blind to the C1 control range `U+0080-U+009F` (the +cp1252-mojibake class this engine's lint covers); reported as +manuscript-tools#11. + ### Source files are text to every tool again (engine#135) `src/stable-id-stability.ts` carried four RAW NUL bytes as key diff --git a/Makefile b/Makefile index db5a03f..9393a28 100644 --- a/Makefile +++ b/Makefile @@ -61,6 +61,16 @@ sync-types-check: ## Exit non-zero if the generated lesson types drift from the conformance-real: build ## Clone all public content repos (read-only) and run every set + lesson through the full engine pipeline node scripts/conformance-real.mjs +prose-check: ## Prose gate over docs/ + README (ms-check: em-dashes, invisible chars) + @# Floor first: ms-check exits 0 on an empty file set (manuscript-tools#9, + @# fails open), so the gate proves the set is non-empty before trusting a + @# green run. STYLE.md is excluded on purpose: it SHOWS the banned + @# characters. CHANGELOG stays out: old entries describe a point in time. + @test "$$(find docs -name '*.md' ! -name 'STYLE.md' | wc -l)" -ge 10 \ + || { echo "prose-check: docs/ yields fewer than 10 markdown files - wrong directory?"; exit 2; } + ms-check docs --exclude "blog/STYLE.md" --exclude "blog/de/STYLE.md" + ms-check README.md + # ─── Package ───────────────────────────────────────────────────────── pack-dry: build ## Show publish contents of the tarball without publishing diff --git a/docs/proposals/author-ergonomics-app-track.md b/docs/proposals/author-ergonomics-app-track.md index aae22e1..2c10a4a 100644 Binary files a/docs/proposals/author-ergonomics-app-track.md and b/docs/proposals/author-ergonomics-app-track.md differ diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..1cbcf3a --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,18 @@ +# This repo is an npm package; this file exists ONLY to configure the +# manuscript-tools prose gate (make prose-check, pinned in CI). ms-check +# resolves [tool.manuscript-tools] from the closest pyproject.toml - having +# our own here also stops a stray parent-directory config from leaking in. +# +# Active rules after the disables: no-dashes (the STYLE.md em-dash ban) and +# no-invisible-chars (the W-INVISIBLE-CHAR class, applied to our own prose - +# it found a raw U+0000 in a proposal's code example on its first run). +# Disabled because they are wrong for this corpus: the docs are mostly +# English Markdown with tables and code blocks, so German quote style, +# double-space and formatting heuristics fire on legitimate text. +[tool.manuscript-tools] +disable = [ + "no-double-spaces", + "non-german-quotes", + "broken-formatting", + "no-repeated-words", +]