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).
This commit is contained in:
69
tasks/unmount-implementation.md
Normal file
69
tasks/unmount-implementation.md
Normal file
@@ -0,0 +1,69 @@
|
||||
---
|
||||
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
|
||||
Reference in New Issue
Block a user