feat(signals): UNSTABLE_MEMO_OUTPUT attribution warning - #3034
Merged
Conversation
The fan-out amplifier detector from the solidjs#3018 follow-up discussion: a memo that commits a referentially-new but shallowly-equivalent plain object/array on N consecutive runs (default 4) has an equality gate that never closes - every subscriber re-runs on every upstream change, a signature previously findable only by profiling. Engine-side only, per review: no new core hook sites. recomputeStart snapshots the node's committed value (mirroring recompute's own pending-aware prev resolution); recomputeEnd shallow-compares on plain, non-overlay changed memo runs. Plain objects and arrays only - promises, dates, class instances have no representative own keys and would false-positive. Key-capped at 64 so hot paths stay cheap. Warns once per streak; a genuinely different value resets it. Opt-out via enable({ unstableMemos: false }); threshold configurable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: c383795 The changes in this PR will be included in the next version bump. This PR includes changesets to release 9 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Follow-up to #3018 (the "spec now" item from the warnings discussion): the fan-out amplifier detector.
What it catches
A memo that commits a referentially-new but shallowly-equivalent plain object/array on N consecutive runs (default 4) has an equality gate that never closes — every subscriber re-runs on every upstream change. A wide memo with fresh object output is the single worst fan-out machine in real apps, and until now was only findable by profiling.
Implementation — engine-side only, no new core hook sites
recomputeStartsnapshots the node's committed value into the existing per-run frame (mirroring recompute's own pending-aware prev resolution, since an earlier run in the same flush may still be holding in_pendingValue).recomputeEnd, notderivedChanged: that hook fires before the commit branches, when the new value is still a local insiderecompute. ByrecomputeEndit is observable via_pendingValue/_value, and the phase facts are in hand.enable({ unstableMemos: false }), threshold configurable.One robustness fix surfaced by the tests: an explicit
undefinedinenable()options clobbers defaults through the spread, so the check treats any non-number as disabled rather than warning on run 1.Tests
5 new in
tests/attribution-unstable-memo.test.ts: warns once at threshold (runs: 4) for fresh-equivalent objects; arrays; streak resets on genuine change; silence for stable refs / primitives / Dates; opt-out. solid-signals suite green (1323).🤖 Generated with Claude Code