WORK-705
ID:WORK-705Status:done

Generate a per-rune intro record from each reference page and the rune's resolution

SPEC-187 D5: the rune intro renders from data. One record per rune, beside the attribute records scripts/generate-rune-attributes.mjs already writes.

Priority:mediumComplexity:moderateMilestone:v0.48.0Source:SPEC-187

Criteria completion

Criteria completion: 6 of 6 (100%) checked; tracking started on Nov 3, no incremental history yet0%25%50%75%100%Nov 3Nov 4

Tracking started Nov 3 — check back for trends.

Acceptance Criteria

  • Each rune with a reference page has one record with title, description, package, composed, status, schemaType and source, and no install field (D8)
  • title, description and status are read from the reference page's frontmatter, not repeated anywhere else
  • composed and source come from how the rune resolves on the main site: a composition's .md definition, or a native rune's schema file, as a repo-relative path
  • schemaType is the type the rune's resolved schema row publishes with its defaults, the row refrakt inspect <rune> --site main prints; it is the default when an attribute changes the type or can switch it off, and empty when the rune publishes nothing (D9)
  • The drift check fails when the committed data differs from a fresh run, as it does for the attribute data
  • A test covers one core rune, one native plugin rune, one composed rune, and one rune that publishes no structured data

Approach

Extend generate-rune-attributes.mjs or add a sibling; SPEC-187 leaves the choice open. Reading resolution from the loaded plugins, not a list, means WORK-702 to WORK-704 flip composed with no edit here.

References

  • SPEC-187: D4, D5, D8, D9.
  • SPEC-128: the generated attribute data.
  • SPEC-130: D5, visibility in place of validation.

Resolution

Completed: 2026-11-03

Branch: claude/composition-usage-rune-pages-c87ar6 PR: refrakt-md/refrakt#770

What was done

  • scripts/rune-intro.mjs: builds one record per rune reference page and writes site/content/_data/rune-intro.json (99 records). Wired into scripts/generate-rune-attributes.mjs, so npm run runes:attributes writes it and --check covers both files.
  • Fields: rune, title, description, status, unstable, package, packageLabel, packageUrl, plugin, composed, source, publishes, schemaType, schemaUrl. No install (D8).
  • scripts/rune-intro.test.mjs: synthetic core / native plugin / composed / no-schema runes; against the repo, every rune page has a record, every source exists, the composed set is cta, hero, testimonial, and the committed file is fresh.

Notes

  • A separate file rather than a sixth partition of rune-attributes.json: that artifact's partition list is pinned by its tests and its query shape.
  • composed/source rest on SPEC-153 D3: a plugin cannot define a rune in both Plugin.runes and its runeDir, so a <runeDir>/<rune>.md in the owning package is the definition. Each plugin's runeDir is read from the plugin module, not assumed. A record whose source names no file fails the build.
  • schemaType is reference dump's schemaOrg.type, the row's default (playlist: MusicAlbum, its fallback).
  • Booleans (composed, unstable, plugin, publishes) exist because Markdoc's {% if %} treats "" as true.