@solidjs/signals 2.0.0-rc.19 → 2.0.0-rc.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/dev-shared.js +553 -264
  2. package/dist/dev.attribution.js +18 -18
  3. package/dist/dev.js +1030 -439
  4. package/dist/observe/affects.js +12 -2
  5. package/dist/observe/boundaries.js +168 -115
  6. package/dist/observe/core/async.js +57 -37
  7. package/dist/observe/core/attribution.js +6 -6
  8. package/dist/observe/core/constants.js +9 -1
  9. package/dist/observe/core/copies.js +10 -0
  10. package/dist/observe/core/core.js +261 -181
  11. package/dist/observe/core/effect.js +32 -27
  12. package/dist/observe/core/graph.js +7 -7
  13. package/dist/observe/core/heap.js +29 -29
  14. package/dist/observe/core/lanes.js +301 -101
  15. package/dist/observe/core/owner.js +13 -13
  16. package/dist/observe/core/scheduler.js +124 -69
  17. package/dist/observe/core/truth.js +9 -7
  18. package/dist/observe/core/verdict.js +160 -98
  19. package/dist/observe/deferred.js +1 -1
  20. package/dist/observe/index.js +2 -0
  21. package/dist/observe/map.js +120 -116
  22. package/dist/observe/reveal.js +48 -48
  23. package/dist/observe/signals.js +5 -5
  24. package/dist/observe/store/affects.js +2 -2
  25. package/dist/observe/store/optimistic.js +272 -176
  26. package/dist/observe/store/projection.js +21 -10
  27. package/dist/observe/store/reconcile.js +8 -2
  28. package/dist/observe/store/store.js +91 -55
  29. package/dist/observe/store/types.js +11 -1
  30. package/dist/observe/store/utils.js +1 -1
  31. package/dist/prod/affects.js +12 -2
  32. package/dist/prod/boundaries.js +164 -109
  33. package/dist/prod/core/async.js +201 -181
  34. package/dist/prod/core/constants.js +9 -1
  35. package/dist/prod/core/copies.js +10 -0
  36. package/dist/prod/core/core.js +244 -164
  37. package/dist/prod/core/dev.js +108 -3
  38. package/dist/prod/core/effect.js +28 -23
  39. package/dist/prod/core/graph.js +9 -9
  40. package/dist/prod/core/heap.js +16 -16
  41. package/dist/prod/core/identities.js +1 -1
  42. package/dist/prod/core/lanes.js +307 -95
  43. package/dist/prod/core/owner.js +22 -22
  44. package/dist/prod/core/scheduler.js +266 -211
  45. package/dist/prod/core/truth.js +9 -7
  46. package/dist/prod/core/verdict.js +161 -99
  47. package/dist/prod/deferred.js +1 -1
  48. package/dist/prod/index.js +2 -0
  49. package/dist/prod/map.js +78 -74
  50. package/dist/prod/reveal.js +34 -34
  51. package/dist/prod/signals.js +3 -3
  52. package/dist/prod/store/affects.js +15 -15
  53. package/dist/prod/store/optimistic.js +185 -89
  54. package/dist/prod/store/projection.js +49 -38
  55. package/dist/prod/store/reconcile.js +8 -2
  56. package/dist/prod/store/store.js +99 -63
  57. package/dist/prod/store/types.js +11 -1
  58. package/dist/types/affects.d.ts +3 -2
  59. package/dist/types/boundaries.d.ts +14 -2
  60. package/dist/types/core/async.d.ts +2 -1
  61. package/dist/types/core/constants.d.ts +8 -0
  62. package/dist/types/core/copies.d.ts +54 -0
  63. package/dist/types/core/core.d.ts +15 -0
  64. package/dist/types/core/dev.d.ts +1 -1
  65. package/dist/types/core/lanes.d.ts +8 -1
  66. package/dist/types/core/scheduler.d.ts +36 -4
  67. package/dist/types/core/truth.d.ts +3 -1
  68. package/dist/types/core/types.d.ts +6 -0
  69. package/dist/types/index.d.ts +2 -0
  70. package/dist/types/store/hooks.d.ts +15 -1
  71. package/dist/types/store/store.d.ts +2 -1
  72. package/dist/types/store/target.d.ts +5 -0
  73. package/dist/types/store/types.d.ts +7 -0
  74. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { CONFIG_GUESS, NOT_PENDING, CONFIG_AUTHORITATIVE, CONFIG_OVERRIDE } from "./constants.js";
1
+ import { CONFIG_GUESS, NOT_PENDING, STATUS_UNINITIALIZED, CONFIG_AUTHORITATIVE, CONFIG_OVERRIDE } from "./constants.js";
2
2
 
3
3
  import { NotReadyError } from "./error.js";
4
4
 
@@ -10,11 +10,13 @@ import { enqueueSub } from "./heap.js";
10
10
  // which exists once something installs lanes (`createOptimistic`, verdicts).
11
11
  /** A lane node's current value: its guess, or the latest it derived — the
12
12
  * staging a shown lane holds for its next reveal, else its slot; the
13
- * committed value while it has none (its first lane pass in flight). */
13
+ * committed value while it has none (its first lane pass in flight) —
14
+ * NOT_PENDING for a node with no committed value either (born in the lane,
15
+ * uninitialized: its reads throw NotReady, A7; #4363). */
14
16
  function laneValueOf(r) {
15
- if (!(r.l & CONFIG_GUESS) && r.ie !== NOT_PENDING) return r.ie;
17
+ if (!(r.l & CONFIG_GUESS) && r.ue !== NOT_PENDING) return r.ue;
16
18
  const t = r.T.P;
17
- return t !== NOT_PENDING ? t : r.le;
19
+ return t !== NOT_PENDING || r.m & STATUS_UNINITIALIZED ? t : r.le;
18
20
  }
19
21
 
20
22
  /** Truth readers (`until`, `refresh`; CONFIG_AUTHORITATIVE) — pay-for-use:
@@ -25,7 +27,7 @@ function laneValueOf(r) {
25
27
  * value. */ function truthRead(r) {
26
28
  if (truth(r)) return laneValueOf(r);
27
29
  if (!(r.l & CONFIG_GUESS)) throw new NotReadyError(null);
28
- return r.ie !== NOT_PENDING ? r.ie : r.le;
30
+ return r.ue !== NOT_PENDING ? r.ue : r.le;
29
31
  }
30
32
 
31
33
  /** A guess confirmed: its lane's truth readers re-read — of the lane's
@@ -36,8 +38,8 @@ function laneValueOf(r) {
36
38
  /** A lane node's value is the truth when every guess beneath it is
37
39
  * confirmed — its source staged a value equal to the guess — and nothing
38
40
  * beneath it is held in the parent: same inputs, same value. */ function truth(r) {
39
- if (r.l & CONFIG_GUESS) return r.ie !== NOT_PENDING && r.xe && r.xe(r.T.P, r.ie);
40
- if (r.ie !== NOT_PENDING) return;
41
+ if (r.l & CONFIG_GUESS) return r.ue !== NOT_PENDING && r.ye && r.ye(r.T.P, r.ue);
42
+ if (r.ue !== NOT_PENDING) return;
41
43
  if (r.l & CONFIG_OVERRIDE) for (let t = r.C; t; t = t.G) if (!truth(t.S)) return;
42
44
  return 1;
43
45
  }
@@ -1,6 +1,6 @@
1
- import { CONFIG_VERDICT, REACTIVE_PROBED, CONFIG_CHILDREN_FORBIDDEN, CONFIG_OVERRIDE, STATUS_ERROR, CONFIG_GUESS, STATUS_PENDING, NOT_PENDING, STATUS_UNINITIALIZED, CONFIG_HELD, EFFECT_RENDER, CONFIG_STAGED_ERROR, REACTIVE_STAGED_READ, REACTIVE_PROBE_UNANSWERED, CONFIG_INPUTS_PUBLISHED, REACTIVE_JOINED, REACTIVE_LANE_READ } from "./constants.js";
1
+ import { REACTIVE_PROBED, REACTIVE_WINDOW, CONFIG_VERDICT, CONFIG_ASYNC, CONFIG_CHILDREN_FORBIDDEN, CONFIG_OVERRIDE, STATUS_ERROR, CONFIG_GUESS, STATUS_PENDING, NOT_PENDING, STATUS_UNINITIALIZED, CONFIG_HELD, EFFECT_RENDER, CONFIG_STAGED_ERROR, REACTIVE_STAGED_READ, REACTIVE_PROBE_UNANSWERED, REACTIVE_REASK, CONFIG_INPUTS_PUBLISHED, REACTIVE_JOINED, REACTIVE_LANE_READ } from "./constants.js";
2
2
 
3
- import { context, tracking, setVerdict, verdict, pullComputed, joinPass, markLateLinker, spectating, unflushedValue, bornInto } from "./core.js";
3
+ import { context, creatorPass, tracking, creatorReads, setVerdict, verdict, prepareComputed, pullComputed, joinPass, markLateLinker, spectating, unflushedValue, bornInto } from "./core.js";
4
4
 
5
5
  import { NotReadyError } from "./error.js";
6
6
 
@@ -38,7 +38,7 @@ function watchVerdict(e, t = false) {
38
38
  * node's, or the staging of a write this flush may hold — and the verdict
39
39
  * does not rescue it: its result shows at the landing, re-derived). A lane
40
40
  * read, for `recompute`'s tail (REACTIVE_LANE_READ). */ function route(e, t) {
41
- if (passLane === null && !(e.R & (REACTIVE_JOINED | REACTIVE_STAGED_READ))) setPassLane(verdictLane(t));
41
+ if (!passLane && !(e.R & (REACTIVE_JOINED | REACTIVE_STAGED_READ))) setPassLane(verdictLane(t));
42
42
  e.R |= REACTIVE_LANE_READ;
43
43
  }
