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).
56 lines
2.4 KiB
Markdown
56 lines
2.4 KiB
Markdown
---
|
|
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 |