Status: accepted (Phase 1)
A long-lived application creates and destroys millions of reactive scopes. Any retained reference — a subscriber link, a context record, an event handler, a DOM node — accumulates. “No leaks” must be a tested property, not an intention.
WeakRef subscribers,
FinalizationRegistry cleanup). Removes whole classes of leaks, but makes
update semantics non-deterministic (a subscriber may vanish mid-flush) and
costs weak-ref overhead on the hottest structure in the framework.Option 2. Every subscription is created under an owner; owner disposal unlinks
every edge in both directions, runs cleanups, removes delegated handler entries
and detaches DOM. WeakRef appears only in tests, never in the runtime hot
path.
--expose-gc and explicit GC between
cycles; reported, not gated, on Firefox and WebKit where forcing GC is not
available.WeakRef probes: hold weak references to a disposed component’s signal,
owner and root DOM node; after forced GC, assert deref() === undefined. Only
executed where forced GC exists; skipped with a recorded reason elsewhere,
never silently.Strong references and pointer unlinking are the fast option; weak collections would add indirection to every subscriber walk. Disposal is O(edges in the subtree) with no allocation.
The point of the ADR: retained size after disposal returns to the pre-creation baseline modulo allocator noise, and that is asserted rather than assumed.
Developers rarely dispose manually — owners do it. The exception is code created
outside a component, where createRoot hands back an explicit dispose and the
documentation says plainly that not calling it leaks.
Weak-everything (non-deterministic updates, hot-path cost), detach-on-notify (unbounded retention), and “assume GC handles it” (untestable, and wrong as soon as one global subscriber list exists).