fix(signals): OBSERVE.exclude covers store nodes and interaction writes - #3380
Conversation
🦋 Changeset detectedLatest commit: f880165 The changes in this PR will be included in the next version bump. This PR includes changesets to release 11 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 |
Coverage Report for CI Build 34726992502Coverage remained the same at 71.842%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
A root write to an excluded subject no longer counts toward the interaction that made it, and an interaction whose writes all went to excluded subjects with none of the app's work run — a click on a devtools panel's own button — is dropped from the ring and never delivered. Store nodes were never excluded subjects: registerGraph's `_owner` stamp on the proxy is swallowed by the set trap outside a draft. The root target now keys its creating owner and nodes copy it into `_owner` as they are created, under the same engine-installed gate as node naming. Found by the Sentry spike's record-driven adapter. Engine scenario 26888 -> 26944 B; observe CSR tier unchanged. Co-authored-by: Claude via Cursor <noreply@cursor.com> Co-authored-by: Cursor <cursoragent@cursor.com>
… installed A WeakMap.set per fresh store regressed the 2000-store create+commit shape (~+30% locally, CodSpeed -11.7%). Gate it on attrHooks like the node stamping it feeds; disabled it bought nothing. Size note rebased. Co-authored-by: Cursor <cursoragent@cursor.com>
2daff9c to
f880165
Compare
|
What
OBSERVE.exclude(owner)now covers writes and stores, not only runs and diagnostics:registerGraph(proxy, owner)never landed on a store: the proxy's set trap swallows writes outside a draft, soisExcluded(storeNode)was alwaysfalse. The root target now keys its creating owner (a WeakMap, one set percreateStore) and the store's nodes (value, presence, key-set, deep) copy it into_owneras they are created — under the sameattrHooks !== nullgate as node naming, so node creation's disabled cost stays one null check.registerGraphstill runs for the dev tier's owner signal lists /onGraph.stampWriteroutes a root write to an excluded subject intoInteractionState.excludedWritesinstead ofevent.writes.writes 0, runs 0, created 0, excludedWrites > 0at settle → removed from the ring, never delivered onsubscribe("interaction"). An idle click that wrote nothing at all is still recorded (that's a fact about the app).Why
Found by the Sentry spike's record-driven adapter (rewritten on the rc.8
subscribe(type)channel): clicking the panel's own "clear" button produced aui.interaction.clicktransaction withwrites 1, runs 0, even with the panel root excluded and the write made underrunWithOwner(panelOwner). The documented contract is that the engine records nothing about the observer's own subtree; this closes the two paths that leaked.Adapter-side consequence, now in the doc paragraph: the store must be created under the excluded owner, not only written under it.
Size
Engine scenario 26888 → 26944 B (+56 B), limit 26.92 → 26.98 KB with a note. The observe CSR scenario did not move (no observe scenario bundles stores); prod tiers are
__OBSERVE__-gated and unchanged.Tests
observe-exclude.test.ts: "forgets an interaction whose only writes went to the panel's own store" — fails without the change (record present,outcome: idle), passes with it; also asserts a click that writes the app and the panel is recorded withwrites 1.Companion router fix from the same spike run: solidjs/solid-router#604 (guard redirect in the landing flush recorded as a hop,
RouterIntegration.inflight).