Skip to content

Refactor: Fine-Grained Reactive Data Context#183

Open
jlukic wants to merge 8 commits intomainfrom
feat/fine-grained-reactivity
Open

Refactor: Fine-Grained Reactive Data Context#183
jlukic wants to merge 8 commits intomainfrom
feat/fine-grained-reactivity

Conversation

@jlukic
Copy link
Copy Markdown
Member

@jlukic jlukic commented May 5, 2026

@vercel
Copy link
Copy Markdown

vercel Bot commented May 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
semantic-next Ready Ready Preview, Comment May 6, 2026 1:00am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
mcp Ignored Ignored Preview May 6, 2026 1:00am

Request Review

@semantic-performance-bot
Copy link
Copy Markdown

semantic-performance-bot Bot commented May 5, 2026

🟡 Mixed Performance (Net Positive) for f5f82a1 on Benchmark Suite 📊

Base: main · Action: #25410752474 · Raw: bench-report.json

Refactor: Fine-Grained Reactive Data Context

Warning

This PR improves ✅ 7 tests while regressing on ❌ 2 tests.

✅ 7 faster · ❌ 2 slower · 🔍 19 unsure · ⚪ 36 no change · 🏆 2 new peaks · 📜 9 reopened


✅ Faster (7)

Metrics where this PR confidently improved performance compared to main.

metric Improvement
clear-completed-250 -52% (29ms) 🌟
remove-row-front-20 -39% (207ms) 🌟
remove-first-10 -12% (21ms)
remove-5-front -7% (6ms)
remove-5-back -6% (4ms)
remove-last-10 -5% (7ms)
toggle-first-10 -3% (5ms)

❌ Slower (2)

Metrics where this PR confidently regressed performance compared to main.

metric Regression
bulk-add-500 +10% (22ms)
each-mount-1000 +4% (2ms)

🏆 New peaks (2)

These metrics reached a new best in this iteration — current's percent-delta vs its baseline dominates the prior peak's percent-delta vs its baseline. Credit candidates are the commits between the prior peak and HEAD; nearest-to-current is usually the cause.

metric current prior peak vs prior peak credit candidates
remove-5-back -6% -2% @ aaeb304 improved 4% 9d8761e
toggle-10 -2% +1% @ 9d8761e improved 2%

📜 Regressions from peak (9)

These metrics were better on a prior iteration than they are now. The peak's percent-delta vs its baseline dominates current's percent-delta vs its baseline — not attributable to per-sample noise. Bisect candidates are the commits between the peak iteration and HEAD; nearest-to-peak is usually the best bet.

metric current peak vs peak bisect candidates
remove-row-middle-20 -1% -21% @ aaeb304 regressed +20% 9d8761e
remove-row-front-20 -39% -56% @ aaeb304 regressed +18% 9d8761e
filter-cycle-20 +2% -11% @ aaeb304 regressed +13% 9d8761e
bulk-add-500 +10% +1% @ aaeb304 regressed +8% 9d8761e
remove-5-front -7% -13% @ aaeb304 regressed +6% 9d8761e
each-mount-1000 +4% +0% @ aaeb304 regressed +4% 9d8761e
edit-start-10 +2% -1% @ 9d8761e regressed +3%
remove-10-middle +0% -2% @ 9d8761e regressed +2%
remove-first-10 -12% -14% @ 9d8761e regressed +2%
⚪ No Change (36)

Metrics where this PR measured within ±2% of main — no meaningful performance change detected.

metric Change
active-indicator-200 0.0% – 0.0%
active-indicator-nested-200 -0.1% – -0.0%
add-20 -0.1% – 0.0%
edit-cycle-5 -1.8% – -1.6%
hydrate-each-100 +0.7% – +1.8%
hydrate-each-100-mount -0.7% – +0.6%
hydrate-helper-100-state-change -0.3% – +1.0%
micro-build-html-string-10k -0.2% – +1.9%
micro-compiler-parse-cold-complex-200 -0.6% – +0.7%
micro-compiler-parse-cold-normal-500 -1.1% – +1.4%
micro-compiler-snippet-args-5k -0.7% – +0.2%
micro-dom-walker-1000x15 -0.5% – +1.8%
micro-expr-js-10k -0.8% – +1.6%
micro-expr-lisp-50k -1.3% – +0.5%
micro-expr-simple-100k -0.9% – +1.0%
reaction-coalesce-200x100 +0.0% – +1.8%
reaction-dep-diff-30k -0.8% – +1.9%
remove-10-middle -0.1% – +0.7%
remove-middle-10 -1.6% – -1.2%
remove-row-middle-20 -1.7% – -0.2%
rename-50 -0.3% – -0.2%
signal-computed-chain-10x60k +0.3% – +1.1%
signal-reactive-fanout-500x1200 -1.1% – +0.9%
signal-reactive-list-replace-1000x1000 -0.5% – +1.0%
signal-reactive-multi-read-5x160k -1.1% – +0.5%
signal-reactive-set-property-by-id-200 -0.5% – +1.3%
signal-set-same-10m -2.0% – +1.5%
snippet-args-per-key-100 -0.0% – 0.0%
snippet-in-subtemplate-100 -0.0% – +0.0%
stable-ref-mutate-500 0.0% – 0.0%
subtemplate-data-blob-100 -0.6% – -0.5%
subtemplate-reactive-data-100 -1.4% – -1.0%
subtemplate-shorthand-props-100 -0.5% – -0.3%
swap-rows-20 -1.1% – +1.4%
toggle-10 -2.0% – -1.3%
toggle-all-20 -1.1% – -0.9%
🔍 Unsure (19)

Inconclusive (11)

The measured difference is small, and our sampling couldn't confidently place it above or below zero. Running more samples in a future run might settle these metrics.

metric Change Expected Noise
append-1k -6.2% – -0.7% ±2%
clear-10k +0.2% – +8.4% ±1%
create-10k +0.8% – +2.0% ±0%
create-1k +0.7% – +4.4% ±2%
edit-start-10 +0.6% – +2.5% ±1%
filter-cycle-20 +0.8% – +3.3% ±0%
remove-row-back-10 +0.7% – +2.9% ±1%
select-40 -2.6% – -1.3% ±0%
signal-reactive-list-filter-1000x300 -0.8% – +2.1% ±1%
signal-reactive-push-2000x20 -2.4% – +0.3% ±1%
update-10th-10 -2.1% – +1.7% ±1%

Too Fast to Measure Precisely (8)

On benches this short, system jitter (scheduling, GC, JIT) masks sub-4% changes; larger deltas still resolve cleanly.

