Skip to content

feat(signals): WIDE_WRITE attribution warning - #3035

Merged
ryansolid merged 2 commits into
solidjs:nextfrom
brenelz:wide-write
Aug 22, 2026
Merged

feat(signals): WIDE_WRITE attribution warning#3035
ryansolid merged 2 commits into
solidjs:nextfrom
brenelz:wide-write

Conversation

@brenelz

@brenelz brenelz commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #3018: the written-fan-out warning, implemented per the review guidance — via the dev-maintained _subCount from the graph-size diagnostics, no core sites touched, specced together with HUGE_FAN_OUT so the two never double-fire.

What it catches

A committed root invalidation — sync write, refresh(), or async landing — reaching a node with ≥ 250 live subscribers (default). Where the per-scope warnings blame the reader, this one blames the write: the fan-out actually happening, priced at the moment it happens.

[WIDE_WRITE] write to "selectedId" reached 1000 subscribers — every one re-runs
this flush. If consumers ask keyed questions of this value (for example every row
comparing against one selected id), invert with createSelector or createProjection
so only the keys whose answer flipped update.

Reconciliation with HUGE_FAN_OUT

  • HUGE_FAN_OUT: always-on, fires at link time from GRAPH_SIZE_WARN_AT (2000) up — structure so large it warns even if never written.
  • WIDE_WRITE: attribution-only, fires at write time from a much lower bar (250), because fan-out only costs anything when the node actually changes. Once per node, re-warning only after the subscriber count doubles — so a node that trips both gets at most one WIDE_WRITE alongside HUGE_FAN_OUT's own milestones.
  • Documented in documentation/solid-2.0/08-dev-diagnostics.md, with a Related: cross-reference under HUGE_FAN_OUT that mirrors the existing HUGE_FAN_INWIDE_SCOPE_DEPS pairing.

Implementation

One placement decision worth a look: the check lives in the engine's stampWrite rather than directly in the write hook. stampWrite is the single funnel for all committed root invalidations (writes, refresh(), async landings), so one call site covers all three — and inherits a correctness property for free: setSignal only stamps after the equality gate, so unchanged writes (which notify nobody) can never warn. The message's verb (write to / refresh of / async landing on) and data.write carry the kind.

Tests

5 new in tests/attribution-wide-write.test.ts: warns once at threshold with muting on repeat writes; re-warns only after 2× subscriber growth (30 → 55 silent, → 65 warns); fires for refresh() of a wide memo; quiet under threshold and for equality-gated unchanged writes; opt-out. solid-signals suite green (1323).

🤖 Generated with Claude Code

The written-fan-out detector from the solidjs#3018 follow-up discussion: a
committed root invalidation (sync write, refresh(), async landing)
reaching a node with >= 250 live subscribers (default) warns that
every one re-runs this flush, and points at createSelector/
createProjection for the keyed-question inversion.

Per review: no new core sites - reads the dev-maintained _subCount
from the graph-size diagnostics, checked inside the engine's
stampWrite, which is the single funnel for all committed root
invalidations (so unchanged writes, which stamp nothing, can never
warn). Specced together with HUGE_FAN_OUT so they don't double-fire:
HUGE_FAN_OUT is always-on at link time from 2000 up (static structure
warns even unwritten); WIDE_WRITE is attribution-only at write time
from a lower bar, once per node, re-warning only on 2x subscriber
growth. Documented in the dev-diagnostics RFC with the HUGE_FAN_OUT
cross-reference mirroring the existing HUGE_FAN_IN <-> WIDE_SCOPE_DEPS
pairing.

Opt-out via enable({ wideWrites: false }); threshold configurable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Aug 22, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c4a2f2f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@solidjs/signals Patch
test-integration Patch
solid-js Patch
babel-preset-solid Patch
@solidjs/web Patch
@solidjs/html Patch
@solidjs/h Patch
@solidjs/universal Patch
@solidjs/element Patch

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>
@ryansolid
ryansolid merged commit 269feae into solidjs:next Aug 22, 2026
3 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants