WORK-674
ID:WORK-674Status:done

A composition's narrative field is checked at definition load

ADR-047 lets a rune declare one narrative field that accepts only the editorial runes textblock and mediatext, and says the field is never published as structured data. As amended, the field is inferred from its match, and both rules are checked.

Priority:lowComplexity:simpleMilestone:v0.46.0Source:ADR-047
claude/milestone-v0-44-0-ism7ni View source

Criteria completion

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

Tracking started Nov 2 — check back for trends.

Branches 3
History 4
  1. 09780ca
    Content editedby bjornolofandersson
  2. dcdef7b
    Created (in-progress)by bjornolofandersson
  3. 0ec343f
    Content editedby Claude
    plan: draft v0.45.0 and v0.46.0; WORK-660 joins v0.44.0
  4. 8c20651
    Content editedby Claude
    plan: accept ADR-047 with checkable narrative-field rules; WORK-674, WOR

Acceptance Criteria

  • A content-model field whose match names editorial runes (tag:textblock, tag:mediatext) and nothing else is recognised as the narrative field
  • A definition declaring more than one narrative field is rejected at load, naming the fields
  • A definition whose schema table maps a narrative field is rejected at load, naming the field and the property
  • A field that mixes editorial runes with other matches is not a narrative field and is not checked as one
  • reference and inspect show which field is the narrative field
  • A fixture composition with a story field renders the story between two template parts, publishes no part of it in JSON-LD, and raises no slot-role warning (ADR-046)

References

  • ADR-047: decisions 1 and 2, as amended.

Resolution

Completed: 2026-11-02

Branch: claude/milestone-v0-44-0-ism7ni

What was done

  • packages/runes/src/lib/composition.ts:
    • isNarrativeMatch (exported) and modelFieldDefinitions;
    • schemaSourceNames walks properties and text in rows, fallback, entities and children;
    • compileComposition rejects a second narrative field (narrative-field-twice) and a mapped one (narrative-field-mapped), and records CompositionInfo.narrativeField.
  • composition-errors.ts: the two codes.
  • packages/runes/src/reference.ts and packages/cli/src/commands/inspect.ts print the narrative field; inspect's JSON carries it.
  • packages/runes/test/composition-narrative.test.ts: inference, the dish fixture (story between section and card; no property in the story; no slot-header-role finding), both rejections, the mixed-match case, and reference.

Notes

  • Only the content model's top-level fields are considered (the slots a template places); a section model's per-section fields are not.