github solidjs/solid @solidjs/signals@2.0.0-rc.14

Patch Changes

  • 0c550fd: A render effect still on screen while an action holds its removal follows the lane's re-derivation of a memo it reads, as its direct latest() twin does (fuzzer adopted-staging case)

  • ecb68a1: Binding slots: the fill runs once per occurrence, untracked, under the occurrence's owner — as a component body and a template-slot fill do. State created in the fill lives as long as the occurrence; a top-level read is a one-time read (dev: STRICT_READ_UNTRACKED, naming the fill); getters are the reactive form. Handlers and refs are read once when an element binds and go through assign, so events delegate, tuples bind and interactions wrap as in client JSX. On the server an array at a handler position is a dev finding (reason tuple) instead of being flattened; only ref merges arrays. Template-slot fills are untracked on every render path and carry the same labelled warning.

    Breaking: AttributeSlot is renamed BindingSlot, with no alias, and its return is constrained (SlotOutput<J> / SlotError<M>, both exported) so an array, DOM node, function, async value or $-prefixed key is a type error on both sides. The diagnostic code ATTRIBUTE_SLOT_POSITION is renamed BINDING_SLOT_POSITION. The fill-shape finding also names async values.

  • b07fed5: A born-held render effect re-run as lane work (a latest() reader remounted during an action's hold) re-stages its value, so the commit applies the latest pass instead of the stale born-held one (fuzzer F13).

  • 21ff8f8: Infer createEffect and createRenderEffect compute results as const so inline tuple results retain their element types without a type argument or as const.

  • 1b9ceb6: Size audit (measurement branch): a derived store's derive reading a key (or container) a transaction holds through its draft — a user's write inside an action, held with it — joins that transaction, so the derive's whole result reveals with the action rather than key by key (core R31 / #3733: "under the transaction and revealed with it"; the derived-write-then-derivation-3733 action-hold pin). A user setter reading its own draft is no pass and joins nothing.

  • fa371c3: Compare optimistic store writes against the committed backing frame of chained stores, so a writable derived store's held staging cannot suppress an optimistic override.

  • 96c5e19: A derived store that returns rows from its own draft no longer recurses forever when its source refreshes: the projection draft wrapper resolves to its store proxy wherever the result carries it, so a retained row keeps its identity and stays readable, and an equivalent refresh doesn't re-notify its readers.

  • 9a213bb: Derived writes apply first, then derivations re-run. A manual write to a writable derived value (createSignal(fn), createStore(fn)) lands at once; when one of its sources changes — in the same update or later, inside or outside an action, across async holds — the function re-runs and receives the write as prev (or as the draft for createStore(fn)), and decides what to keep. A write on its own never re-runs the function.

    This reverses beta.11's same-tick precedence (#2692), where a write beat a source change in the same flush: a function that ignores prev now discards a write made in the same update as a source change, and a same-value write no longer holds against it. To keep a local value across source changes, carry it in the data as a flag the function honors. It also fixes #3733 (a write inside an action blocked later source changes for the whole hold, a regression since #2692) and supersedes the frame-scoped mask from #3740, whose changeset this replaces.

  • 721eb06: Attribution cost checks judge only what the scope's author can act on (#3739). WIDE_SCOPE_DEPS no longer counts HMR plumbing sources (the solid-js/refresh memo per component instance), skips framework scopes marked with the new internal dev-only _wide option (CONFIG_WIDE; not public API), and its wideDeps default rises from 30 to 200. The engine-side HUGE_FAN_OUT (fanOut) no longer counts plumbing subscribers. The always-on HUGE_FAN_IN and core HUGE_FAN_OUT (2000) keep no exceptions.

  • b07fed5: A render reader whose pass errored (NotReady included) before reaching a flight it read last time still holds that flight's transaction: a write no longer shows beside a reader still derived from the previous value while the flight is in the air (fuzzer F4).

  • bc51ada: A new async memo created over a held update now waits for it (#3800). A memo created while a transition holds a value, whose first pass reads that value and returns a promise, lands its first answer into the transition and reveals at its commit, as the same memo with a synchronous first answer already did. Before, the promise landed on its own and its readers showed the new value beside the rest of the page still on the old one. The transition never waits for the new memo's first load: if it lands after the transition commits, it is its own commit.

  • eaddda4: Fix false GRAPH_GROWTH warnings caused by the initial route declaration, which runs before page content mounts. The detector now compares completed visits while still emitting the initial graph record.

  • d231b99: An optimistic store over a store reads a property the inner store's reconcile removed as undefined instead of its last value (#3883)

  • 3086f1b: Fix an infinite flush loop ("Potential Infinite Loop Detected") when a latest()-gated Show mounts a fresh Loading under an action hold: lane work that reads a node born staged is no longer re-queued to re-derive on a committed value it doesn't have.

  • 3c7631a: ABANDONED_FLIGHTS no longer fires for a frames slot arg that every re-shipped record re-reads while it is still pending (#3852). Dev builds mark the per-key slot-arg memo with an internal option that the check skips; the memo's flights are still recorded and still counted in feedback().

  • 09eadfe: A fresh Loading mounted over a held value shows its fallback in a flush too (#3540 under L2): a first pass a loading boundary that has not shown content catches is the boundary's, not the tick's, so the mount publishes and the content reveals at the commit. Content bound by a render effect under the boundary is collected, so the boundary no longer reveals empty content.

  • be82cf3: Observe: one interaction frame per event, not per listener. InteractionRef takes an optional event; frames with the same event re-enter one interaction record, which stays joinable for the event's dispatch and is recorded at the next task. The web runtime keys its frames by the DOM event, and @solidjs/web exports dispatchAsInteraction(e, fn) so a listener outside the runtime (a router's document click handler) joins the frame of the same event — fn() in production builds. One anchor click is now one interaction record carrying both the onClick work and the navigation (#3754).

  • fd9f381: Fix L2 lane regressions found by the semantic fuzzer: a lane dissolving with a node still in flight marks it as committed beneath published inputs, so a mount or verdict reader observes the flight instead of being served a value that tears against them; a correction of a blocked lane drops the re-guess runs it parked instead of releasing them; and a lane pass's pending propagation no longer lists a born-held or mid-pass mainline render effect on the lane, so a mount over a memo of a lane flight is born held, control and content together.

  • b07fed5: A landing whose commits dispose a zombie re-judges the transactions parked at the same seam: a write held only because that zombie observed its flight now lands with the commit that disposes it instead of staying unpublished until an unrelated flush (fuzzer F3).

  • fff1615: A lane now holds through a Loading boundary showing content: a boundary output forwarding its tree's pending counts as a frame reader, so latest() no longer reveals beside the boundary's stale content (A33). An output that never committed — a mount the frame has not revealed — holds nothing. A corrected guess that never showed is void at the correction: untracked reads return the committed value (A18 amendment, 2026-10-05).

  • 11e9fb6: An element an optimistic guess mounts now lands together with its bindings (#3835). A first pass created by a guess's lane reads as the lane's, not just routes as it: a binding the lane mounts reads a write the action still holds as the screen (its committed value) and re-derives when the action lands. Before, a binding inside a memo the lane created was born held while the memo's element showed, so <div>Hello</div> appeared without its style until the action finished; directly under the lane pass the binding showed the held value early instead.

  • 11e9fb6: A Loading mounted by an optimistic write over a flight shows its fallback again (#3835's seat regressed it). Lane work with no committed value yet reads a pending flight the way a mainline mount's memo does: it enters and throws, so the boundary it mounts catches the pending (A29's boundary exemption), instead of being served the flight's committed value. A render effect is still a stale reader of a held flight (rule 3). Approach and tests from #3843 by @brenelz.

  • b0bad02: A lane's node inside a held frame stays the lane's: holdFrame no longer re-lists a verdict reader (or a derivation of a guess) created under a held pass on the frame's transaction, where the landing nulled its transaction with its lane value still on and the next read of it crashed (laneRead → txOf(null), REACTIVITY_HALTED) — a Loading over latest(x), or a memo of isPending(() => x()), unmounted and remounted while x is held (fuzzer F7a/F7b; A15 #3698: lane work never makes its node transaction work).

  • 0c550fd: A mainline mount whose child reads a lane derivation in flight shows the child as a stale reader beside its mount control, whether or not the lane is held (fuzzer F8)

  • 2317623: Fix a render effect a lane took over from a held transaction: it keeps running as the lane's work while it waits on the lane's flight, and drops the hold when it leaves the lane (#3766).

  • 4f67697: Breaking: only on followed by an uppercase letter (onClick, onPointerDown) is an event handler. Lowercase on* names (onclick, onmouseover) are plain attributes everywhere:

    • Both compilers compile onclick={expr} like any other attribute (setAttribute, reactive when expr is dynamic) instead of binding a delegated or native event, and SSR renders it as an escaped attribute instead of dropping it. A leftover 1.x on:click={fn} is likewise a plain namespaced attribute (it previously compiled to addEventListener(":click", fn)).
    • @solidjs/web spread/assign set lowercase on* keys as attributes, the server spread walk renders them, and useHead applies lowercase on* attributes (camelCase handler names stay skipped). ssrAttribute escapes a function value instead of interpolating its source raw.
    • @solidjs/html and @solidjs/h elements wrap a function passed to a lowercase on* in a getter like any other attribute; only onXxx and ref are exempt.
    • @solidjs/html components follow @solidjs/h's rule: every zero-argument function prop, onXxx handlers and ref included, is a getter, so a component handler must declare its event argument (onClick=${e => …}).
    • New dev-only check LOWERCASE_EVENT_ATTRIBUTE (added to the DiagnosticCode union): warns once per attribute name when a function is set on a lowercase on* (or on:) attribute, naming the camelCase handler to use.
  • 2317623: Fix an optimistic store over a derived store hiding its update after an action's local write to the same row: the row a held write staged is no longer guessed over the container's slot (#3796).

  • d1309ad: Resolve a writable derived store's retained draft row to its store proxy when an optimistic store chained over it writes, so the optimistic write to that row shows while its action is pending (#3859).

  • 924d909: A store fold's presence notification (in subscribers) now diffs the old and new presence of each observed key before writing the node, as the value notification already does (#3743). setSignal joins a held node's transaction before its equality gate (A34 (1): a write to a held node is a proposal, the same value or another), so a reconcile() outside an action that had deleted an observed key — the incoming snapshot leaving it absent too — made the whole tick the action's: an unrelated a.value stayed stale until the action settled. A real presence change still notifies and still proposes on a held node.

    The adoption's diff base now materializes a nested prototype-overlay draft (a wide owned record) before it is taken: through the overlay's prototype a key the draft had deleted still read as present, so the presence skip fired on a real deletion and a reconcile restoring the key never re-proposed on the held leaf (it committed the draft's undefined beside a backing that had the key).

    Two optimistic-store fixes the diff uncovered: a container carrying an arrangement guess is now told of an arrangement change whether or not anything subscribes to the container (for a guessed container the write is the landing that judges the guess — before, only the unconditional presence write reached the lane, so a newer question's rows landing beneath an optimistic push published beside it when the reader subscribed to leaves only); and an older truth re-based under an arrangement guess no longer re-stages a slot whose row the committed backing already shows by key, nor an unchanged length (a spurious frame for leaf-only readers).

  • 6be6c51: Remove the empty carved module reexport that caused TS2306 during the Signals build.

  • 7acc039: A render effect created while an action holds a value it reads no longer runs its callback when a later pass re-stages it before the action lands (#3802). That run passed undefined as the value, because the effect had nothing committed yet, so compiled JSX bindings threw and halted reactivity. The effect now runs once, at the commit that lands the action, with the latest staged value.

  • bde4299: The seam (settle) no longer pays the effect-queue merge on a plain flush — nothing parked, no lane reveal, no landing: this flush's runs are the queue as they stand instead of a concat copy, a parked flush stashes its runs in place, and the per-flush list resets run only when a list is non-empty. About 100 ns less fixed cost per flush (−11% on a 20k-key store commit, −45% on a one-signal flush), with the effect order of every other seam unchanged.

  • 1b9ceb6: Size audit (measurement branch): affects() rebuilt on the L2 hold model as ruled (A24 (4), the #2893 audit) — a declared in-flight change that lights up isPending on the marked accessor and its derivations for the surrounding transaction's lifetime; never a hold, never an entanglement, never a suspension. A count on the node, listed with its scope; coverage pull-derived at probe time; verdict readers re-derived at registration and release. The store targets return with the stores. Also: GlobalQueue's hook statics are declare static (type-only) — they emitted as static X; on every bundle.

  • 1b9ceb6: Attribution on the L2 hold model: the observe-tier engine is fed from the rebuilt lane and verdict layers again (hold census — blockers, optimistic/affects/isPending/latest acknowledgements; optimistic reverts labelled superseded vs reverted; loading-boundary fallback show/hide records; run posture). A lane derivation's first landing no longer trips the dev SETTLE_WALK_UNINITIALIZED_SOURCE tripwire.

  • 1b9ceb6: Size audit (measurement branch): the reactive engine rebuilt on the L2 hold model — transactions as the one hold relationship (membership, blocked, frame reads, born-held), with lanes (createOptimistic), verdicts (isPending/latest), boundaries (createLoadingBoundary/createErrorBoundary), createRevealOrder and action rebuilt on it as modules behind GlobalQueue hooks; stores, affects() and the attribution engine carved out pending their own steps. Every step is measured on the whole size suite and recorded in documentation/plans/size-reduction-carve-step1.md (§1–§28), with the maintainer's rulings that decided each behavior. Checkpoint before the §28 replay of the lane layer.

  • 1b9ceb6: Size audit (measurement branch): carve the lane layer — createOptimistic's write, isPending, latest — ahead of its rebuild from the §28 principles (documentation/plans/size-reduction-carve-step1.md). The layer measured 1775 B br on + isPending/latest and 1809 B br on the live page as built.

  • 1b9ceb6: Size audit (measurement branch): the lane layer rebuilt from the §28 principles (S0 skeleton). A node's value lives in one of three places — _value the committed truth, _pendingValue a transaction's staging, _x._lane the lane's value — and the lane transaction carries the shown/held state (_shown, _held); the seat of a pass is its node's; leaves read the screen; the body-end correction runs at the seam with one more pure round so its re-derivations are the parent's; a dissolving lane retires the void world's flights. Removes CONFIG_LANE_HELD, CONFIG_HELD_TRUTH, REACTIVE_VERDICT_RERUN and the seam-time value swap. Fixes #3409 (indicators of a body-end correction clear together) and the #3698 held-lane children case. Design and results in documentation/plans/size-reduction-carve-step1.md §28.

  • 1b9ceb6: Size audit (measurement branch): §28 S1 — holds and seams on the rebuilt lane layer. A render effect reading a lane flight that has never shown waits on it in its own frame and reads the landed answer at the landing (A15 LANE, #3334); a zombie's say is moot only for the transaction that disposes it (#3463); a lane-derived value committed at a dissolve publishes its inputs (#3648); a boundary re-armed through a display-ahead read swaps as the lane's from the head (#3540); any stale reader of a flight holds it, lane work included (V5/A17).

  • 1b9ceb6: Size audit (measurement branch): §28 S2 — verdicts and consolidation on the rebuilt lane layer. The verdict watchers merge into the lane layer's staged-readers list (one seam, one rule: a pass that read this flush's staging as the screen re-derives if the frame parks); one staleReader registration shared by frame reads, lane reads and verdict routes; dissolveLane restructured by outcome, every guess of a dissolving lane re-homed with its truth. No behavior change; 0 pins moved.

  • 1b9ceb6: Size audit (measurement branch): the spec pass. SPEC-ASYNC-SEMANTICS.md gains "The hold model — L2 (2026-10-04)" — the carve's rulings in the spec's voice, the 2026-10-03 re-pins, and a mechanism note (the per-rule "Mechanism (index, 2026-09-14/15)" paragraphs describe the pre-L2 implementation; the L2 module map is the cross-reference) — with dated amendments on A18, A19, A22, A29 and A34. INTERNALS-ASYNC-STATE.md gains "0. L2 — the hold model: what replaced §1–§4". RULES-INDEX.md regenerated; plan-section citations in src/ comments are written plan sec. N. Comment-only in source.

  • 1b9ceb6: Size audit (measurement branch): §41.4 benchmark fixes. A plain pass already marked as having read this flush's staging reads an unheld container staging directly — the per-key "did this key change" question is asked once per pass, not once per key (a mapArray over 1k shifted rows asked it 1k times; store array ops splice/shift/unshift/reverse/push on 1k proxied rows now at parity with next). At the fold, a child whose parent was adopted whole no longer re-resolves its slot by an O(rows) indexOf that cannot hit (the slot already holds the child's new backing).

  • 1b9ceb6: Size audit (measurement branch): §41 benchmark fixes. A derived store's family settle walk runs only after a wake (fam.woke), not on every sync commit — a 1k-row derived store's no-op re-derive was walking every leaf (14× the fork). A value read under a staging asks only whether the key's value or presence changed (readSource(target, key, shape)); descriptor readers and hold decisions keep the full enumerability/accessor test, as does any container with accessors seen. Keyed reconcile of 1k rows read by mapArray in the staging flush: 2.5× faster.

  • 1b9ceb6: Size audit (measurement branch): §41.5 — the container node's escape hatch (Q-A). A store staging gets its container node only when something can read the frame through it: a structural subscriber, lane work, a creation-time pass, or a derive a transaction holds. Otherwise the backing swap and the fold queue are the whole staging — nothing is allocated, queued or swept per container — and when a flush parks, the seam materializes and holds the node for every node-less staging (_storePark), so a never-read key of a held container still reads committed until the landing (pinned). The fold queue itself no longer allocates per batch: a reusable list plus a weak map of pre-batch backings written in place (a dbmon tick's ~7000 containers cost ~540 KB of map table per tick before). dbmon-deep tick 1.17–1.19× → 1.08–1.13× by the harness's own method; node parity.

  • 1b9ceb6: Size audit (measurement branch): the fold queue records a pre-batch backing only for adoptions (whose backing swaps eagerly), in a weak map written in place batch after batch; a draft's pre-batch backing is its own committed backing, so nothing is recorded for it — 2000 fresh one-key stores per flush had cost 2000 weak-map insertions and ran at 2× next (CodSpeed's fresh stores bench). The two rare moves of a draft's backing mid-batch (a privatization, a draft over an adopted raw) are kept in small per-batch maps.

  • 1b9ceb6: Size audit (measurement branch): §40 S3c — projection verdict windows and family pending on L2; the promise-delivery readers by posture. A probe answered before the flush had a transaction re-runs at the seam even when a later read routed its pass into the verdict lane (REACTIVE_PROBE_UNANSWERED); a render effect already observing a derive's flight keeps pulling it on re-run (the frame's hold is not dropped with its flight still up); the post-pass family wake fires only for a flight this pass registered (#3181); a derive's rejection reaches its leaves' readers (handleAsync gains an onError(error, pending) seam; errorFamily). wakeFamily stamps leaves with the derive as a pending source and propagates through core's own propagateStatus (split out of notifyStatus): branch recovery stays pending through another path, pending render effects are held by the frame. A refresh() during a non-quiet flight does not launder the new question; a quiet flight's landing writes are quiet through their reveal on stores. resolve/until/refresh's waiter deliver their own transaction's frame and, over a foreign hold, the committed view at its commit (#3482/#3490). The descriptor trap reads the backing the container's frame serves (#3706). Four pins re-ruled onto L2 / signal parity (plan §40.2): A22-3, #3662 step 1, #3585 never-resolving case, #3038 companion walk.

  • 1b9ceb6: One provenance test for a derivation's landing and a written landing alike (stale); signal/store twin pins for the overlapping-actions and kanban shapes.

  • 1b9ceb6: Optimistic stores: a landing is judged against the guess of the question it answers. Another action's landing beneath a guess is held beneath it (the truth for the commit), the guess keeps showing, and the guess's own landing judges it; an arrangement guess on a keyed list is re-based over the held truth by key (order from the guess, rows from the truth, new rows appended, rows the setter removed stay removed). Two overlapping list edits confirming out of order no longer snap back. A corrected lane that had shown keeps the runs it queued this round; a chained view's guess reverts against the inner store's live value.

  • 1b9ceb6: Stores on L2, S1: plain createStore returns (snapshot, deep, storePath, isWrappable, markRaw, $TRACK/$TARGET/$PROXY/$RECORD, storeIsShallow). A store is a tree of L2 nodes: one-literal slot nodes (slotSignal) for leaves, presence, deep witness and the container node — the $TRACK node given a value, whose staging is the pending backing, so the scheduler owns the backing's lifetime. Core: the slot-node sweep dispatch and the store commit hook; _devWindows becomes an observe-literal slot; mapArray reads $TRACK again. Derived stores, projections, reconcile and optimistic stores return on later steps.

  • 1b9ceb6: Stores on L2, S2: plain stores under holds. Every leaf read is core's read() (the hold rules — frame reads, joins, A28 — come from core, tracked or not); nodes are born from the two frames and held by the container's transaction only for keys the batch changed (#3706); structural reads take the container's frame; a setter's returned replacement is staged, not eager. Core: read()'s held arm now applies to untracked reads by a pass (a derivation of a held write is never published mainline — A29/A15).

  • 1b9ceb6: Stores on L2, S3a: createProjection, createStore(fn, seed) and reconcile return. The firewall is projection-only and lives in the store: every read through a projection pulls the derive first (core read() of it — untracked when settled, so nothing subscribes to the derive; tracked while a flight is up, so readers observe it as a memo's would); pending propagates to leaf readers by core's own dependent rule and settles at the landing; a derive's continuation writes join its hold; the creation run commits directly; adoption is eager with the container node keeping the committed frame. Core: the self-registered-flight probe in recompute is restored (projection-only, carved by mistake); an untracked verdict read of an uninitialized pending node links its reader as read() does. Derived-store manual writes follow A34 rule B (re-pinned).

  • 1b9ceb6: Stores on L2, S3b: holds on derived stores. A pass reading a key a held batch left unchanged reads committed and holds no one (#3706); a mainline setter above a held adoption publishes mainline for the keys the hold did not change (#3688); a user write to a key whose staging is a held derivation becomes the draft's prior state and the hold re-derives over it (A34 (3), #3612 — CONFIG_MANUAL_WRITE discriminates a user's proposal from the derive's derivation).

  • 1b9ceb6: Stores on L2, S4: optimistic stores on lanes. A user write to an optimistic store is a guess on the written key's node (presence and container arrangement guesses alongside), shown under the action's hold, confirmed or corrected by a landing beneath it, dissolved at settle — no store-side layer or backup snapshots. The committed backing is never touched by a guess. Reads compose per key through the nodes; a guess over an in-flight derive stands in for the flight (A17). Chained views (createOptimisticStore(base)) keep their links on the inner store's truth. A user's reconcile on an optimistic family writes the draft. The optimistic machinery is late-bound: a plain store does not carry the lane layer. Core: a slot node's flight is its family's derive (_slotFlight); an untracked read inside lane work derives from the lane; a pass that joined a hold before its first lane read is re-derived on the screen; linked lanes are judged by blocked; a supersession resolves the lane's merged parent.

  • 1b9ceb6: Store size pass after S4: the write override is a live binding (no accessor call on the get hot path); the optimistic draft and its set-aside staging live in the optimistic module; one predicate for the lane-view composition sites. Behavior unchanged.

  • 1b9ceb6: Stores on L2, S5: the store half of affects() — affects(store) marks the record's carrier and every live node under it, affects(record, key) the slot's leaf; coverage by raw identity (captured proxies, chained views, cross-family raws), nodes born in the window inherit the mark, untracked probes are witnessed. Ambient marks whose flush parks join its transaction; one over a node whose own flight is up (a declared reload) lives to the landing. StoreNode is exported again (the L2 target's shape).

  • 1b9ceb6: Stores on L2, S-U: merge/omit and the merge/omit view machinery (utils.ts) are back unchanged; the carve has no stubs left.

  • 1a3f87f: Store fold queue: the pre-batch committed backing is recorded beside the queued target and released with the drain. The weak map it replaces kept every container's last adopted-away backing alive until its next adoption — for a keyed reconcile, the previous tick's whole tree promoted out of the nursery every tick (the saturated listened-paths and reconcile-tree shapes ran 10–15% over next on that alone); for a store adopted once, the old tree for the store's lifetime. The per-batch side maps for mid-batch privatizations and drafts over adoptions fold into the same record.

  • 5622be8: UNSTABLE_MEMO_OUTPUT compares symbol-keyed properties too, so a memo returning a fresh symbol-keyed box each run (as dynamic does for an in-flight promise) is no longer reported as new-but-equivalent.

  • 11e9fb6: A mount made by a verdict reader stays mainline (#3851). Inside an action, <Show when={latest(x) > 0}> opens at once, but a <Loading> it mounts used to show content 1 beside the committed x = 0: the content's first pass was staged in the verdict lane its creator was in, and in the action's own flush it read the staged x before the seam held it. A first pass now takes its creator's lane only for an optimistic lane (head and tail of its pass alike); a mount a verdict lane makes whose first pass reads a staging of a flush with a transaction is born held like one that read a held node (other new memos do not join the transaction by being created); and verdict-lane work that read the frame's stagings re-derives on the committed world when the frame stays parked. The boundary shows its fallback and content 1 at the landing.

  • b07fed5: A memo pulled by an isPending/latest probe computes as its own pass, outside the probe's window: it no longer caches the committed input in place of a flushed write (fuzzer F10), or reads an uninitialized input as undefined instead of suspending (F11).

  • b0bad02: A verdict reader that reveals a flight nobody holds registers it with the frame (A15 first observer, #3458): observeFlight holds the flight's node in the frame's transaction, so the transaction waits for the landing instead of holding nothing, landing at its own seam and re-deriving the reader into the same observation every flush ("Potential Infinite Loop Detected") — an action whose body-end write re-asks an async memo as its verdict lane's work, revealed to a latest() reader the action adopted (fuzzer F12), or any memo re-asked unobserved and then revealed to a reader using latest()/isPending().

  • b07fed5: An isPending reader of an async memo settles when the memo's flight lands equal to its committed value: the settle walk re-derives the verdict reader instead of leaving it true (fuzzer F9).

  • b0c8489: A re-run that commits undefined is no longer counted as waste. A projection that mutates its draft or reconciles a returned value, or a memo that does its work by writing a signal, has no output to compare, so its re-runs were reported as pure cost. RerunEvent.changed now reports true for these runs (as it already did for side-effect-only effects), so WASTED_RECOMPUTE no longer fires for them and costs().wastedMs, expectNoWaste and the performance tracks stop counting them as wasted.

Don't miss a new solid release

NewReleases is sending notifications on new releases.