--- 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