V0.39.0
Name:v0.39.0Status:complete

v0.39.0 — Declarations, part two

v0.38.0 deleted what was provably inert and made two declarations reach the reader and the runtime. This milestone continues on the same line, one level up: the remaining places where a rune's behaviour is written as code but is really data, plus the one place where the two schema resolvers' disagreement already publishes wrong structured data.

These are also the self-contained foundations of the composed-runes work (SPEC-145, SPEC-153, SPEC-156). Each one is valuable on its own and does not depend on composition landing. Composition itself is deliberately not in this milestone.

Milestone burndown: 1 open work item remaining; peak 14, started Sep 16036912Sep 16Oct 11
Open work items Ideal burndown
Progress 9/10 work items
Related 23
History 6
  1. 3eb75b7
    statusactive→complete
    by bjornolofandersson
  2. 02e4e86
    Content editedby Claude
    docs(plan): close v0.39.0; mark shipped specs
  3. cfe714f
    Content editedby bjornolofandersson
  4. 5191d3e
    Content editedby Claude
    docs(plan): cancel WORK-617, defer storytelling to composed runes
  5. 50daca8
    Created (active)by bjornolofandersson
  6. 1046f41
    Content editedby Claude
    docs(plan): add v0.39.0 milestone, Declarations part two

Work Items

Draft 1
WORK-617 main
character, realm and faction drop their transforms for the slot declaration
The second proving set for SPEC-143: the storytelling entity runes whose sections arrive as already-rendered child runes (emitTag). Together with WORK-616 this covers both sides of the emitTag split, which is what proves the mechanism rather than one shape of it.Same gate (D7): no drift in contracts or the SEO baseline, per rune.recipe is the standing proof that the escape hatch is still needed (D3). It is not migrated, and it is not bent to fit.
medium moderate
0/6 criteria
Done 9
WORK-609 main
Stop findChildren retyping author-nested runes of a colliding name
SPEC-146 Problem 1, the present-tense half. findChildren (packages/runes/src/lib/schema-table.ts) matches a schema children key against data-rune as well as data-name / data-field, descends the whole subtree and applies every match. So playlist's children: { track } retypes an author's own {% track %} nested in an unrelated container as one of the playlist's tracks, and because the child row is applied with the author's node as root, the row's own properties resolve inside it. The SPEC records the result in the JSON-LD graph, not only in RDFa: an unrelated recording published as a track.The colliding rows are a closed set: playlist's musicRow/spokenRow and breadcrumb's breadcrumb-item carry their own properties and reach the graph; recipe/howto (step), pricing (tier), timeline and accordion carry text/generated only and mis-stamp RDFa.
high moderate
9/9 criteria
WORK-610 main
Let findAllByName resolve owner-marked nodes across a rune boundary
SPEC-146 Problem 2. findAllByName stops dead at any nested data-rune, which is right for every rune today and wrong the moment content is placed inside a primitive on another rune's behalf (SPEC-145). Only node-sourced values are affected: properties from a node, text, and the node half of entities. Attribute-sourced values resolve through the field bag and are untouched by nesting.
medium simple
7/7 criteria
WORK-611 main
Add the registers declaration and its core registration hook
SPEC-144's mechanism. A rune declares that it registers a named entity or an edge, and one core pipeline participant performs the registration in the existing Phase 2 (register) / Phase 3 (aggregate) slots. The registry, the relationship graph and the query runes (collection, relationships, aggregate) are unchanged. This only gives them a declarative way in.
high complex
9/9 criteria
WORK-612 main
Migrate storytelling's entity and bond registration onto registers
The motivating case for SPEC-144. plugins/storytelling/src/pipeline.ts registers character, realm, faction, lore and plot through a generic walk and two field-list switch statements (extractEntityName, extractEntityData), expands character aliases in aggregate, and registers bond as an edge. All of that becomes a registers block on each rune.postProcess stays exactly as it is. Declaring sentinel resolution is out of scope for this milestone (see WORK-611).
medium moderate
6/6 criteria
WORK-613 main
Migrate design's registration onto registers
The second reachable plugin in SPEC-144's reach table. plugins/design/src/pipeline.ts (92 lines) has the same shape as storytelling's, only smaller. Move its registration onto registers declarations and delete the hooks.Under the same D4 gate as WORK-612: a registry snapshot taken before, asserted after, with order included.
low simple
3/3 criteria
WORK-614 main
Add the slot declaration and generate a rune's transform from it
SPEC-143's mechanism, without migrating any rune. That happens in WORK-616 and WORK-617.createContentModelSchema gains an emits declaration carrying the renderable's identity (rune, tag, property), its properties in SPEC-140's data form (fieldMetas, which already takes no function values), and its slots:
high complex
16/16 criteria
WORK-615 main
Remove snippet's standalone figure wrapper
SPEC-141 D5/D6, shipped first and on its own. snippet runs in two phases: preprocess, and a postProcess pass, wrapStandaloneSnippets in packages/runes/src/config.ts, which wraps a standalone <pre> in <figure class="rf-snippet">. The wrapper adds no information: data-source and data-lines are already on the <pre>, and .rf-snippet's CSS only resets the margins the figure itself introduced.Removing it makes snippet single-phase, so WORK-618 moves one concern into the tag module rather than half of one.Breaking output change. Downstream CSS or tooling selecting .rf-snippet or [data-source-path] must move to pre[data-source]. Authors who want chrome compose it: {% codegroup title="…" %}, or {% figure %} once BUG-028 lands in this milestone.
medium simple
7/7 criteria
WORK-616 main
work, bug and decision drop their transforms for the slot declaration
The first proving set for SPEC-143: the plan entity runes whose sections arrive as resolved entries (no emitTag). After SPEC-081 they build no structure; what is left is properties, title → header, description → blurb (omitted when empty), sections → body. That is exactly what the slot declaration expresses.
medium moderate
5/5 criteria
WORK-618 main
Resolve preprocessors in one tree-order walk
SPEC-141's main change. Replace the three whole-AST passes (walkAndReplaceIncludes, walkAndReplaceSnippets, walkAndReplaceData) and their hand-written order in config.ts with one walk that dispatches per tag, and move each preprocessor into the tag module that owns it:
high complex
12/12 criteria