Files
ujsx/tasks/unmount-implementation.md
glm-5.1 c9c32a6aa6 decompose reconciler roadmap into 20 implementation tasks across 5 phases
Tasks follow the architecture spec phases:
- Phase 0: key field on UElement (2 tasks + review)
- Phase 1: reactive-host bridge / fiber tree (4 tasks + review)
- Phase 2: key-based children reconciliation (3 tasks + review)
- Phase 3: unmount & dispose support (4 tasks)
- Phase 4: TypeBox value optimizations (4 tasks)

Validated with taskgraph CLI: no cycles, 15 parallel generations,
3 high-risk tasks identified (signal-driven-updates, commit-mutations,
fiber-disposal).
2026-05-18 16:26:52 +00:00

69 lines
2.7 KiB
Markdown

---
id: unmount-implementation
name: Implement full Root.unmount()
status: pending
depends_on: [fiber-disposal, reactiveroot-dispose]
created: 2026-05-18T16:22:57.308494756Z
modified: 2026-05-18T16:22:57.308495198Z
scope: moderate
risk: medium
impact: component
level: implementation
---
# Description
Replace the stub `Root.unmount()` with a full implementation that tears down the fiber tree, removes host instances, disposes signal subscriptions, and calls host cleanup methods.
Current stub:
```typescript
unmount() {
host.finalizeRoot?.(ctx);
host.emit?.("root.unmount", `root_${Date.now()}`, {});
}
```
New flow:
```
root.unmount()
→ disposeFiber(rootFiber, ctx) // disposes signals, calls finalizeInstance bottom-up
→ removeChild for each top-level child // host removal (top-down from root, each child subtree already disposed)
→ host.finalizeRoot(ctx) // root-level host cleanup
→ emit "root.unmount"
→ clear rootFiber reference
```
Note: `disposeFiber` handles resource cleanup (signals, finalizeInstance) but NOT `host.removeChild`. We need to walk the fiber tree and call `removeChild` for host instance removal. However, since children are already disposed, we only need to remove top-level children from the root context.
Open question from lifecycle.md: Should `ReactiveRoot` auto-dispose on `root.unmount()`? The architecture doc suggests decoupling is safer (a ReactiveRoot could drive multiple roots). This task should keep them decoupled — the consumer is responsible for calling `ReactiveRoot.dispose()` separately if needed.
## Acceptance Criteria
- [ ] `Root.unmount()` calls `disposeFiber(rootFiber, ctx)`
- [ ] `Root.unmount()` calls `host.removeChild` for top-level children
- [ ] `host.finalizeRoot(ctx)` called after disposal and removal
- [ ] `host.emit("root.unmount", ...)` still fires
- [ ] `rootFiber` reference cleared after unmount
- [ ] Subsequent `render()` calls after `unmount()` start fresh (new mount)
- [ ] Signal subscriptions from the fiber tree are cleaned up
- [ ] Does NOT auto-dispose `ReactiveRoot` — consumer responsibility
- [ ] `unmount()` is idempotent (safe to call twice)
- [ ] Existing tests pass
- [ ] New test: unmount cleans up all host instances
- [ ] New test: unmount then re-render works (fresh mount)
- [ ] New test: double unmount is safe
- [ ] New test: unmount calls finalizeInstance for each fiber
## References
- docs/architecture/lifecycle.md — Root Unmount Flow, Host Notification
- docs/architecture/host-config.md — Known Gaps: unmount is a stub
- docs/architecture/lifecycle.md — Open Question 2 (ReactiveRoot auto-dispose on unmount)
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion