Skip to content

refactor(signals): affects() dedicated channel + delete stashedOptimisticReads (arch audit tier-1)#2923

Merged
ryansolid merged 1 commit into
nextfrom
arch/tier1-affects-reveal
Jul 20, 2026
Merged

refactor(signals): affects() dedicated channel + delete stashedOptimisticReads (arch audit tier-1)#2923
ryansolid merged 1 commit into
nextfrom
arch/tier1-affects-reveal

Conversation

@ryansolid

Copy link
Copy Markdown
Member

The two Tier-1 architecture consolidations that survived design-spike measurement (spikes 1 and 3 were declined — pull-verdicts is spec-pinned by the #2831/lane-held wake schedule and measured size-neutral; store node-authority costs +585 min). Each of these retires a mechanism family, not a line.

Δ full (min/gz) Δ floor (min/gz)
Combined −775 / −304 −388 / −169

affects() off the async status rails

A mark becomes a refcount on the marked node(s) plus a pull-computed coverage walk at verdict time; Loading interaction survives as a boundary-only visual notification. Because marks never touch _statusFlags/_error/_pendingSources/_asyncReporters, the five carve-out families that existed only to un-teach the async rails everything a mark does — value-transparency, transaction-inertness, error-inferiority, settle-release, quiet-reask immunity — are deleted as unrepresentable rather than maintained. The per-read affects collection and per-recompute mark bookkeeping also leave the core read/recompute hot paths (a small simplification of the paths Sierpinski exercises).

Designer rulings encoded as the channel's structural contract: marks are invisible to all completion/settlement accounting by construction — a mark can never block or legitimize ending its own transaction (the action holding the window is the real work); ambient marks (no transaction) are verdict-only and release at flush end; a mark serializes only inside a resumable transaction. Hydration capture now takes marked-covered nodes' real committed values (they carry no status), consistent with value-transparency.

delete stashedOptimisticReads

It forced a committed-view effect re-run when a transaction backgrounded — masking an active override from stale tracked reads (against A17's "do not mask the override from any read path") and un-rendering co-written optimistic flags mid-window — while engaging zero times across all prior tests. The queue stash and _gatedSubs replay are retained: they cover transaction-held reveal and silent-revert re-ask respectively, which are irreducibly distinct reveal actions; a spec comment records why they cannot physically merge (the design-spike negative result).

Tests

1077 pass (1073 prior, unchanged, + 4 new pins):

  • S3 — the backgrounded-transaction reveal shape: co-written optimistic flag stays rendered, user effects fire once.
  • S4 — a transaction-held effect must not leak during an interleaved ambient flush. This was a pre-existing coverage hole (the suite never interleaved ambient work with a stash); the queue stash is load-bearing and was previously untested.
  • isolation — deterministic recompute-count guards for the propagation/Sierpinski surgical-update property (the isolation CodSpeed's propagation:* benches measure by time; this asserts it by count, noise-free).

CodSpeed is the arbiter on hot-path shape — the coverage walk is O(upstream reachability) per marked-node verdict (was O(pendingSources)); flagged for the perf run. Every prior spike round taught that local wall-clock can't resolve these deltas, so the benches decide.

🤖 Generated with Claude Code

…sticReads

Tier-1 architecture consolidations from the growth audit — each retires a
mechanism family rather than shrinking one.

affects() off the async status rails:
- a mark is now a refcount + pull-computed coverage walk at verdict time;
  Loading interaction is a boundary-only visual notification
- marks never touch _statusFlags/_error/_pendingSources/_asyncReporters,
  so the five carve-out families (value-transparency, transaction-
  inertness, error-inferiority, settle-release, quiet-reask immunity) are
  deleted as unrepresentable, not maintained
- per-read affects collection + per-recompute mark bookkeeping leave the
  core read/recompute hot paths
- rulings (Ryan): marks invisible to all completion/settlement accounting
  by construction (never block or end their own transaction); ambient
  marks verdict-only, release at flush end; serialize only with a
  resumable transaction; hydration capture takes real committed values
  (value-transparency) since mark state carries no status

delete stashedOptimisticReads:
- forced a committed-view effect re-run on transaction backgrounding,
  masking an active override from stale tracked reads (A17 violation) and
  un-rendering co-written optimistic flags mid-window; engaged 0x in the
  suite. queue stash + _gatedSubs retained (distinct reveal actions);
  spec comment records why they can't merge.

Full 56,904->56,129 min / 21,201->20,897 gz; floor 18,238->17,850 /
7,453->7,284. 1077 tests pass (1073 prior + S3 reveal pin, S4 queue-stash
guard for a pre-existing coverage hole, deterministic recompute-count
isolation guard for the propagation/Sierpinski property).

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

cursor Bot commented Jul 20, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@changeset-bot

changeset-bot Bot commented Jul 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1035c9c

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

@github-actions

Copy link
Copy Markdown

size-limit report 📦

Path Size
signals: core floor (createSignal/Memo/Effect/Root/flush) 6.5 KB (-1.86% 🔽)
signals: + createStore 11.08 KB (-1.16% 🔽)
signals: + isPending/latest 8.1 KB (-0.95% 🔽)
app: render + one signal (the simple-app floor) 9.07 KB (-1.44% 🔽)
app: CSR with Show/For/Loading/Errored/lazy 11.09 KB (-1.04% 🔽)

@coveralls

Copy link
Copy Markdown

Coverage Report for CI Build 29783820848

Warning

No base build found for commit 2bf022e on next.
Coverage changes can't be calculated without a base build.
If a base build is processing, this comment will update automatically when it completes.

Coverage: 75.328%

Details

  • Patch coverage: No coverable lines changed in this PR.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

Requires a base build to compare against. How to fix this →


Coverage Stats

Coverage Status
Relevant Lines: 778
Covered Lines: 626
Line Coverage: 80.46%
Relevant Branches: 592
Covered Branches: 406
Branch Coverage: 68.58%
Branches in Coverage %: Yes
Coverage Strength: 14.11 hits per line

💛 - Coveralls

@codspeed-hq

codspeed-hq Bot commented Jul 20, 2026

Copy link
Copy Markdown

Merging this PR will regress 1 benchmark

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 3 improved benchmarks
❌ 1 regressed benchmark
✅ 117 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
merge 266.5 µs 369.6 µs -27.9%
merge 165.2 µs 73.5 µs ×2.2
reconcile: deep tree, 10 of ~12k paths subscribed 6.4 ms 3.3 ms +92.3%
updateSignals:update1to1 54.4 ms 51.5 ms +5.56%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing arch/tier1-affects-reveal (1035c9c) with next (2bf022e)

Open in CodSpeed

@ryansolid

Copy link
Copy Markdown
Member Author

CodSpeed: net strongly positive; the one regression is a shared-VM artifact

⚡ 3 improved · ❌ 1 regressed · ✅ 117 untouched

Benchmark BASE → HEAD
merge-merge-static(both 5,1,3,2) 165.2 → 73.3 µs ×2.3
reconcile: deep tree, 10 of ~12k paths 6.4 → 3.3 ms +92%
updateSignals:update1to1 54.4 → 51.5 ms +5.6%
merge-mixed(0,100,3,2) 266.5 → 369.6 µs −27.9%

Attribution (two isolation probe PRs, now closed)

  • stashedOptimisticReads deletion alone → clean, gate passed, 1 improvement.
  • affects-channel alone → reproduces the merge pair exactly: merge-mixed −27.9% and merge-static ×2.3. They are one coupled effect of simplifying read()'s shape.

Why merge-mixed is a measurement artifact, not a cost

merge-mixed builds objects whose properties alternate between a plain value descriptor ({value: 1}) and a plain-JS getter ({ get() { return 1 } } — no signal, no Solid primitive). It exercises merge's property-descriptor resolution over getter/value polymorphism; it never calls read(), link(), or any code this diff touches. So the −28% cannot be a per-operation cost from the change — it is V8 retiering the shared merge bench file's megamorphic descriptor-dispatch site because read() (called by other benches in the same process) changed shape. merge-static ×2.3 is the coupled other half of the same recompilation; the two always move together and neither reflects a real cost in the merged code.

Acknowledging merge-mixed on that basis. The real ledger — a 2.3× and a 92% improvement on paths the diff does touch, against zero reachable regressions — plus the architecture win (five affects carve-out families deleted as unrepresentable; the affects fix-cluster retired) is the reason to land.

@ryansolid
ryansolid merged commit c04931b into next Jul 20, 2026
4 of 5 checks passed
@ryansolid
ryansolid deleted the arch/tier1-affects-reveal branch July 20, 2026 23:02
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