--- id: fiber-disposal name: Implement fiber tree disposal status: pending depends_on: [review-reconciler] created: 2026-05-18T16:22:57.277429897Z modified: 2026-05-18T16:22:57.277430341Z scope: moderate risk: high impact: phase level: implementation --- # Description Implement `disposeFiber()` for full teardown of a fiber subtree. This is the foundation for both root unmount and partial tree removal during reconciliation. Disposal is bottom-up (children before parents) and covers: 1. Recursively dispose all child fibers 2. Call `host.finalizeInstance?(instance, ctx)` for per-instance cleanup 3. Call each disposer in `fiber.signalDisposers` to clean up signal subscriptions 4. Clear fiber state (children = [], parent = null, effect = null, signalDisposers = []) **Important constraint:** `disposeFiber` disposes resources but does NOT call `host.removeChild()`. Instance removal happens during the commit phase, in a specific order, as part of the reconciliation algorithm. This separation ensures correct mutation ordering when batching removes. All disposal operations are idempotent — calling `dispose()` twice is safe. ## Acceptance Criteria - [ ] `disposeFiber(fiber, ctx)` function implemented in `src/host/fiber.ts` - [ ] Bottom-up disposal: children disposed before their parent - [ ] Calls `host.finalizeInstance?(instance, ctx)` for each fiber after children are disposed - [ ] Calls every disposer in `fiber.signalDisposers` - [ ] Clears `fiber.signalDisposers = []` after calling (prevents double-call) - [ ] Clears `fiber.parent = null` after disposal - [ ] Clears `fiber.effect = null` - [ ] Idempotent: calling `disposeFiber` twice is safe (no double-dispose, no errors) - [ ] Does NOT call `host.removeChild()` — that's the commit phase's job - [ ] `computed` signals are NOT explicitly disposed (they're garbage collected when references clear) - [ ] Only `effect()` return values need explicit disposal - [ ] New test: diposeFiber on a tree with 3 levels calls disposers and finalizeInstance bottom-up - [ ] New test: idempotent double-dispose does not error - [ ] New test: signal subscriptions are cleaned up (effect no longer fires after dispose) ## References - docs/architecture/lifecycle.md — Fiber Tree Disposal, Root Unmount Flow, Disposal Idempotency, computed vs effect Cleanup - docs/architecture/reconciler.md — Effect type "remove" ## Notes > To be filled by implementation agent ## Summary > To be filled on completion