Version 1.4.1
What's Changed
Fixed
List.get()never established child-signal edges on first read, leaving reads permanently stale (src/nodes/list.ts):createList()reset a freshly initialized node's flags fromFLAG_DIRTYto0right after building its items, on the theory that the cached value was already correct and no recompute was needed. Butget()'s first-access branch relies onrefresh()callingrecomputeMemo()— which tracked-callsbuildValue()and thereby links each child item signal as a source of the list's node — andrefresh()only does this whenFLAG_DIRTYis set. With the node starting clean, the very firstget()no-op'd,node.sourcesstayednullforever, and the list never reacted to a nested item's own signal changing unless a mutation method (add/remove/splice/etc.) later forcedFLAG_DIRTY | FLAG_RELINK. Now the node startsFLAG_DIRTY, matching how every otherMemoNodeinitializes.ensureFresh()'s eager re-entrant access path silently dropped the changed-cascade to downstream sinks (src/nodes/list.ts,src/nodes/store.ts,src/nodes/collection.ts):List.get(),Store.get(),createCollection().get(), andderiveCollection'sensureFresh()shared a two-step recompute shape — an untrackedbuildValue()pre-write tonode.value, followed by a trackedrefresh()/recomputeMemo()only whenFLAG_RELINKwas set.recomputeMemo()decides whether to promote downstreamFLAG_CHECKsinks toFLAG_DIRTYby diffing its freshly tracked-built value againstnode.value— but that value had already been overwritten to the same result by the untracked pre-step, so the diff was always trivially "unchanged" and the cascade never fired. This only surfaced when a sink two-plus hops downstream, reachable only viaFLAG_CHECK, was read out-of-band — e.g. an eager.byKey()/.get()/.keys()call racing ahead of the normal effect-queue-drivenrefresh()cascade.List.get(),Store.get(), andcreateCollection().get()now checkFLAG_RELINKbefore callingbuildValue(), skipping the untracked pre-write when a tracked recompute is about to happen.deriveCollection'sensureFresh()still needs its untrackedbuildValue()call (it discoversFLAG_RELINKas a side effect viasyncKeys()), so instead it stops writing that result intonode.valuewhen the flag comes back set, leavingrecomputeMemo()'s own tracked build as the sole write.
Full Changelog: v1.4.0...v1.4.1