Acceptance Criteria
milestone keeps its ## sections, so a milestone's body renderswork, bug and decision keep preamble content that is not a paragraph, for example with a catch-all preamble field- Rerunning WORK-631's measurement over
plan/ reports no content-unmatched finding CONTENT_UNMATCHED_LEVEL in packages/runes/src/lib/index.ts is raised to error, and the docs and tests that state the severity are updatednpm run seo:baseline:check and refrakt contracts --check report no drift on either contract copy, or the drift is reviewed and explained
Approach
Fix the content models first, and only then raise the severity. Raising first would fail the build for every project with a plan directory. refrakt plan reads entities structurally, not through the content model, so the CLI is not affected either way.
References
- WORK-631: the report, and the measurement in its resolution.
- SPEC-145 D11.
Resolution
Completed: 2026-10-09
Branch: claude/v041-plan-runes-keep-content PR: refrakt-md/refrakt#700
What was done
plugins/plan/src/tags/milestone.ts: the goals/notes sequence fields are replaced by one catch-all body field (match: 'any'), the same shape spec uses. The goals list, notes and every ## section render in the body, in authored order. Top-level --- is stripped.plugins/plan/src/tags/{work,bug,decision}.ts: a catch-all intro preamble field after description, and an intro slot (region, omitWhenEmpty, role: body). It keeps blockquotes, lists, fences, tables and --- written before the first ##.plugins/plan/src/config.ts: the Work, Bug and Decision layouts place intro between tags and body.- Lumina
work.css, bug.css, decision.css: __intro uses the body's type scale. Blockquotes in it are styled like spec's, and a trailing --- is hidden. milestone.css gains the blockquote rule for its body. plan/work/WORK-224: unescaped backslash-escaped backticks that had turned an inline {% codegroup %} into a real, unclosed tag.CONTENT_UNMATCHED_LEVEL is error. These were updated to state the new severity:docs/configuration/reference.md and extend/rune-authoring/content-models.md;- the plan rune pages;
validate-content.test.ts and composed-character.test.ts.
- New
plugins/plan/test/kept-content.test.ts. emits-equivalence gains intro: 'body' in its sections table; its snapshot is untouched. - Contracts (both copies):
intro is added to the three layouts. - Changeset
content-unmatched-error.md (minor) states the behaviour change and the author's fix: add a field, or set rawBody.
Measurement
WORK-631's measurement, rerun over plan/ (908 files):
- Before: 803 nodes in 200 files: milestone 500/34, work 264/148, bug 37/16, decision 1/1, plus codegroup 1/1 from the malformed WORK-224.
- After: 0.
refrakt validate on main and plan (and plan --deep): 0 findings. plan-site builds clean.
Notes
- The slot is
intro, not preamble. preamble is a header role, and the engine special-cases data-name="preamble"; this content reads as the opening of the body. - A preamble that opens with a blockquote before its lead paragraphs puts those paragraphs in
intro, not blurb. That keeps the authored order. plan/ used as a site still has 265 pre-existing findings from other ids: literal tag syntax in prose. They are outside this item, and plan/ is not a configured site.