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.
{% testimonial %} parses its attribution line as **Name** — Role, stripping a leading -, – or — from the text after the <strong>. It does not strip a comma, so the comma form — which is the obvious alternative and which nothing rejects — carries the separator into the role.
data-meta-rank is the channel by which density compaction is meant to drop secondary metadata. It is specified, it is styled, and no code path ever puts it on an element.
howto, recipe, steps and track each hand-roll a CSS counter that the sequence dimension already provides for them. The duplication is invisible because the output looks identical — but the two rules land at different specificities, so which one is actually in effect differs from rune to rune.
When two files claim an ID, runMigrateIds sorts the claimants by path and keeps the first (plugins/plan/src/commands/migrate-ids.ts:165). Which claimant is already published on the base ref plays no part, so on a branch the tool will happily renumber the entity that is already on main and leave the local draft holding the ID.The safety argument for that choice is stated in the code:
resolveSections has two branches. The emitTag branch (packages/runes/src/lib/resolver.ts:480-502) builds a tag node per section and returns — it never calls matchKnownSection:
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.
refrakt reference answers "which runes are there?" differently depending on which way you ask. Two symptoms, one question, so they are filed together.Found by WORK-547's survey, which reads reference dump as the rune set and got a set that matches neither reference <name> nor check-rune-docs.mjs.
{% data %} resolves where through resolveString, which handles string literals and Variable nodes. Anything else — a Function node, most obviously — returns the empty string, and applyWhere treats an empty expression as no filter. So a where the rune cannot understand renders the entire source instead of erroring.
{% 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:
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:
Six Lumina rules style runes by selecting on the RDFa property attribute rather than the BEM element class the rune's refs already produce. Four of them now match nothing: the schema property was renamed, moved onto a <meta>, or removed entirely, and the stylesheet was never updated.Nothing detected it. The CSS coverage test checks that the selectors derived from config exist in the CSS; it has no way to notice a hand-written selector that matches no element.
/runes/media/track tells authors that "tracks can be used independently or inside a playlist rune". The composition does not work. A {% track %} inside a {% playlist %} is not a track of that playlist in the rendered HTML or in the structured data — it renders as a bare <li> in the prose body and publishes a detached top-level entity.Found while settling SPEC-130's open question about the two MusicRecording emitters. The question turned out to rest on this composition working; it does not.
Three live pages point a file-ref at a line range that no longer contains the symbol it is labelled with — and no longer exists in the file at all. This is the exact failure SPEC-131 describes as its motivating case, observed rather than predicted.
WORK-559 added validation to RefraktConfig "as a deprecated shorthand, matching sandbox". The type is there, the JSON Schema declares it, the generated reference documents it — and nothing reads it.A user who configures validation the documented shorthand way gets editor autocomplete, schema shape-checking, no warning, and no effect.
ADR-024 made themes framework-agnostic: no target, and layouts declare regions rather than pointing at framework components. validateManifest (packages/transform/src/validate.ts:467) was never updated.It still requires target and layouts.*.component, so it rejects the manifest create-refrakt generates and the manifest Lumina ships. Nobody noticed because nothing ran it — until WORK-579 gave it a command of its own.
For a rune whose primary syntax is a Markdown list, refrakt reference documents that a list is accepted and nothing about what goes in it. Three facts are lost, at two different points in the pipeline.