# Composure: Immediate Action Items

Prioritized work to transition from proof-of-concept to production-ready runtime.

---

## Tier 1: Architecture — COMPLETE

All Tier 1 items have been implemented.

### 1. Keyed Reconciliation ✓

**Implemented:**
- `_prevChildKeys` Map tracks children by key
- `getChildKey()` uses `_key` if set, falls back to index
- Removed children have their DOM elements cleaned up
- Existing elements are reused when keys match
- DOM order is corrected only when needed

### 2. Dirty Tracking ✓

**Implemented:**
- `_dirty` flag for layout, `_renderDirty` flag for render
- `_markDirty()` propagates up to root and clears measure cache
- `_markRenderDirty()` for render-only changes (attrs, events)
- Mutations (`.add()`, `.remove()`, `.size()`, `.pad()`, `.style()`, `.clear()`, `.gap()`, `.align()`) mark dirty
- `layout()` skips clean subtrees when constraints match `_lastConstraints`
- `renderNode()` skips render work for clean nodes
- `.dirty()` method for manual invalidation

### 3. Measurement Fidelity ✓

**Implemented:**
- `measureText()` now applies ALL non-excluded styles (including `textTransform`, `letterSpacing`, etc.)
- Cache key includes `styleHash` so style changes invalidate cache
- Cache also includes text content for text nodes

### 4. Style Patch Cleanup ✓

**Implemented:**
- `_prevStyleKeys` tracks applied styles, stale ones are cleared
- `_prevAttrKeys` tracks applied attributes, stale ones are removed
- `.style({ color: null })` removes the style
- `.attr('foo', null)` removes the attribute
- `.off(event)` added for removing event handlers

---

## Tier 2: Usability — COMPLETE

All Tier 2 items have been implemented.

### 5. Flexible Space Distribution ✓

**Implemented:**
- `.grow(n)` method on nodes (default n=1)
- `_grow` property tracked on nodes
- `vstackLayout()` and `hstackLayout()` updated:
  - First pass: measure non-growing children
  - Second pass: distribute remaining space proportionally
  - Third pass: assign positions in order
- Growing children fill their allocated share

```javascript
hstack().add(
  box().size(100, null),  // fixed 100px
  box().grow(1),          // takes 1/3 of remaining
  box().grow(2),          // takes 2/3 of remaining
)
```

### 6. Debug Tooling Enhancements ✓

**Implemented:**
- `debug` config object exported from composure.js:
  - `debug.logConstraints` — log constraint flow
  - `debug.logMeasure` — log when nodes are measured
  - `debug.trackMeasured` — track which nodes were measured
  - `debug.measuredNodes` — Set of measured nodes
- `debugResetTracking()` — clear measured set before update
- `exportTree(node)` — serialize layout tree to JSON
- Enhanced debug.js:
  - `enableConstraintLogging()` / `disableConstraintLogging()`
  - `enableMeasureLogging()` / `disableMeasureLogging()`
  - `enableMeasureTracking()` / `disableMeasureTracking()`
  - `getMeasuredNodes()` — get Set of measured nodes
  - `logTree(node)` — console log tree structure
  - `flashMeasuredNodes(duration)` — visual flash for measured nodes
  - `enableDebug(root, { showDirty, showMeasured })` — enhanced options
- Debug overlay shows grow factor and dirty state

### 7. Event Handling Review ✓

**Implemented:**
- `.off(event)` added in Tier 1
- Wrapper pattern kept (still useful for handler replacement without re-binding)
- Event handling is clean: bind once, wrapper fetches current handler

---

## Tier 3: Polish — MOSTLY COMPLETE

### 8. Render-Layer Separation — SKIPPED

**Reason:** Per TODO notes, only do if SSR or testing becomes priority. Current inline approach works fine for DOM rendering.

### 9. Limited Intrinsic Queries ✓

**Implemented:**
- `measureIntrinsic(node, 'min')` — measure with minimal constraints (longest word width for text)
- `measureIntrinsic(node, 'max')` — measure with no constraints (natural size)
- Works for text nodes and containers
- Temporarily forces dirty/cache clear for accurate measurement

```javascript
const minSize = measureIntrinsic(textNode, 'min')  // min-content
const maxSize = measureIntrinsic(textNode, 'max')  // max-content
```

### 10. Animation Helpers ✓

**Implemented:**
- `.transition({ duration, easing })` — enable frame animation
- `.noTransition()` — disable animation
- `_prevFrame` stored for comparison
- CSS transitions applied when frame changes
- Supports `duration` (ms) and `easing` (CSS easing function)

```javascript
box()
  .transition({ duration: 300, easing: 'ease-out' })
  .size(100, 100)

// Later, changing size will animate:
node.size(200, 200)
app.update()  // frame animates from 100x100 to 200x200
```

---

## Not Planned

These are explicitly out of scope per NON_GOALS.md:

- Global constraint solving
- CSS layout delegation (flexbox, grid)
- Component framework (state, lifecycle, data binding)
- JSX or DSL syntax
- Canvas/WebGL rendering
- Plugin architecture

---

## Quick Wins

Small fixes that can be done anytime:

- [x] Fix `textTransform` measurement bug (Tier 1)
- [x] Add `.off()` for event removal (Tier 1)
- [ ] Document which styles affect measurement
- [ ] Add test for reorder reconciliation
- [x] Add `node.dirty()` method for manual invalidation (Tier 1)

---

## Suggested Order

1. **Keyed reconciliation** — unblocks real interactivity
2. **Dirty tracking** — unblocks performance
3. **Measurement fidelity** — fixes correctness bugs
4. **Style patch cleanup** — completes the render model
5. **Flexible space** — most-requested usability feature
6. **Debug enhancements** — helps development
7. Everything else as needed