metric Change Test Time Expected Noise
hydrate-helper-100-mount -2.3% – -0.1% ~45ms ±3%
micro-compiler-ast-walk-5k -0.1% – +3.9% ~15ms ±10%
reaction-flush-noop-5m -0.7% – +2.9% ~56ms ±3%
replace-1k -1.0% – +2.1% ~79ms ±2%
signal-reactive-set-index-300 -2.1% – -0.0% ~103ms ±2%
signal-sub-unsub-100k -0.7% – +3.6% ~21ms ±8%
toggle-last-10 -2.3% – -1.1% ~155ms ±1%
toggle-middle-10 -2.3% – -1.6% ~159ms ±1%
📖 Bench glossary (56 metrics)
metric what it tests
add-20 Appends 20 todo items one at a time, like a user typing entries in a row.
append-1k Appends 1000 new rows onto an existing 1000-row table.
bulk-add-500 Renders 500 todo items added at once from a single data load.
clear-10k Clears a 10000-row table back to empty in a single operation.
clear-completed-250 Clears 250 completed items from a 500-item list in one action, like clicking clear completed.
create-10k Renders a fresh 10000-row table into an empty parent at ten times the create-1k scale.
create-1k Renders a fresh 1000-row table into an empty parent.
each-mount-1000 Mounts a fresh 1000-item each block with five-field items so per-record allocation cost dominates the wall clock.
edit-cycle-5 Runs 5 full edit-then-save cycles on different items, like editing a row and saving it.
edit-start-10 Enters edit mode on 10 different items in a row, like double-clicking each one.
filter-cycle-20 Cycles through active, completed, and all filters 20 times on a 100-item list.
hydrate-each-100 Reassigns the items of a hydrated 1000-item list to a fresh array with the same keys and data.
hydrate-each-100-mount Hydrates a server-rendered 1000-item list and waits for it to become interactive without re-rendering.
hydrate-helper-100-mount Hydrates a 1000-item list where each item calls a helper that reads state shared across the list.
hydrate-helper-100-state-change Cycles the shared activeID through 10 different items in a hydrated 1000-item list so two items repaint per cycle.
micro-build-html-string-10k Builds the HTML string for a realistic card AST 10000 times. Raw assembly throughput.
micro-compiler-ast-walk-5k Walks a kitchen-sink AST through optimizeAST 5000 times. Merge, hoist, and recurse pass.
micro-compiler-parse-cold-complex-200 Compiles a feature-dense kitchen-sink template 200 times. Catches parser regressions on uncommon block paths.
micro-compiler-parse-cold-normal-500 Compiles a TodoMVC-style component template 500 times. Headline metric for normal-component compile throughput.
micro-compiler-snippet-args-5k Parses four representative subtemplate-call shapes 5000 times each. Snippet args extraction.
micro-dom-walker-1000x15 Runs bindMarkers across a 1000-node card fragment 15 times. TreeWalker pass and binding dispatch.
micro-expr-js-10k Evaluates one arithmetic expression and one ternary 10000 times each. JS-eval hot path.
micro-expr-lisp-50k Evaluates one Lisp-style helper call 50000 times. Parse-cache lookup and helper dispatch.
micro-expr-simple-100k Evaluates one simple identifier and one dotted path 100000 times each. Property-lookup hot path.
reaction-coalesce-200x100 Sets one signal 100 times then flushes once across 200 bursts so 100 subscribers wake one time per burst.
reaction-dep-diff-30k Toggles which of two signals a subscriber reads across 30000 cycles. Per-run dep-set diffing.
reaction-flush-noop-5m Calls Reaction.flush() 5000000 times with no pending work. Scheduler dispatch overhead.
remove-10-middle Deletes 10 items from the middle of a 100-item list, one click at a time.
remove-5-back Deletes 5 items from the end of a 100-item list, one click at a time.
remove-5-front Deletes 5 items from the front of a 100-item list, one click at a time.
remove-first-10 Deletes the first item 10 times from a 100-item list, with remaining items moving up each time.
remove-last-10 Deletes the last item 10 times from a 100-item list, with no other items needing to move.
remove-middle-10 Deletes the middle item 10 times from a 100-item list, walking halfway through to find each target.
remove-row-back-10 Removes the last row 10 times from a 1000-row table, with no other rows needing to move.
remove-row-front-20 Removes the first row 20 times from a 1000-row table, with all remaining rows sliding up each time.
remove-row-middle-20 Removes the middle row 20 times from a 1000-row table, with the rows below it sliding up each time.
rename-50 Renames 50 different items in a 100-item list via single-field setProperty without editingId co-fires.
replace-1k Replaces 1000 rows with a fresh 1000-row set, diffing the keyed list against a populated table.
select-40 Highlights one row at a time across 40 rows so only the previous and newly highlighted rows update.
signal-computed-chain-10x60k Propagates a value change from root to leaf through a 10-deep chain of derived signals 60000 times.
signal-reactive-fanout-500x1200 Fans out one signal's value change to 500 subscribers across 1200 successive updates.
signal-reactive-list-filter-1000x300 Changes a search-term signal 300 times, re-scanning a 1000-item list on each change.
signal-reactive-list-replace-1000x1000 Replaces a 1000-item list signal with a fresh 1000-item array and rescans it 1000 times.
signal-reactive-multi-read-5x160k Changes five signals in turn for 32000 rounds with one subscriber reading all five.
signal-reactive-push-2000x20 Appends 20 items onto an empty list signal with a subscriber, across 2000 reset cycles.
signal-reactive-set-index-300 Replaces one item by index in a 1000-item list signal across 300 updates, with a subscriber.
signal-reactive-set-property-by-id-200 Finds an item by id and updates one field in a 1000-item list signal across 200 alternating updates.
signal-set-same-10m Sets a signal to its current value 10000000 times. Exercises the no-op fast path when nothing changes.
signal-sub-unsub-100k Creates and tears down a subscriber on one signal across 100000 cycles. Subscription churn cost.
swap-rows-20 Swaps the second and second-to-last rows in a 1000-row table, repeated 20 times.
toggle-10 Checks off the first 10 items one by one, like a user working down a list.
toggle-all-20 Toggles all 100 items completed and back across 20 cycles via the master checkbox.
toggle-first-10 Toggles the first item in a 100-item list ten times, alternating completed on and off.
toggle-last-10 Toggles the last item in a 100-item list ten times, alternating completed on and off.
toggle-middle-10 Toggles a middle item in a 100-item list ten times, alternating completed on and off.
update-10th-10 Updates the label on every tenth row of a 1000-row table, looped ten times to lift the work above noise.

Sample size: 50 · Resolution floor: ±2% · Timeout: 3min · Wall-clock: 21m24s

@github-actions github-actions Bot added Reactivity Modifies reactivity package CI modifies continuous integration labels May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI modifies continuous integration Docs Modifies documentation Reactivity Modifies reactivity package Tests Modifies tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant