Skip to content

fix(agera): queue batch and trigger writes onto a running flush instead of draining it - #256

Merged
dangreen merged 1 commit into
mainfrom
fix/agera-batch-in-flush
Sep 12, 2026
Merged

dangreen merged 1 commit into
mainfrom
fix/agera-batch-in-flush

Conversation

@dangreen

Copy link
Copy Markdown
Member

Why

A plain signal write inside a running flush joins its queue (!batchDepth && !flushDepth), but batch and trigger only checked batchDepth. When one of them ended inside a flush, it called flush() again and drained the rest of the queue on the caller's stack.

In nanoviews this happens when code rendered from a flush (a swapped if_/switch_ branch, a for_ reconcile) calls batch or trigger, directly or through a library call:

  • a queued show_ toggle starts the branch's deferred scope while its body is still running, so effects created before the batch run before the tree is built, and the ones after it see a started scope;
  • a row body that batches runs startRows early, and the rows created after it in the same reconcile are never started: for_ going from [1] to [1, 2, 3] left the new rows' value$ bindings empty.

What

  • batch and trigger flush only when batchDepth drops to zero outside a running flush. Inside a flush their writes are picked up by the flush that is already running.
  • Tests: batch > should queue writes onto the running flush when called inside an effect and trigger > should queue updates onto the running flush when called inside an effect. Both fail on main: the queued effects ran before the effect that called batch/trigger finished.

Size

No limit changes. agera, measured with size-limit against the rebuilt dist:

bundle before after
All publics (Gzip) 3358 B 3358 B
All publics (Brotli) 3093 B 3092 B
Minimal set (Gzip) 1623 B 1623 B
Popular set (Gzip) 2065 B 2065 B

size-limit passes in every package that has it, and every limit still equals its size rounded up to 0.05 kB.

Checks

  • oxlint, tsc --noEmit and vitest run pass in packages/agera (183 tests).
  • vitest run passes in kida, store, query, router, intl, ssr, react, preact, svelte, react-router, preact-router, svelte-router, next-router, svelte-kit, react-ssr, preact-ssr, svelte-ssr and platform-web.
  • nanoviews: its suite passes against this agera except internals/effects.spec.ts "should stop rows when the branch is hidden during rows start", which pins the old immediate teardown through batch(() => $show(false)) inside a row effect. It has to be updated when nanoviews picks up this version.

…nstead of draining it

A `batch` or `trigger` that ended inside a running flush drained the rest of the queue on the caller's stack, while a plain signal write already joined the running flush. Code rendered from a flush that batched a write could then run queued effects in the middle of the render: a deferred scope started before its body finished, and rows created by the same reconcile were never started.
@codecov

codecov Bot commented Sep 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.41%. Comparing base (39ebdc0) to head (6021b57).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #256      +/-   ##
==========================================
+ Coverage   83.30%   83.41%   +0.11%     
==========================================
  Files          98       98              
  Lines        2557     2557              
  Branches      552      552              
==========================================
+ Hits         2130     2133       +3     
  Misses        314      314              
+ Partials      113      110       -3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@dangreen
dangreen merged commit d6afbdd into main Sep 12, 2026
10 checks passed
@dangreen
dangreen deleted the fix/agera-batch-in-flush branch September 12, 2026 22:57
@github-actions github-actions Bot mentioned this pull request Sep 12, 2026
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.

1 participant