Remove Legacy Model Class and Decorators
Migrate all runes from the imperative Model + decorator pattern to createContentModelSchema, then remove the legacy API surface entirely.
Migrate all runes from the imperative Model + decorator pattern to createContentModelSchema, then remove the legacy API surface entirely.
The rune authoring API currently exposes two parallel patterns for defining rune schemas:
Model base class, use @attribute, @group, @groupList, and @id decorators, override processChildren() and transform(), wrap with createSchema(ModelClass).createContentModelSchema() with a declarative content model (sequence, sections, delimited, custom) and a transform function that receives resolved fields.Both are publicly exported, both are documented, and both appear in shipped runes. This creates real problems:
constructor → processChildren → transform). This is a high bar for a content framework.createSchema and createContentModelSchema, or they drift apart.NodeStream, RenderableNodeCursor, and createSchema are all kept alive for ~24 runes when the modern API can express the same logic.Migrate every rune that uses Model + decorators to createContentModelSchema, then delete:
Model base class (packages/runes/src/lib/model.ts)@attribute decorator (packages/runes/src/lib/annotations/attribute.ts)@group / @groupList decorators (packages/runes/src/lib/annotations/group.ts)@id decorator (packages/runes/src/lib/annotations/id.ts)createSchema factory (in packages/runes/src/lib/index.ts)NodeStream, RenderableNodeCursor, decorator metadata typessite/content/docs/authoring/model-api.md)After this work, createContentModelSchema is the sole way to define a rune schema.
createSchema, and supporting types from @refrakt-md/runesRuneConfig systemcreateContentModelSchemacreateContentModelSchemapackages/runes/src/tags/)| Rune | Current pattern | Content model type | Complexity |
|---|---|---|---|
| accordion | Model + @group | sections | simple |
| budget | Model + @group | sequence | simple |
| conversation | Model + custom processChildren | custom | complex |
| form | Model + custom processChildren | custom | complex |
| nav | Model + @group | sections | moderate |
| reveal | Model + @group | delimited | simple |
| sandbox | Model + @group | sequence | simple |
| tabs | Model + custom processChildren | custom | complex |
runes/marketing/src/tags/)| Rune | Current pattern | Content model type | Complexity |
|---|---|---|---|
| bento | Model + @group + custom processChildren | custom | complex |
| comparison | Model + custom processChildren | custom | complex |
| feature | Model + @group | sequence | simple |
| pricing | Model + @group | sections | moderate |
| steps | Model + @group | sequence | simple |
runes/storytelling/src/tags/)| Rune | Current pattern | Content model type | Complexity |
|---|---|---|---|
| character | Model + @group | sections | simple |
| faction | Model + @group | sections | simple |
| plot | Model + @group | sections | simple |
| realm | Model + @group | sections | simple |
| storyboard | Model + custom processChildren | custom | moderate |
| Rune | Package | Content model type | Complexity |
|---|---|---|---|
| cast | business | sections | simple |
| timeline | business | sections | simple |
| changelog | docs | sections | simple |
| preview | design | sequence | simple |
| map | places | sections | moderate |
Each legacy pattern maps cleanly to a content model type:
| Legacy pattern | Content model type |
|---|---|
@group with sequential node type filters | sequence |
@group with section option (heading-based splitting) | sections |
@groupList with delimiter: 'hr' | delimited |
Custom processChildren() override | custom with processChildren function |
@attribute declarations | attributes object in schema config |
@id with generate: true | attributes with id + generate logic in transform |
For each rune:
createContentModelSchema call with the appropriate content model typetransform() method to the new transform(resolved, attrs, config) functionrefrakt inspect <rune> --type=all that the identity transform output is identicalMigrate in dependency order and increasing complexity:
@group → sequence/sections/delimited conversions. These build confidence and flush out any gaps in the migration pattern.processChildren overrides that need custom content models: form, conversation, tabs, bento, comparison, storyboard.createSchema, and related types.model-api.md, update patterns.md and the authoring overview.refrakt inspect <rune> --type=all output must be identical before and after migration for every runeModel, @attribute, @group, @groupList, @id, createSchema, NodeStream, and RenderableNodeCursor are no longer exported from @refrakt-md/runesSubtle output differences. The Model's processChildren and createContentModelSchema's content resolver may handle edge cases differently (empty children, unexpected node types, whitespace nodes). Mitigated by per-rune refrakt inspect comparison.
@id auto-generation. The @id decorator tracks generated IDs in config.variables.generatedIds. The new pattern needs equivalent behavior. Check whether createContentModelSchema already handles this or if it needs to be added.
_tintNode / _bgNode extraction. The Model constructor extracts tint/bg child tags before group processing. createContentModelSchema already handles this (it injects tint/bg meta tags), but verify the behavior is identical.
Community package breakage. Any third-party packages extending Model (unlikely but possible) would break. This is acceptable since the framework is pre-1.0 and Model was never recommended for external use in the content model era.