V0.18.0
Name:v0.18.0Status:planning

v0.18.0 — Contract hardening

Follows v0.17.0's declarative metadata-and-layout model. The release hardens the rune output contract before third-party themes build against it, and lands the one breaking change held back from v0.17.0.

Milestone burndown: 2 open work items remaining; peak 2, started Jun 1012Jun 1Jun 15
Open work items Ideal burndown
Progress 12/12 work items
Related 14

Work Items

Done 12
WORK-313 main
Remove legacy slots + structure shim from engine
Phase 3 of SPEC-079. Removes the backwards-compat path in packages/transform/src/engine.ts that lets legacy slots: [...] + structure: {...} configs continue to render. Lands once all first-party plugins have migrated (WORK-306 through WORK-312 done) and the deprecation warning has been visible across at least one minor release.
low simple
8/8 criteria
WORK-321 main
Reserved fields attribute + schema dual-emit
Step 1 of SPEC-082. Introduce the typed field-data channel: rune schemas write their field values to a single reserved attribute, data-rune-fields, holding a JSON-encoded object — produced by createComponentRenderable (properties populate it). Keep emitting the legacy <meta data-field> children in parallel (dual-emit) so behavior is unchanged. No engine changes in this step.
high moderate
5/5 criteria
WORK-322 main
Engine reads the fields attribute (dual-read)
Step 2 of SPEC-082. The engine resolves modifierValues / metaFields from the parsed data-rune-fields first, falling back to the legacy <meta data-field> children when a key is absent. Parse the reserved attribute once per node. With both channels carrying the same data (after WORK-321), output is unchanged.
high moderate
5/5 criteria
WORK-323 main
Drop data-field metas; delete the side-channel cruft
Step 3 of SPEC-082 — the payoff. Stop emitting <meta data-field>; the engine reads only data-rune-fields (parse once, strip the reserved key before output). Delete the legacy meta-read path, the meta-strip filter, the kebab-matching set, and the unconsumed-meta leak filter. Genuine schema.org / SEO <meta property> tags are untouched.
medium moderate
0/5 criteria
WORK-324 main
Recursive layout assembly engine
The engine primitive for SPEC-081. Generalize composeContainer into a recursive resolver over a name-keyed layout, so the config can create the structural skeleton (preamble / content / media wrappers) rather than only ordering containers the transform pre-built.
high complex
5/5 criteria
WORK-325 main
Flatten rune transforms to flat-emit + declarative grouping
Migrate the runes that hand-build structural skeletons in TypeScript to emit a flat bag of data-name slots (content interpretation only) and declare their preamble / content / media grouping via the recursive layout from WORK-324. Output stays identical; the grouping moves from imperative code to config.
medium complex
5/5 criteria
WORK-326 main
Move semantic derivation out of postTransform (budget totals)
Apply the SPEC-081 computation boundary: semantic derivation belongs in the rune transform, not the presentation postTransform. Budget's grand / per-category / per-day totals are the worked example — a theme-invariant fact about the content currently stranded in the engine's escape hatch.
medium moderate
5/5 criteria
WORK-327 main
Surface grouped skeleton in contracts; deprecate projection.group/relocate
Finish SPEC-081: teach the contract generator about declaratively-grouped skeletons, and retire the projection operations now subsumed by recursive layout.
low moderate
4/4 criteria
WORK-328 main
Migrate pre-engine field consumers to the fields bag
WORK-322 migrated the engine to read data-rune-fields, but the field metas have other readers that run on the pre-engine tree and still read field values from <meta data-field>. They must move to the bag before the metas can be dropped (WORK-323) — otherwise entity registration and SEO break.
high moderate
5/6 criteria
WORK-329 main
Untangle schema.org SEO metas from the data channel
Resolves SPEC-082 problem #4 (SEO double-booking) — the blocker for WORK-323. Some property metas are conflated: they carry both data-field (data, now in the bag via WORK-321 / WORK-322 / WORK-328) and property= from the schema map (e.g. recipe's prepTime / cookTime / servings). Split the two so the data channel (bag) and the schema.org channel (property= metas) are independent — only then can WORK-323 drop the data metas and remove the kebab set + meta-strip filter.
high moderate
6/6 criteria
WORK-330 main
Stabilize the plan-site dogfood test under parallel load
packages/content/test/plan-site-dogfood-real.test.ts ("builds a browsable plan site from refrakt's real plan/ via entityRoutes + collection") flakes under full-suite parallel load — it failed on most npm test runs across the SPEC-082 work, yet passes reliably in isolation (~5–6s). It is a heavy, real-file pipeline build (reads the whole plan/ tree, runs the full content pipeline), so under vitest's parallel worker pool it appears to hit a timeout or a shared-resource race rather than a genuine assertion failure.This is pre-existing and unrelated to any one change — it just became visible because every SPEC-082 step ran the full suite.
low simple
4/4 criteria
WORK-331 main
Drop dual-emitted data-field metas from rune output (Tier 1)
Re-open the high-value slice of WORK-323 (descoped as a whole): stop emitting the dual-emit modifier/field <meta data-field> tags so the data-rune-fields bag is the only representation of field data in the rune tree. The risk being closed is that theme developers treat data-field metas as part of the output contract; this removes them from the pre-engine tree (they are already stripped from rendered output) without touching the engine input contract.
medium moderate
6/6 criteria