Rulebearing Playground Coverage Schemas GitHub

ADR-0072: The docs site is generated from docs/ by a small Node generator, and one Pages deployment serves it with the released schemas

Context

Plan 0004 asks for a static docs site built from docs/, a playground component in its theme that loads the rb-wasm module, the JSON schemas at the $id URLs they carry, a link check over the build, and deployment to GitHub Pages from main. The plan's dependency table names mdbook or zola as candidates.

Four facts shape the choice:

Decision

A small generator in TypeScript, under site/, on markdown-it.

Part What it does
site/src/pages.ts Each tracked (git ls-files) Markdown file under README.md, CONTRIBUTING.md, SECURITY.md, docs/, schema/README.md and cookbook/README.md becomes a page; README.md becomes its folder's index.html. A file under docs/plans/ or docs/artifacts/ is never a page, even in a checkout that has them.
site/src/slug.ts The link check's slug rule, ported, with its examples and properties as tests.
site/src/links.ts Rewrites each relative link: to a page, to a served file (the schemas), to github.com/.../blob/<commit>/<path> for any other tracked file, or to plain text for a local-only folder. A link that resolves to nothing fails the build.
site/src/render.ts, layout.ts Render and lay out each page. Raw HTML is kept only for comments, line breaks and explicit anchors, and is otherwise escaped. Mermaid diagrams are shown as their source with a link to GitHub's rendering, because rendering them here would mean shipping Mermaid, whose dependency tree includes elkjs under EPL-2.0.
site/src/linkcheck.ts Checks the built site: every relative href, src and data-module must name a file it holds, and every fragment an id on that page.
site/web/ The playground's page script and the stylesheet.
site/build.sh Compiles rb-wasm for wasm32-unknown-unknown, binds it with wasm-bindgen --target web, as the wasm CI job does, compiles the generator and runs it.

Every page carries a content security policy: scripts from the site only, no inline script, no eval, and wasm-unsafe-eval so the module can compile. Plan 0004 § 1.11 asks for this.

The playground takes YAML and JSON only, and says so. It runs evaluate over a pasted configuration and cruise result, with any output type rb-report has except x-dot-webpage, which needs GraphViz's dot from the PATH (ADR-0053). The page states that JavaScript configurations and .NET assemblies are not accepted (ADR-0067). It wires only the exports rb-wasm has on main when the site is built: evaluate and version.

One deployment, from main, carrying the schemas of the latest release. .github/workflows/docs.yml builds the site:

The build reads schema/v1.json and schema/config-v1.json from the tag of the latest published release (gh release view), not from the checkout. It refuses a file whose $id is not the URL it is served at. A workflow_run runs in the default branch's context, so a release rebuilds the site from main with the new schemas and deploys it through the same main-only deployment. release.yml's schema-pages job is removed, so nothing else writes the site. Only the deploy job holds pages: write and id-token: write.

The npm packages are licence-checked against the same list as the crates. The site adds two root dev dependencies:

node site/dist/node/main.js licences walks both packages' trees in package-lock.json and checks each licence against deny.toml's allow list. It has one exception, scoped and with its reason: argparse, Python-2.0, which is markdown-it's command-line parser and is never loaded by the library entry the site imports. The check runs in the site CI job and in docs.yml. No npm code ships to the browser: the site serves only the compiled page script and the rb-wasm module.

Consequences

Alternatives considered

Option Why not
mdbook (MPL-2.0, Rust) Needs a SUMMARY.md listing every page, so pages would be listed by hand or by a preprocessor written for the purpose. Its anchors follow its own slug rule, so the link-check rule would need a preprocessor too, and so would link rewriting. The playground's TypeScript would sit outside the Rust tool's build.
zola (MIT, Rust) Wants content in its own tree with front matter, so docs/ would be copied and rewritten at build time, which is the generator's job again. Its anchors differ from the link check's in the same way.
VitePress, Astro, Eleventy (MIT, Node) Each brings a large dependency tree (Vite, Vue or its own renderer), a slug and link pipeline to override plugin by plugin, and inline scripts in its output that a no-inline-script policy would need hashes for.
Keep schema-pages and add a second, docs-only deployment One Pages site per repository: each deployment replaces the other, so the docs would vanish at every release and the schemas would vanish at every docs change.
Serve the schemas from the checkout on main The URL would serve unreleased work in progress, which docs/release.md rules out.
Render Mermaid with the mermaid package Its dependency tree includes elkjs (EPL-2.0), which is outside the allow-list.