Acceptance Criteria
- Plan entity rune configs use
slots to define assembly order: ['header-primary', 'content', 'header-secondary'] - Primary badges (id, status) are assigned to the
header-primary slot with id on the left and status on the right (justify-between) - Secondary badges (priority, complexity, assignee, milestone, source, created, modified, etc.) are assigned to the
header-secondary slot - Title (h1 from body content) renders between the two badge groups
- All five entity types (spec, work, bug, decision, milestone) are updated consistently
- Primary badges render without label text (labelHidden), matching backlog card style
- Secondary badges retain their current label + value rendering
- Backlog cards remain unchanged (they build their own structure in pipeline.ts)
- BEM classes follow the pattern:
.rf-work__header-primary, .rf-work__header-secondary - CSS in Lumina updated to style the split header layout (primary badges inline, title prominent, secondary badges as pills/row)
- Existing CSS coverage tests pass
- Contracts regenerated
Dependencies
- WORK-140 — Tab layout for plan entity pages (the tab group sits below the secondary badges)
Approach
Config changes (runes/plan/src/config.ts)
For each entity rune config (Work, Spec, Bug, Decision, Milestone):
- Add
slots: ['header-primary', 'content', 'header-secondary'] - Split the existing
structure.header into two entries:'header-primary': { tag: 'div', slot: 'header-primary', children: [id-badge, status-badge] }'header-secondary': { tag: 'div', slot: 'header-secondary', children: [remaining badges...] }
- Remove the old single
header structure entry - Update
sections map to reflect the new structure names
The engine's assembleWithSlots function handles the ordering — primary badges are emitted first, then content (which includes the title), then secondary badges. No engine changes needed.
CSS changes (packages/lumina/styles/runes/)
Update the per-rune CSS files (work.css, spec.css, bug.css, decision.css) to style the split layout:
.rf-work__header-primary — flex row with justify-content: space-between, id on the left and status on the right (matching backlog card header layout).rf-work__header-secondary — flex row with wrap, pill-style badges with labels
Variant-specific badges
Each rune type has different secondary badges:
- Work: priority, complexity, assignee, milestone, source, created, modified
- Spec: version, supersedes, created, modified
- Bug: severity, assignee, milestone, source, created, modified
- Decision: date, supersedes, source, created, modified
- Milestone: target, created, modified
References
runes/plan/src/config.ts — current plan rune configs with single header structurepackages/transform/src/types.ts — RuneConfig.slots, StructureEntry.slot definitionspackages/transform/src/engine.ts — assembleWithSlots implementationrunes/plan/src/pipeline.ts — backlog card builder (reference for primary/secondary badge pattern)packages/lumina/styles/runes/work.css — current work rune CSS
Resolution
Completed: 2026-04-13
Branch: claude/implement-work-141-rpJ3J
What was done
- Split the single
header structure entry into header-primary and header-secondary for all 5 plan entity rune configs (Spec, Work, Bug, Decision, Milestone) in runes/plan/src/config.ts - Added
slots: ['header-primary', 'content', 'header-secondary'] to each entity config so the engine assembles: primary badges → body content (title) → secondary badges - Primary badges (id/name + status) use
labelHidden: true matching backlog card style; secondary badges retain labels - Updated CSS in
packages/lumina/styles/runes/ for all 5 entity types: header-primary gets justify-content: space-between, header-secondary gets appropriate margin - Updated complexity dots selectors in work.css to reference
header-secondary instead of header - Regenerated
contracts/structures.json
Notes
- No engine changes were needed — the existing
assembleWithSlots function handles all the slot-based ordering - Backlog cards are unaffected since they build their own structure in
pipeline.ts - Both header-primary and header-secondary get
data-section="header" from the sections map, so the generic section dimension CSS (flex row, wrap, gap) applies to both