playlist accepts type="album | podcast | audiobook | series | mix" and emits MusicPlaylist for all five, with every item typed MusicRecording.So a podcast is published as a music playlist whose episodes are music recordings, and an audiobook as one whose chapters are songs. The rune already knows better — the author told it.
Markdoc.validate() is never called on site content. A rune typo, an unknown attribute, a missing required attribute and an out-of-enum modifier value all render silently, and the only user who ever learns is one running the VS Code extension.It is called in two places, neither of which sees a user's pages:
The shared stacked-layout contract (packages/lumina/styles/layouts/split.css) assumes media-first source order: top is plain DOM order, bottom flips visually via a generic column-reverse. But hero, feature, and step emit content-first DOM (text before media — the right reading order for their classic media-beneath-text presentation). Result: both stacked labels lie — the default top rendered media at the bottom, and an explicit bottom hoisted it to the top. Found in SPEC-101 review (PR #432); pre-existing.
Found while auditing section roles for WORK-530: Character's entity-level body slot is emitted, placed by layout, and always empty. Prose an author writes directly inside {% character %} never reaches the output.Realm and Faction — the two runes that otherwise share Character's exact shape — handle the same content correctly, which is what makes this a bug rather than a design choice.
extractHeadings in packages/runes/src/util.ts builds a heading's id by joining only the text child nodes, stripping ?, collapsing whitespace runs to -, and lowercasing. It does not strip any other punctuation, and inline code inside a heading contributes nothing at all — a code node is not a text node, so it is skipped.The result is ids that nobody writing a link would guess:
site/content/plan/docs/plan-entities.md documents the attributes of {% spec %}, {% work %}, {% bug %}, {% decision %}, and {% milestone %}. All five tables are incomplete, and two of the omissions are attributes the project's own mandatory workflow depends on.Measured against refrakt reference <rune> --format json --site plan:
spacing and inset are universal attributes — every one of the 45 block runes that carries universals accepts both. Neither has a page that says what it does.Found while checking whether /runes/surfaces was a sound link target for SPEC-128 D1's axis accordion. It is, for most axes, but not all.
{% data %} throws result is empty after projection (no rows to render) whenever the projection chain ends with zero rows. That fires on a filter which is correct and simply has no matches — a normal thing to ask of real data.The check cannot be relaxed on its own, because it is the only thing standing between an author and a silently wrong page. Measured against a two-row source with headers name,scope: