feat(agera): derive mounted state from the graph instead of counting subscribers - #191
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #191 +/- ##
==========================================
+ Coverage 84.23% 84.54% +0.30%
==========================================
Files 138 139 +1
Lines 3026 3112 +86
Branches 565 580 +15
==========================================
+ Hits 2549 2631 +82
- Misses 339 343 +4
Partials 138 138 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…subscribers - replace the subscriber counters with a presence model: mounted state is never stored, it is a question asked of the graph - does this node have a live path up to an effect - memoized per drain and invalidated by any edge edit - deliver mount and unmount as one level change from a coalescing queue at quiescent boundaries: churn inside a turn is silent, sources mount before their dependents and unmount after them - move the layer behind two lazy sockets wired on first `mountable()` use, so a signal-only bundle drops it entirely: `signal` -17%, `nanoviews` -4% - `onMounted` and the new `isMounted` live in `signal.ts` over a plain listener list; `node.subsCount` and `node.mounted` are gone - an `onMounted` listener registered while the signal is already mounted now gets `true` at the next boundary instead of waiting for the next cycle - fix late contagion and late `mountable()` never mounting a signal, a cold computed unmounting a signal under a live subscriber, stuck `mounted(true)` on discarded subscriptions, listeners skipped or served twice when one un-subscribes or registers during a fire, and delivery lost for other signals when a listener throws
dangreen
force-pushed
the
feat/presence-lifecycle
branch
from
August 10, 2026 10:49
3b62ddd to
2cc1f8c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Holistic rework of the signal lifecycle: the mounted state is no longer a counter maintained on every node, it is derived from the graph on demand.
mountable()use, so a signal-only bundle drops it entirely:signal-17%,nanoviews-4%onMountedand the newisMountedlive insignal.tsover a plain listener list;node.subsCountandnode.mountedare goneonMountedlistener registered while the signal is already mounted now getstrueat the next boundary instead of waiting for the next cyclemountable()never mounting a signal, a cold computed unmounting a signal under a live subscriber, stuckmounted(true)on discarded subscriptions, listeners skipped or served twice when one un-subscribes or registers during a fire, and delivery lost for other signals when a listener throwsSizes (brotli, vs the previous mechanism): agera
{ signal }1606 -> 1332, minimal set 1791 -> 1503, popular set 1917 -> 1917, all publics 2630 -> 2715; nanoviews all publics 7126 -> 6807, average usage 4330 -> 4049.Verified with the full test chain (agera 125 + 1 expected fail, kida 61, store 57, nanoviews 72, query 162, router 129), size-limit across all packages, randomized differential fuzzing of presence, ordering and listener interleavings, and a real-browser benchmark at parity.
🤖 Generated with Claude Code