44
44
 
@@ -65,7 +65,7 @@ function watchVerdict(e, t = false) {
65
65
  * transaction (`bornInto`, #4010): it has no screen — it waits on the flight
66
66
  * with the rest of its frame. */ function observeFlight(e, t) {
67
67
  if (t.l & CONFIG_INPUTS_PUBLISHED || t.l & CONFIG_HELD && bornInto(e, txOf(t))) return false;
68
- if (globalQueue.q) {
68
+ if (globalQueue.Y) {
69
69
  joinFuture(null);
70
70
  if (!(t.l & CONFIG_HELD)) queuePendingNode(t);
71
71
  verdictRead(e, flushTransaction, true);
@@ -90,9 +90,9 @@ let probeFound = false;
90
90
  * value notifying anyone (a held write's commit; a held landing's): its
91
91
  * reader re-derives there. `latest` shows the proposal that lands — a
92
92
  * rewrite or a landing reaches its reader through the link it holds — so a
93
- * re-run would only repeat the frame. */ function verdictRead(e, t, n) {
93
+ * re-run would only repeat the frame. */ function verdictRead(e, t, r) {
94
94
  route(e, t);
95
- if (n) staleReader(e, t); else if (probing && t.En[t.En.length - 1] !== e) t.En.push(e);
95
+ if (r) staleReader(e, t); else if (probing && t.En[t.En.length - 1] !== e) t.En.push(e);
96
96
  }
97
97
 
98
98
  /** A verdict read of a node staged or in flight but not held yet: whether it
@@ -105,40 +105,41 @@ let probeFound = false;
105
105
  * watches the seam and runs again if the flush parks (a plain sync write
106
106
  * never glitches it true).
107
107
  *
108
- * `latest` has its answer either way — the proposal — and only the reader's
109
- * membership was open, so it is settled now: the frame gets its transaction
110
- * (`joinFuture(null)`; nothing holds it at the seam and it lands there, the
111
- * lane dissolving into it — a plain commit) and the reader is its verdict
112
- * lane's. One pass: a provisional pass re-derived at the seam ran everything
113
- * downstream of it twice (#3540 web). A pass that also read the frame's own
114
- * stagings plainly (REACTIVE_STAGED_READ) stays the frame's (`route` does
115
- * not move it); a verdict reader's plain read AFTER the window sees the
116
- * screen (`read`: `stagedScreen`). */ function provisionalVerdict(e, t) {
117
- if (!probing) {
118
- joinFuture(null);
119
- verdictRead(e, flushTransaction);
120
- return;
121
- }
122
- if (flushTransaction !== null) {
123
- if (t) probeFound = true;
108
+ * `latest` has its answer either way — the proposal — but its reader's
109
+ * membership is the seam's too: the frame opens no transaction for it
110
+ * (#4365 — one opened for the read alone made a plain read after the window
111
+ * take it for a hold, `stagedScreen`, and serve the screen beside the
112
+ * staging in a frame nothing held). The reader watches the seam like a
113
+ * probe before anything joined: its pass is the frame's, and runs again in
114
+ * the verdict lane if the flush parks. Once the flush has joined a
115
+ * transaction, the reader is its verdict lane's at once; a pass that also
116
+ * read the frame's own stagings plainly (REACTIVE_STAGED_READ) stays the
117
+ * frame's (`route` does not move it). */ function provisionalVerdict(e, t) {
118
+ if (flushTransaction) {
119
+ if (probing && t) probeFound = true;
124
120
  verdictRead(e, flushTransaction);
125
- if (e.R & REACTIVE_STAGED_READ) watchVerdict(e);
121
+ if (probing && e.R & REACTIVE_STAGED_READ) watchVerdict(e);
126
122
  return;
127
123
  }
128
124
  // Before anything joined, a staging that would not be final held has no
129
125
  // answer yet: whatever the seam decides, the pass runs again — a later
130
126
  // plain read of the same pass may route it into the verdict lane
131
127
  // (`observeFlight`), which the seam must not take as this probe's answer.
132
- watchVerdict(e, t);
128
+ // `latest` opens no transaction for its answer either (#4365): the plain
129
+ // read of a staging after it took one opened for it for a hold and paired
130
+ // the staging with the screen, in a frame nothing held. Its pass is the
131
+ // frame's — whole — and re-derives once if the flush parks (unanswered:
132
+ // its membership is the seam's, not the transaction it joins).
133
+ watchVerdict(e, !probing || t);
133
134
  }
134
135
 
135
136
  /** A19 exc. 2 / A24: a flight that re-asks the question already answered
136
137
  * (a `refresh()`, a poll) is quiet; a node pending through others is quiet
137
138
  * when every flight it waits on is. */ function quietPending(e) {
138
139
  const t = e.T;
139
- if (t === null) return false;
140
- if (t.fe !== undefined) {
141
- for (const e of t.fe) if (!e.T?.Ve) return false;
140
+ if (!t) return false;
141
+ if (t.se) {
142
+ for (const e of t.se) if (!e.T?.Ve) return false;
142
143
  return true;
143
144
  }
144
145
  return t.Ve;
@@ -157,16 +158,24 @@ let probeFound = false;
157
158
  * flight — a staging equal to what is displayed changes nothing when it
158
159
  * lands: final now (maintainer, 2026-10-02). */ function heldNotFinal(e) {
159
160
  if ((e.m & STATUS_PENDING) !== 0 && !quietPending(e)) return true;
160
- return e.ie !== NOT_PENDING && !latestActive && !e.T.Ve && !(e.m & STATUS_UNINITIALIZED) && (!!e.T.Ie || !e.xe || !e.xe(e.le, e.ie));
161
+ return e.ue !== NOT_PENDING && !latestActive && !e.T.Ve && !(e.m & STATUS_UNINITIALIZED) && (!!e.T.Te || !e.ye || !e.ye(e.le, e.ue));
161
162
  }
162
163
 
163
164
  /** `isPending`'s answer for an unheld node whose flight is up (cause ii). */ function pendingVerdict(e, t) {
164
165
  if (t.m & STATUS_UNINITIALIZED) return;
165
166
  if (probing && !quietPending(t)) probeFound = true;
166
- if (e !== null && tracking) {
167
- if (t.l & CONFIG_HELD) verdictRead(e, txOf(t)); else if (globalQueue.q) provisionalVerdict(e, false);
167
+ if (e && tracking) {
168
+ if (t.l & CONFIG_HELD) verdictRead(e, txOf(t)); else if (globalQueue.Y) {
169
+ // `latest` of a flight serves the committed value, the frame's and the
170
+ // lane's alike (D-22): nothing is the seam's, so the reader is the
171
+ // verdict lane's now, as a plain read of a flight makes it
172
+ // (`observeFlight`). Its frame pass re-derived in the lane (R5) asked
173
+ // its question again (F-9, #4397). A staging's is the seam's (#4365).
174
+ if (!probing) joinFuture(null);
175
+ provisionalVerdict(e, false);
168
176
  // decided above
169
- }
177
+ }
178
+ }
170
179
  }
171
180
 
172
181
  /** The pass entering a verdict window is a verdict reader (CONFIG_VERDICT):
@@ -174,11 +183,19 @@ let probeFound = false;
174
183
  * an untracked window: that is a snapshot, like any untracked read (#3946 —
175
184
  * a router's link claim probing inside the computation that creates the
176
185
  * anchor). A throw still reaches the pass through `untrack`. */ function markVerdictReader(e) {
177
- let t = context;
178
- if (t?.Qe) t = t.Ye;
179
- if (t !== null && tracking) {
180
- t.l |= CONFIG_VERDICT;
181
- t.R |= REACTIVE_PROBED;
186
+ const t = creatorPass(context);
187
+ if (t && tracking) {
188
+ // A pass run inside passes still running — its creator's, theirs — one
189
+ // of which read the future or a staging (a branch a held or staged
190
+ // condition opened, and whatever that branch creates) has no screen: the
191
+ // branch exists only in that world. It reads that world as any
192
+ // derivation of it does (`bornInto` once held) and stays its pass
193
+ // (`route`); a verdict reader from its next pass. #4341: a memo born in
194
+ // a newly opened <Match> read the screen, where its branch was closed.
195
+ // Not such a pass: a verdict reader now.
196
+ t.l &= ~CONFIG_ASYNC;
197
+ t.R |= REACTIVE_PROBED | REACTIVE_WINDOW | (creatorReads(t, 0) || (t.l |= CONFIG_VERDICT,
198
+ 0));
182
199
  }
183
200
  }
184
201
 
@@ -186,14 +203,14 @@ let probeFound = false;
186
203
  * restores the dispatch it found — none inside a memo's pass a window
187
204
  * pulled (`verdictValue`). */ function latest(e) {
188
205
  markVerdictReader();
189
- const t = latestActive, n = verdict;
206
+ const t = latestActive, r = verdict;
190
207
  latestActive = true;
191
208
  setVerdict(verdictValue);
192
209
  try {
193
210
  return e();
194
211
  } finally {
195
212
  latestActive = t;
196
- setVerdict(n);
213
+ setVerdict(r);
197
214
  }
198
215
  }
199
216
 
@@ -231,8 +248,8 @@ let probeFound = false;
231
248
  */ function isPending(e) {
232
249
  markVerdictReader();
233
250
  const t = probing;
234
- const n = probeFound;
235
- const r = verdict;
251
+ const r = probeFound;
252
+ const i = verdict;
236
253
  probing = true;
237
254
  probeFound = false;
238
255
  setVerdict(verdictValue);
@@ -250,23 +267,23 @@ let probeFound = false;
250
267
  return probeFound;
251
268
  } finally {
252
269
  probing = t;
253
- probeFound = n;
254
- setVerdict(r);
270
+ probeFound = r;
271
+ setVerdict(i);
255
272
  }
256
273
  }
257
274
 
258
275
  /** The staging, or the staged error thrown (D-41). */ function staged(e) {
259
- if (e.l & CONFIG_STAGED_ERROR) throw e.ie;
260
- return e.ie;
276
+ if (e.l & CONFIG_STAGED_ERROR) throw e.ue;
277
+ return e.ue;
261
278
  }
262
279
 
263
280
  /** `latest()` of a held node: the flushed staging — the proposal — and, for
264
281
  * a tracked reader of a rewrite not yet flushed, the late-linker re-run in
265
282
  * the flush that carries it. */ function heldLatest(e, t) {
266
- const n = unflushedValue(e);
267
- if (n === NOT_PENDING) return staged(e);
268
- if (t !== null) markLateLinker(t);
269
- return n;
283
+ const r = unflushedValue(e);
284
+ if (r === NOT_PENDING) return staged(e);
285
+ if (t) markLateLinker(t);
286
+ return r;
270
287
  }
271
288
 
272
289
  /** The verdict windows' read — `latest(fn)` and `isPending(fn)` — in one
@@ -279,7 +296,9 @@ let probeFound = false;
279
296
  * differs (A24, A18 provenance). A derivation: `latest` sees the lane's
280
297
  * latest (a landing a blocked lane holds has answered its question — the
281
298
  * checkout's shipping text updates independently of the tax in flight),
282
- * `isPending` the screen; not final while its own flight is up;
299
+ * `isPending` the screen; not final while its own flight is up. A
300
+ * derivation's first load in flight (nothing produced yet — an async memo
301
+ * over a verdict memo, F-6) reads as the flight below: loading (D-22);
283
302
  * - a held node: the reader breaks out as the holder's verdict lane's and
284
303
  * re-derives at the landing; `latest` serves the proposal (`heldLatest`),
285
304
  * `isPending` answers `heldNotFinal`;
@@ -290,63 +309,76 @@ let probeFound = false;
290
309
  * serves the committed value — below the async nothing newer exists; an
291
310
  * uninitialized one throws NotReady: loading, not pending (A19 exc. 1);
292
311
  * - an errored derivation throws for every reader (#2897). */ function verdictValue(e, t) {
293
- const n = e;
294
- const r = t !== null && !(t.l & CONFIG_CHILDREN_FORBIDDEN);
295
- const i = r && tracking;
296
- if (t !== null && tracking) {
312
+ const r = e;
313
+ const i = !!t && !(t.l & CONFIG_CHILDREN_FORBIDDEN);
314
+ const n = i && tracking;
315
+ // A31: the pulled memo's pass is its own, not the probe's — it reads
316
+ // outside the window, and the probe's read below answers for what the pass
317
+ // produced. So is a lazy or dormant memo's wake (an unowned memo with no
318
+ // reader left, #4366): woken inside the window, it read its sources as the
319
+ // probe does, the committed value under a landing. (A signal has no
320
+ // `_flags`: the wake is a no-op for it.)
321
+ setVerdict(null);
322
+ prepareComputed(r);
323
+ if (t && tracking) {
297
324
  link(e, t);
298
- if (n.X !== undefined) {
299
- // A31: the pulled memo's pass is its own, not the probe's — it reads
300
- // outside the window, and the probe's read below answers for what
301
- // the pass produced.
302
- setVerdict(null);
303
- pullComputed(n, t);
304
- setVerdict(verdictValue);
305
- }
325
+ if (e.X) pullComputed(r, t);
306
326
  }
327
+ setVerdict(verdictValue);
307
328
  // A live `affects()` mark on the node or a dependency (affects.ts): not
308
329
  // final by declaration — the value itself is read as below. The verdict is
309
330
  // display-ahead like any: in a transaction's flush (the declaring action's
310
331
  // body) the reader is its verdict lane's, not a staging the frame parks.
311
- if (probing && GlobalQueue.p !== undefined && GlobalQueue.p(n)) {
332
+ if (probing && GlobalQueue.p?.(r)) {
312
333
  probeFound = true;
313
- if (i && flushTransaction !== null) verdictRead(t, flushTransaction);
334
+ if (n && flushTransaction) verdictRead(t, flushTransaction);
314
335
  }
315
- if (e.l & CONFIG_OVERRIDE && !(n.m & STATUS_ERROR && !(e.l & CONFIG_GUESS))) {
316
- const r = txOf(e);
317
- if (i) verdictRead(t, r._parent ?? r);
318
- const u = (n.m & STATUS_PENDING) !== 0 && !quietPending(n);
319
- if (e.l & CONFIG_GUESS) {
320
- if (probing && (u || e.ie !== NOT_PENDING && (!e.xe || !e.xe(e.T.P, e.ie)))) probeFound = true;
321
- // A lane a correction folded under (D-34): `latest()` shows the hold's
322
- // world whole — the truth beneath each guess, else what it covered.
323
- if (latestActive && r.folded) return r.folded(null, e);
324
- return e.T.P;
336
+ if (e.l & CONFIG_OVERRIDE && !(r.m & STATUS_ERROR && !(e.l & CONFIG_GUESS))) {
337
+ const i = txOf(e), o = (r.m & STATUS_PENDING) !== 0 && !quietPending(r), a = e.l & CONFIG_GUESS,
338
+ // NOT_PENDING: a node born in the lane with nothing in it yet has no
339
+ // value in either view — loading, not pending, and no verdict to read
340
+ // ahead: it is read as any uninitialized node, NotReady below (A7, A19
341
+ // exc. 1; #4363), its reader not moved into the verdict lane.
342
+ u = a ? 0 : latestActive && !o ? laneValueOf(e) : display(e);
343
+ if (u !== NOT_PENDING) {
344
+ if (n) verdictRead(t, i._parent ?? i);
345
+ if (a) {
346
+ if (probing && (o || e.ue !== NOT_PENDING && (!e.ye || !e.ye(e.T.P, e.ue)))) probeFound = true;
347
+ // A lane a correction folded under (D-34): `latest()` shows the hold's
348
+ // world whole — the truth beneath each guess, else what it covered.
349
+ if (latestActive && i.folded) return i.folded(null, e);
350
+ return e.T.P;
351
+ }
352
+ // A first load in flight with nothing produced yet: loading, for
353
+ // `latest` (D-22) as for `isPending` (A19 exc. 1) — unless an error
354
+ // answered it first: its re-ask is pending, the error its display
355
+ // (D-41, #4375).
356
+ if (o && u === e.le && r.m & STATUS_UNINITIALIZED && (latestActive || !r.T.Te)) throw r.T.U;
357
+ if (probing && o) probeFound = true;
358
+ return u;
325
359
  }
326
- if (probing && u) probeFound = true;
327
- return latestActive && !u ? laneValueOf(e) : display(e);
328
360
  }
329
- const u = (n.m & STATUS_UNINITIALIZED) !== 0;
361
+ const o = (r.m & STATUS_UNINITIALIZED) !== 0;
330
362
  if (e.l & CONFIG_HELD) {
331
- if (!u) {
332
- const r = txOf(e);
363
+ if (!o) {
364
+ const i = txOf(e);
333
365
  // A render effect re-run (or mounted) outside the verdict lane's flush
334
366
  // while the lane is blocked — its display held on its own derivation
335
367
  // in flight — is a stale reader of the lane (#3460, as `laneRead`): the
336
368
  // committed value now, re-derived at the reveal. Not inside a probe:
337
369
  // `isPending` is answered below either way.
338
- if (i && !probing && t.i === EFFECT_RENDER && passLane === null && r.Pe !== null && r.Pe.ln && flushTransaction !== r) {
339
- staleReader(t, r.Pe);
370
+ if (n && !probing && t.i === EFFECT_RENDER && !passLane && i.Pe?.ln && flushTransaction !== i) {
371
+ staleReader(t, i.Pe);
340
372
  return e.le;
341
373
  }
342
- if (i) verdictRead(t, r);
343
- if (probing && heldNotFinal(n)) probeFound = true;
344
- if (latestActive && e.ie !== NOT_PENDING) {
374
+ if (n) verdictRead(t, i);
375
+ if (probing && heldNotFinal(r)) probeFound = true;
376
+ if (latestActive && e.ue !== NOT_PENDING) {
345
377
  // An action body reading another transaction's proposal derives
346
378
  // from it: the two settle as one (A15; posture C, 2026-09-15). An
347
379
  // untracked read elsewhere has no transaction to entangle.
348
- if (!i && flushTransaction !== null && !globalQueue.q) joinFuture(txOf(e));
349
- return heldLatest(e, i ? t : null);
380
+ if (!n && flushTransaction && !globalQueue.Y) joinFuture(txOf(e));
381
+ return heldLatest(e, n ? t : null);
350
382
  }
351
383
  return e.le;
352
384
  }
@@ -354,46 +386,76 @@ let probeFound = false;
354
386
  // committed value, so no verdict: `isPending` reads it as its read does —
355
387
  // the owner joins the hold (held with it, or caught by a boundary that
356
388
  // has not shown content) and answers for the commit, where it is final.
357
- if (e.ie !== NOT_PENDING && !(n.m & STATUS_PENDING)) {
358
- if (probing && r) joinPass(t, e);
389
+ if (e.ue !== NOT_PENDING && !(r.m & STATUS_PENDING)) {
390
+ if (probing && i) joinPass(t, e);
359
391
  return staged(e);
360
392
  }
361
- } else if (e.ie !== NOT_PENDING) {
362
- if (n.m & STATUS_PENDING && !u) pendingVerdict(i ? t : null, n); else if (i && globalQueue.q) provisionalVerdict(t, !latestActive && !u);
393
+ } else if (e.ue !== NOT_PENDING) {
394
+ if (r.m & STATUS_PENDING && !o) pendingVerdict(n ? t : null, r); else if (n && globalQueue.Y) provisionalVerdict(t, !latestActive && !o);
363
395
  // Outside a flush, the staging is an unflushed write (A28): the probe
364
396
  // answers for the flushed world, and watches the seam of the flush that
365
397
  // carries the write — a memo of `isPending(x)` created after the write
366
398
  // flips if that flush parks (#3078). (The write's own fan-out ran before
367
399
  // the reader existed; nothing else would re-derive it.)
368
- else if (i && probing) watchVerdict(t);
400
+ else if (n && probing) watchVerdict(t);
369
401
  if (latestActive) {
370
402
  // A28: an unflushed write is not what `latest` serves; a tracked
371
403
  // reader derived from the flushed world runs again in the carrying
372
404
  // flush.
373
- if (globalQueue.q) return staged(e);
374
- if (t !== null) markLateLinker(t);
405
+ if (globalQueue.Y) return staged(e);
406
+ if (t) markLateLinker(t);
375
407
  }
376
408
  return e.le;
377
409
  }
378
- if (n.m & STATUS_PENDING) {
379
- if (!u) {
380
- pendingVerdict(i ? t : null, n);
410
+ if (r.m & STATUS_PENDING) {
411
+ if (!o) {
412
+ pendingVerdict(n ? t : null, r);
381
413
  return e.le;
382
414
  }
383
415
  // As `read()`: an untracked read of a pending node still re-runs its
384
416
  // reader when the node settles (a projection's pull reads its firewall
385
417
  // untracked, store/store.ts).
386
- if (t !== null && !tracking && !spectating && e !== t) link(e, t);
387
- throw n.T?.U;
418
+ if (t && !tracking && !spectating && e !== t) link(e, t);
419
+ throw r.T?.U;
388
420
  }
389
- if (n.X !== undefined && n.m & STATUS_ERROR) throw n.T.U;
421
+ if (e.X && r.m & STATUS_ERROR) throw r.T.U;
390
422
  return e.le;
391
423
  }
392
424
 
425
+ /** D-25: a node whose fetch a hold is waiting on is that hold's work, not a
426
+ * verdict reader — a pass that re-runs it reads plainly — and a memo's
427
+ * posture is what it reads: one that reads a verdict reader's value is a
428
+ * verdict reader itself (#4050). An async memo with no verdict window of its
429
+ * own (REACTIVE_WINDOW: it read a verdict memo, it called neither `latest`
430
+ * nor `isPending`) is a verdict reader between its flights, and the hold's
431
+ * work while one is up or its hold re-runs it.
432
+ *
433
+ * At a pass's head (core.ts `recompute`): a pending node's pass — its
434
+ * flight is the transition's own work (#3884) — and a held one's re-run of
435
+ * such a memo read plainly: the write that re-ran it is its hold's, and
436
+ * served the screen it re-asked a question it had answered (A10, #4397).
437
+ * Only a memo that never asked: D-25's "a verdict posture outlives the pass
438
+ * that asked" is a pass that called `latest`/`isPending`, which clears
439
+ * CONFIG_ASYNC and stays a verdict reader whoever dirties it.
440
+ *
441
+ * On `source` going pending (`propagateStatus`): such a memo waits on it
442
+ * like any derivation (F-9) instead of re-deriving — what it read changed
443
+ * no value, so its re-run re-asked the question it was answering. Unless
444
+ * its own flight is up outside a lane on a new question of the source's:
445
+ * its re-run supersedes a flight asked of a value the source has moved past
446
+ * (re-asked by a `refresh()`, the source's question is the same one). */ function holdWork(e, t) {
447
+ // CONFIG_ASYNC records an async memo with no window of its own: its last
448
+ // answering pass registered a flight (`handleAsync`) and called neither
449
+ // `latest` nor `isPending`. A window (`markVerdictReader`), a sync answer or
450
+ // an error clears it; a pass left pending keeps the last answer's.
451
+ const r = e.l & CONFIG_ASYNC;
452
+ return r && (!(e.m & STATUS_PENDING) || e.T.Re?.P || t.R & REACTIVE_REASK);
453
+ }
454
+
393
455
  // Installed at module evaluation — present exactly when something imports
394
456
  // `latest` or `isPending`. (`read` dispatches to `verdictValue` through
395
457
  // `verdict`, set while a window is open.)
396
- installVerdictHooks(observeFlight);
458
+ installVerdictHooks(observeFlight, holdWork);
397
459
 
398
460
  /** A store read inside an untracked `isPending` probe found a live mark on
399
461
  * a record with no node to carry it (store/affects.ts): not final. */ GlobalQueue.rt = () => {
@@ -121,7 +121,7 @@ GlobalQueue.er = e => lagging.size !== 0 ? lagOf(e, new Set) : undefined;
121
121
  * does not replace (D-40) — restaged as the committed value, the hold's
122
122
  * readers would re-derive against the old input. */ const serve = e => {
123
123
  const r = handleAsync(t, e);
124
- return t.l & CONFIG_HELD && t.ie !== NOT_PENDING ? t.ie : r;
124
+ return t.l & CONFIG_HELD && t.ue !== NOT_PENDING ? t.ue : r;
125
125
  };
126
126
  const end = () => t.R & REACTIVE_DISPOSED && land(o);
127
127
  return accessor(computed(r => {
@@ -24,6 +24,8 @@ import "./core/effect.js";
24
24
 
25
25
  export { configureClientErrors } from "./core/error-hooks.js";
26
26
 
27
+ export { checkForeignOwnerless, runAsSolidCopy } from "./core/copies.js";
28
+
27
29
  export { storeName } from "./store/edges.js";
28
30
 
29
31
  export { createEffect, createMemo, createOptimistic, createReaction, createRenderEffect, createSignal, createTrackedEffect, onCleanup, onFlush, onSettled, refresh, resolve, until } from "./signals.js";