You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[2.0 / next] A derived store's per-key isPending reads false under a Loading that has shown content (D-30, S-37) #4269
Reproduced on next at 2a0da2f (2026-10-24), @solidjs/signals built from source. Run: node --conditions=browser --conditions=development dv4-signals.mjs [store|memo] [boundary|none].
Rule. RULES-DERIVED D-30: "a derived store's leaves report the
derive's new-question refetch like any async memo"; SCENARIOS S-37 row 2:
after setId(2), isPending(() => state.a) is true.
Shape.createStore(async draft => { Object.assign(draft, await fetch(id())) }, {}),
a render effect showing state.a and isPending(() => state.a), under a createLoadingBoundary that has shown content. setId(2).
The async memo under the same boundary reports pending; the same store
outside a boundary reports pending. Only the store-under-boundary
combination reads false. It shows when the verdict is read in the same computation as the value; with the verdict in its own {…} hole (as compiled JSX reads it) it reads true.
Repro
dv4-signals.mjs
// a derived store's per-key verdicts under a boundary that has shown content.// Expected (RULES-DERIVED D-30, SCENARIOS S-37 row 2): after setId(2), while the derive re-asks, isPending(() => state.a) is true.import{createRoot,createSignal,createMemo,createStore,createRenderEffect,createLoadingBoundary,isPending,flush,untrack}from"@solidjs/signals";constflights=newMap();constfetchKey=key=>{if(!flights.has(key)){letresolve;constp=newPromise(r=>(resolve=r));flights.set(key,{ p, resolve });}returnflights.get(key).p;};consttick=async()=>{awaitnewPromise(r=>setTimeout(r,0));flush();awaitnewPromise(r=>setTimeout(r,0));flush();};constland=async(key,v)=>{flights.get(key).resolve(v);awaittick();};const[kind,where]=[process.argv[2]??"store",process.argv[3]??"boundary"];letscreen="";const[id,setId]=createSignal(1);createRoot(()=>{leta;if(kind==="store"){const[state]=createStore(asyncdraft=>{constv=awaitfetchKey("s:"+id());Object.assign(draft,v);},{});a=()=>state.a;}else{constm=createMemo(()=>fetchKey("s:"+id()));a=()=>m().a;}constview=()=>`${a()}${isPending(a) ? "pending" : "-"}`;constout=where==="boundary" ? untrack(()=>createLoadingBoundary(view,()=>"loading")) : view;createRenderEffect(()=>out(),v=>{screen=v;});});flush();constshow=label=>console.log(label.padEnd(18),JSON.stringify(screen));awaittick();show("mount");awaitland("s:1",{a: 1,b: 1});show("s(1) lands");setId(2);flush();awaittick();show("setId(2)");// expected: "1 pending"awaitland("s:2",{a: 2,b: 2});show("s(2) lands");
Found by ReactiveScript's conformance suite, which diffs its spec against Solid's SCENARIOS.md.
Activity
fix(signals): clear a derived store's stale inputs-published mark at …
ryansolid commentedon Oct 26, 2026
Fixed on
nextby #4278 (f811097); it ships in the next RC.Generated by Claude Code