WORK-537
ID:WORK-537Status:ready

Separate the prose capability from the body role

body carries two meanings that were merged by accident of timing:

Priority:mediumComplexity:moderateMilestone:v0.32.0Source:SPEC-125

Criteria completion

Criteria completion: 0 of 8 (0%) checked; tracking started on Sep 6, no incremental history yet0%25%50%75%100%Sep 6Sep 6

Tracking started Sep 6 — check back for trends.

Branches 1
History 2
  1. 8b65a2f
    Created (ready)by bjornolofandersson
  2. 127194f
    Content editedby Claude
    Add work items WORK-528..537 for milestones v0.31.0 and v0.32.0

Shape

Declare the gate rather than inferring it, per SPEC-125's governing rule:

readingAxis.requires = 'prose'
TextBlock: { provides: ['prose'] }

Only one axis needs it initially, so this is close to a bespoke field in cost. It is worth the general shape because SPEC-124 already gave every facet a declaration point — requires sits beside contract and describeForRune, and flows into the structure contract for free. A bespoke proseSection on RuneConfig solves the same case and leaves the next axis to invent its own.

Acceptance Criteria

  • reading and dropcap gate on a declared prose capability, not on the body role
  • The capability is declared by the facet and provided by the rune, so the next axis needing one does not invent a bespoke field
  • The structural body role and every stylesheet keying on [data-section="body"] are unchanged
  • The ~21 body-role runes are audited for whether they bear authored prose
  • DataTable, Showcase, Form, Api and Symbol no longer offer reading/dropcap; Blog, TextBlock, PullQuote, Sidenote and Lore still do
  • The structure contract's unavailable reasons reflect the new gate rather than still citing the body role
  • A breaking changeset records the runes that lose the attributes
  • npm run build, the full repo suite, and refrakt contracts --check pass

Approach

Sequenced after WORK-534, and the order is load-bearing. The design question is the default:

  • Default-on (a body role implies prose unless a rune opts out) keeps the migration tiny, but preserves the lossy proxy as the default — so this same bug recurs for the next non-prose rune.
  • Default-off (a rune must declare that it bears prose) is honest, but a forgotten declaration silently disables reading — today's failure mode returning.

Default-off is right only once schemas have narrowed: with WORK-534 in place a forgotten declaration is no longer silent — the attribute is not offered and refrakt reference says so. Running this first would forfeit that, so take default-off and rely on the narrowing to make omissions discoverable.

Note Playlist may arrive here from WORK-531 with a newly-added structural body role and no prose — that is the intended interaction between the two items, not a conflict.

Blocked by

  • WORK-534

References

  • SPEC-125 — Phase 4, and The governing rule
  • SPEC-108 — where the proxy was introduced
  • SPEC-124 — the facet declaration point this reuses