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

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 (65) hide show
  1. package/dist/dev-shared.js +168 -88
  2. package/dist/dev.attribution.js +16 -13
  3. package/dist/dev.js +272 -129
  4. package/dist/observe/boundaries.js +88 -67
  5. package/dist/observe/core/action.js +8 -0
  6. package/dist/observe/core/async.js +46 -34
  7. package/dist/observe/core/attribution.js +30 -28
  8. package/dist/observe/core/constants.js +21 -1
  9. package/dist/observe/core/core.js +164 -136
  10. package/dist/observe/core/effect.js +6 -6
  11. package/dist/observe/core/graph.js +3 -3
  12. package/dist/observe/core/heap.js +5 -5
  13. package/dist/observe/core/lanes.js +104 -84
  14. package/dist/observe/core/owner.js +10 -9
  15. package/dist/observe/core/scheduler.js +38 -35
  16. package/dist/observe/core/truth.js +6 -6
  17. package/dist/observe/core/verdict.js +13 -13
  18. package/dist/observe/deferred.js +39 -40
  19. package/dist/observe/index.js +2 -2
  20. package/dist/observe/map.js +22 -22
  21. package/dist/observe/reveal.js +5 -5
  22. package/dist/observe/signals.js +57 -15
  23. package/dist/observe/store/affects.js +1 -1
  24. package/dist/observe/store/hooks.js +3 -0
  25. package/dist/observe/store/optimistic.js +11 -11
  26. package/dist/observe/store/projection.js +34 -21
  27. package/dist/observe/store/reconcile.js +2 -2
  28. package/dist/observe/store/store.js +63 -53
  29. package/dist/observe/store/utils.js +7 -2
  30. package/dist/prod/boundaries.js +153 -132
  31. package/dist/prod/core/action.js +8 -0
  32. package/dist/prod/core/async.js +55 -43
  33. package/dist/prod/core/constants.js +14 -1
  34. package/dist/prod/core/core.js +162 -134
  35. package/dist/prod/core/effect.js +9 -9
  36. package/dist/prod/core/graph.js +3 -3
  37. package/dist/prod/core/heap.js +12 -12
  38. package/dist/prod/core/lanes.js +98 -78
  39. package/dist/prod/core/owner.js +15 -14
  40. package/dist/prod/core/scheduler.js +43 -40
  41. package/dist/prod/core/truth.js +6 -6
  42. package/dist/prod/core/verdict.js +17 -17
  43. package/dist/prod/deferred.js +39 -40
  44. package/dist/prod/index.js +2 -2
  45. package/dist/prod/map.js +14 -14
  46. package/dist/prod/reveal.js +8 -8
  47. package/dist/prod/signals.js +46 -4
  48. package/dist/prod/store/affects.js +1 -1
  49. package/dist/prod/store/hooks.js +3 -0
  50. package/dist/prod/store/optimistic.js +16 -16
  51. package/dist/prod/store/projection.js +22 -9
  52. package/dist/prod/store/reconcile.js +2 -2
  53. package/dist/prod/store/store.js +262 -262
  54. package/dist/prod/store/utils.js +2 -0
  55. package/dist/types/core/action.d.ts +8 -0
  56. package/dist/types/core/constants.d.ts +20 -0
  57. package/dist/types/core/core.d.ts +14 -1
  58. package/dist/types/core/dev.d.ts +1 -1
  59. package/dist/types/core/index.d.ts +1 -1
  60. package/dist/types/core/lanes.d.ts +5 -1
  61. package/dist/types/core/scheduler.d.ts +2 -0
  62. package/dist/types/index.d.ts +3 -1
  63. package/dist/types/signals.d.ts +37 -0
  64. package/dist/types/store/target.d.ts +2 -0
  65. package/package.json +1 -1
@@ -22,12 +22,12 @@ import { globalQueue, schedule, heldRunHook, haltReactivity, GlobalQueue } from
22
22
  // staged); the flush's commit replays this effect. Its first run is not this
23
23
  // creation's (A29). A lane's node likewise: its run is the lane's, queued
24
24
  // by the pass and released at the reveal (lanes.ts).
25
- !u?.defer && f.ue === NOT_PENDING && !f.T?.Re?.v && (f.i === EFFECT_USER || u?.schedule ? globalQueue.enqueue(f.i, runEffect.bind(null, f)) : runEffect(f, f.i));
25
+ !u?.defer && f.ie === NOT_PENDING && !f.T?.Re?.P && (f.i === EFFECT_USER || u?.schedule ? globalQueue.enqueue(f.i, runEffect.bind(null, f)) : runEffect(f, f.i));
26
26
  }
27
27
 
28
28
  function notifyEffectStatus() {
29
29
  const t = this.m;
30
- const e = this.T?.F;
30
+ const e = this.T?.U;
31
31
  if (t & STATUS_ERROR) {
32
32
  globalQueue.notify(this, STATUS_PENDING, 0);
33
33
  if (this.i === EFFECT_USER) {
@@ -81,8 +81,8 @@ function runEffect(t, e) {
81
81
  // notifyEffectStatus, and a runner queued by an earlier valueChanged in the
82
82
  // same flush must not be hijacked by a later-arriving error status.
83
83
  if (t.m & STATUS_ERROR && t.i === EFFECT_USER) {
84
- const e = unwrapStatusError(t.T?.F);
85
- t.ge = t.Ie;
84
+ const e = unwrapStatusError(t.T?.U);
85
+ t.ke = t.le;
86
86
  t.Ae = false;
87
87
  try {
88
88
  t.qe ? t.qe(e, () => {
@@ -97,21 +97,21 @@ function runEffect(t, e) {
97
97
  }
98
98
  // Captured before the callback: its own throw errors the node below, but
99
99
  // the compute pass that produced `_value` was clean, so its tail still goes.
100
- const E = t.T?.F == null;
100
+ const E = t.T?.U == null;
101
101
  const u = t.Je;
102
102
  t.Je = undefined;
103
103
  try {
104
104
  u?.();
105
- const e = t.Ke(t.Ie, t.ge);
105
+ const e = t.Ke(t.le, t.ke);
106
106
  if (false && e !== undefined && typeof e !== "function") ;
107
107
  // The final cleanup is invoked by disposeChildren at true disposal.
108
108
  t.Je = e;
109
109
  } catch (e) {
110
- ext(t).F = new StatusError(t, e);
110
+ ext(t).U = new StatusError(t, e);
111
111
  t.m |= STATUS_ERROR;
112
112
  escalate(t, e);
113
113
  } finally {
114
- t.ge = t.Ie;
114
+ t.ke = t.le;
115
115
  t.Ae = false;
116
116
  // The run applied: this is the frame now, so the dependency tail the
117
117
  // compute pass left linked goes (A30, #3438 — `recompute` defers an
@@ -157,7 +157,7 @@ GlobalQueue.K = runEffect;
157
157
  // Status dispatch rides the SHARED notifier (statusNotifierOf keys off
158
158
  // _type): its error arm is behavior-identical to the closure that used to
159
159
  // live here, without the per-node NodeExtension allocation.
160
- E.M = run;
160
+ E.Z = run;
161
161
  // The first run rides the heap like every wake (GlobalQueue._update), so a
162
162
  // tracked effect created inside a render-effect callback runs after that
163
163
  // pass's staged writes commit, not before.
@@ -133,7 +133,7 @@ function link(e, n) {
133
133
  if (s) {
134
134
  o = l !== null ? l.G : n.C;
135
135
  if (o !== null && o.S === e) {
136
- o.Te = n.Ne;
136
+ o.de = n.Ne;
137
137
  n._ = o;
138
138
  return;
139
139
  }
@@ -144,14 +144,14 @@ function link(e, n) {
144
144
  // (the old alien-signals `isValidLink` walk, O(n²) when a computation
145
145
  // re-reads earlier deps non-consecutively, e.g. store leaf reads).
146
146
  const r = e.ve;
147
- if (r !== null && r.u === n && (!s || r.Te === n.Ne)) return;
147
+ if (r !== null && r.u === n && (!s || r.de === n.Ne)) return;
148
148
  const t = n._ = e.ve = {
149
149
  S: e,
150
150
  u: n,
151
151
  G: o,
152
152
  Xe: r,
153
153
  t: null,
154
- Te: n.Ne
154
+ de: n.Ne
155
155
  };
156
156
  if (l !== null) l.G = t; else n.C = t;
157
157
  if (r !== null) r.t = t; else e.o = t;
@@ -11,14 +11,14 @@ import { dirtyQueue } from "./scheduler.js";
11
11
  * callback to the user queue once the pass has committed (see
12
12
  * GlobalQueue._update, #3291).
13
13
  */ function enqueueSub(e) {
14
- if (dirtyQueue.Ge > e.Fe) dirtyQueue.Ge = e.Fe;
14
+ if (dirtyQueue.Fe > e.he) dirtyQueue.Fe = e.he;
15
15
  insertIntoHeap(e, dirtyQueue);
16
16
  }
17
17
 
18
18
  function actualInsertIntoHeap(e, t) {
19
- const E = (e._parent?.Qe ? e._parent.Ye?.Fe : e._parent?.Fe) ?? -1;
20
- if (E >= e.Fe) e.Fe = E + 1;
21
- const n = e.Fe;
19
+ const E = (e._parent?.Qe ? e._parent.Ye?.he : e._parent?.he) ?? -1;
20
+ if (E >= e.he) e.he = E + 1;
21
+ const n = e.he;
22
22
  const I = t.$e[n];
23
23
  if (I === undefined) t.$e[n] = e; else {
24
24
  const t = I.We;
@@ -65,7 +65,7 @@ function deleteFromHeap(e, t) {
65
65
  const E = e.R;
66
66
  if (!(E & (REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT))) return;
67
67
  e.R = E & -25;
68
- const n = e.Fe;
68
+ const n = e.he;
69
69
  if (e.We === e) t.$e[n] = undefined; else {
70
70
  const E = e.be;
71
71
  const I = t.$e[n];
@@ -98,11 +98,11 @@ function markNode(e, t = REACTIVE_DIRTY) {
98
98
 
99
99
  function runHeap(e, t) {
100
100
  e.p = false;
101
- for (e.Ge = 0; e.Ge <= e.et; e.Ge++) {
102
- let E = e.$e[e.Ge];
101
+ for (e.Fe = 0; e.Fe <= e.et; e.Fe++) {
102
+ let E = e.$e[e.Fe];
103
103
  while (E !== undefined) {
104
104
  if (E.R & REACTIVE_IN_HEAP) t(E); else adjustHeight(E, e);
105
- E = e.$e[e.Ge];
105
+ E = e.$e[e.Fe];
106
106
  }
107
107
  }
108
108
  e.et = 0;
@@ -110,13 +110,13 @@ function runHeap(e, t) {
110
110
 
111
111
  function adjustHeight(e, t) {
112
112
  deleteFromHeap(e, t);
113
- let E = e.Fe;
113
+ let E = e.he;
114
114
  for (let t = e.C; t; t = t.G) {
115
115
  const e = t.S;
116
- if (e.X && e.Fe >= E) E = e.Fe + 1;
116
+ if (e.X && e.he >= E) E = e.he + 1;
117
117
  }
118
- if (e.Fe !== E) {
119
- e.Fe = E;
118
+ if (e.he !== E) {
119
+ e.he = E;
120
120
  for (let E = e.o; E !== null; E = E.t) insertIntoHeapHeight(E.u, t);
121
121
  }
122
122
  }
@@ -1,4 +1,4 @@
1
- import { CONFIG_GUESS, NOT_PENDING, CONFIG_OVERRIDE, REACTIVE_DISPOSED, CONFIG_VERDICT, REACTIVE_PROBE_UNANSWERED, REACTIVE_LANE_DIRTY, CONFIG_HELD, REACTIVE_LANE_READ, STATUS_UNINITIALIZED, REACTIVE_RECOMPUTING_DEPS, CONFIG_AUTHORITATIVE, STATUS_ERROR, CONFIG_CHILDREN_FORBIDDEN, STATUS_PENDING, EFFECT_RENDER, REACTIVE_SCREEN_READ, REACTIVE_FRAME_READ, REACTIVE_IN_HEAP, REACTIVE_DIRTY, REACTIVE_CHECK, CONFIG_INPUTS_PUBLISHED, CONFIG_SLOT_NODE, CONFIG_STAGED, REACTIVE_JOINED, REACTIVE_STAGED_READ } from "./constants.js";
1
+ import { CONFIG_GUESS, NOT_PENDING, CONFIG_OVERRIDE, REACTIVE_DISPOSED, CONFIG_VERDICT, REACTIVE_PROBE_UNANSWERED, REACTIVE_LANE_DIRTY, CONFIG_HELD, REACTIVE_LANE_READ, STATUS_UNINITIALIZED, REACTIVE_RECOMPUTING_DEPS, CONFIG_AUTHORITATIVE, STATUS_ERROR, CONFIG_CHILDREN_FORBIDDEN, EFFECT_RENDER, REACTIVE_SCREEN_READ, REACTIVE_FRAME_READ, REACTIVE_IN_HEAP, REACTIVE_DIRTY, REACTIVE_CHECK, STATUS_PENDING, CONFIG_INPUTS_PUBLISHED, CONFIG_SLOT_NODE, CONFIG_STAGED, REACTIVE_JOINED, REACTIVE_STAGED_READ } from "./constants.js";
2
2
 
3
3
  import { ext, tracking, stagedRead } from "./core.js";
4
4
 
@@ -8,7 +8,7 @@ import { laneValueOf } from "./truth.js";
8
8
 
9
9
  import { enqueueSub } from "./heap.js";
10
10
 
11
- import { schedule, question, nextQuestion, installLaneHooks, GlobalQueue, newTransaction, resolveTx, ownFlights, blocked, txOf, clock, insertSubs, laneDirty, queuePendingNode, list, passLane, sameLane, flushTransaction, commitPendingNode, releaseQueues, holdNode, joinFuture, reruns, merge, setPassLane } from "./scheduler.js";
11
+ import { schedule, question, nextQuestion, installLaneHooks, GlobalQueue, newTransaction, resolveTx, ownFlights, blocked, txOf, clock, insertSubs, laneDirty, queuePendingNode, list, passLane, setPassLane, sameLane, flushTransaction, commitPendingNode, releaseQueues, holdNode, joinFuture, reruns, merge } from "./scheduler.js";
12
12
 
13
13
  // Lanes (plan sec. 28 replay, 2026-10-02; maintainer rulings 2026-10-01/02). A lane
14
14
  // is "a new base of a transition": the sub-frame an optimistic write opens
@@ -50,8 +50,8 @@ function newLane(e) {
50
50
 
51
51
  /** What the screen shows for a lane's node: the lane's value once the lane
52
52
  * has revealed, the committed truth before. */ function display(e) {
53
- const n = e.T.v;
54
- return e.T.Re.ke && n !== NOT_PENDING ? n : e.Ie;
53
+ const n = e.T.P;
54
+ return e.T.Re.ge && n !== NOT_PENDING ? n : e.le;
55
55
  }
56
56
 
57
57
  /** Guesses written since the last seam (`[node, value, question, …]`).
@@ -66,7 +66,7 @@ function newLane(e) {
66
66
  * on (a store setter's draft too, store/optimistic.ts). */ function guessedValueOf(e) {
67
67
  const n = pendingGuessOf(e);
68
68
  if (n !== NOT_PENDING) return n;
69
- return e.l & CONFIG_OVERRIDE ? laneValueOf(e) : e.Ie;
69
+ return e.l & CONFIG_OVERRIDE ? laneValueOf(e) : e.le;
70
70
  }
71
71
 
72
72
  /** The unflushed guess to `n`, else NOT_PENDING. */ function pendingGuessOf(e) {
@@ -119,10 +119,10 @@ function applyGuesses(e) {
119
119
  // value re-asked renews the question; nothing to notify.
120
120
  u = !t.xe || !t.xe(laneValueOf(t), l);
121
121
  if (!(t.l & CONFIG_GUESS)) {
122
- t.ue = NOT_PENDING;
122
+ t.ie = NOT_PENDING;
123
123
  t.l |= CONFIG_GUESS;
124
124
  }
125
- t.T.v = l;
125
+ t.T.P = l;
126
126
  i = txOf(t)._parent;
127
127
  } else {
128
128
  let s;
@@ -141,12 +141,12 @@ function applyGuesses(e) {
141
141
  // screen's plus the guess (plan sec. 19) — a derivation reading a held write
142
142
  // beside the guess must not show it. Two flights for one input, when
143
143
  // the worlds coincide, is the price.)
144
- ext(t).v = l;
144
+ ext(t).P = l;
145
145
  t.l |= CONFIG_OVERRIDE | CONFIG_GUESS;
146
146
  list(t, s);
147
147
  }
148
148
  if (e !== null && i !== null) merge(e, i);
149
- ext(t).Ee = pendingGuesses[s + 2];
149
+ ext(t).Te = pendingGuesses[s + 2];
150
150
  if (u) {
151
151
  // The lane's members re-derive as its work (REACTIVE_LANE_DIRTY): a
152
152
  // blocked lane's re-guess does not re-run its render effects as stale
@@ -187,7 +187,7 @@ function applyGuesses(e) {
187
187
  }
188
188
 
189
189
  /** Is `l` nested under `a` (an ancestor lane)? */ function under(e, n) {
190
- for (let s = e._parent; s !== null && s.v; s = s._parent) if (s === n) return true;
190
+ for (let s = e._parent; s !== null && s.P; s = s._parent) if (s === n) return true;
191
191
  return false;
192
192
  }
193
193
 
@@ -231,7 +231,7 @@ function unlink(e) {
231
231
  * lane under the holder, shown now, re-derived at the landing, ending with
232
232
  * it. Judged at the seam like any lane: blocked while a verdict reader's
233
233
  * own derivation is in flight (lane rule 3), shown otherwise. */ function verdictLane(e) {
234
- return e.he ??= newLane(e);
234
+ return e.Pe ??= newLane(e);
235
235
  }
236
236
 
237
237
  /** A lane pass's node (core.ts `recompute`, before its staging; a pending
@@ -255,16 +255,16 @@ function unlink(e) {
255
255
  const s = n.Re;
256
256
  // Cleared before equality, so a return to the committed value notifies
257
257
  // nobody. The seam wakes it unless the frame is still held (#3892).
258
- if (s?.ke && !blocked(resolveTx(s._parent))) e.R |= LEFT_SHOWN;
259
- if (s?.v) n.Re = null;
260
- n.v = NOT_PENDING;
258
+ if (s?.ge && !blocked(resolveTx(s._parent))) e.R |= LEFT_SHOWN;
259
+ if (s?.P) n.Re = null;
260
+ n.P = NOT_PENDING;
261
261
  }
262
262
  e.l &= -1050881;
263
263
  return false;
264
264
  }
265
265
  if (!e.i) {
266
266
  if (!(e.l & CONFIG_OVERRIDE)) {
267
- e.ue = NOT_PENDING;
267
+ e.ie = NOT_PENDING;
268
268
  e.l = e.l & -1048833 | CONFIG_OVERRIDE;
269
269
  ext(e);
270
270
  }
@@ -287,7 +287,7 @@ function unlink(e) {
287
287
  // for the commit sweep as mainline's (async.ts). A node born in the lane
288
288
  // has nothing on screen: its leaf waits as the lane's.
289
289
  else if (t) {
290
- if (t !== true && !(t.m & STATUS_UNINITIALIZED) && (e.l & CONFIG_HELD || e.R & REACTIVE_RECOMPUTING_DEPS) && !e.T?.Re?.v) {
290
+ if (t !== true && !(t.m & STATUS_UNINITIALIZED) && (e.l & CONFIG_HELD || e.R & REACTIVE_RECOMPUTING_DEPS) && !e.T?.Re?.P) {
291
291
  queuePendingNode(e);
292
292
  return false;
293
293
  }
@@ -306,14 +306,14 @@ function supersede(e, n, s) {
306
306
  // A store row answered by a new object the store would reconcile into
307
307
  // the guessed one unchanged is an echo, not a correction (#3898): the
308
308
  // server's object never matches the guess by reference.
309
- if (s && e.l & CONFIG_SLOT_NODE && GlobalQueue.nn?.(e.T.v, n)) s = false;
309
+ if (s && e.l & CONFIG_SLOT_NODE && GlobalQueue.nn?.(e.T.P, n)) s = false;
310
310
  if (s) {
311
311
  dissolveLane(t, l, e);
312
312
  // What the screen showed stays the screen until the parent lands (A18
313
313
  // (c): display and untracked reads keep the override until the commit).
314
- if (t.ke) e.Ie = e.T.v;
314
+ if (t.ge) e.le = e.T.P;
315
315
  e.l &= -10241;
316
- e.T.v = NOT_PENDING;
316
+ e.T.P = NOT_PENDING;
317
317
  holdNode(e, l);
318
318
  if (e.o !== null) insertSubs(e);
319
319
  } else {
@@ -321,7 +321,7 @@ function supersede(e, n, s) {
321
321
  // A confirmation is silent (A17); only truth readers are told.
322
322
  GlobalQueue.sn?.(t);
323
323
  }
324
- e.ue = n;
324
+ e.ie = n;
325
325
  joinFuture(l);
326
326
  }
327
327
 
@@ -340,9 +340,9 @@ function supersede(e, n, s) {
340
340
  unlink(e);
341
341
  // Its verdicts end with it (a correction's dissolution reaches here before
342
342
  // `endLanes` would): the readers re-derive from the truth's notification.
343
- const l = e.he;
343
+ const l = e.Pe;
344
344
  if (l !== null) {
345
- e.he = null;
345
+ e.Pe = null;
346
346
  if (lanes.indexOf(l) !== -1) dissolveLane(l, null);
347
347
  }
348
348
  for (let t = 0; t < e.tn.length; t++) {
@@ -351,12 +351,12 @@ function supersede(e, n, s) {
351
351
  if (l === s || u.Re !== e) continue;
352
352
  const i = l.i;
353
353
  const r = l.l & CONFIG_GUESS;
354
- const o = u.v;
354
+ const o = u.P;
355
355
  // What the screen shows of it (NOT_PENDING: nothing — a lane pass that
356
356
  // errored or pends staged no value), and the lane's latest.
357
- const E = e.ke && !i ? o : l.Ie;
357
+ const E = e.ge && !i ? o : l.le;
358
358
  const f = laneValueOf(l);
359
- u.v = NOT_PENDING;
359
+ u.P = NOT_PENDING;
360
360
  l.l &= -10241;
361
361
  if (n === null) {
362
362
  // A derivation the revert re-derives (dirtied by the guess's
@@ -365,19 +365,19 @@ function supersede(e, n, s) {
365
365
  // of its flight observes it (#3648, #3651; #3305's commit beneath a
366
366
  // flight).
367
367
  u.Re = null;
368
- if (!i && !r) l.ue = f;
368
+ if (!i && !r) l.ie = f;
369
369
  commitPendingNode(l);
370
370
  if (!i) {
371
371
  if (l.R & (REACTIVE_IN_HEAP | REACTIVE_DIRTY | REACTIVE_CHECK) || l.m & STATUS_PENDING) l.l |= CONFIG_INPUTS_PUBLISHED;
372
- if (E !== NOT_PENDING && (!l.xe || !l.xe(E, l.Ie))) insertSubs(l);
372
+ if (E !== NOT_PENDING && (!l.xe || !l.xe(E, l.le))) insertSubs(l);
373
373
  }
374
374
  } else if (r) {
375
375
  // A guess of a dissolving lane: its truth — a landing held beneath it,
376
376
  // else the value it covered — is the parent's to land, and its readers
377
377
  // re-derive from it there. What the screen showed stays the screen
378
378
  // until then (A18 (c)).
379
- if (l.ue === NOT_PENDING) l.ue = covered(l);
380
- if (e.ke) l.Ie = o;
379
+ if (l.ie === NOT_PENDING) l.ie = covered(l);
380
+ if (e.ge) l.le = o;
381
381
  holdNode(l, n);
382
382
  insertSubs(l);
383
383
  } else {
@@ -390,13 +390,13 @@ function supersede(e, n, s) {
390
390
  // it: an input's truth equal to its committed value is silent).
391
391
  u.Re = null;
392
392
  if (!i) {
393
- if (E !== NOT_PENDING && e.ke) l.ue = E;
393
+ if (E !== NOT_PENDING && e.ge) l.ie = E;
394
394
  if (l.m & STATUS_PENDING) {
395
- u.Se = null;
395
+ u.Ee = null;
396
396
  enqueueSub(l);
397
397
  }
398
398
  }
399
- if (e.ke) {
399
+ if (e.ge) {
400
400
  commitPendingNode(l);
401
401
  if (!i) l.l |= CONFIG_INPUTS_PUBLISHED;
402
402
  } else {
@@ -416,7 +416,7 @@ function supersede(e, n, s) {
416
416
  // void: nothing of it reached the screen. So are the runs a blocked lane
417
417
  // parked: they show a re-guess the seam never revealed, beside derivations
418
418
  // that keep what the screen showed.
419
- if (n === null || e.ke && !e.ln) releaseQueues(e); else e.un[0].length = e.un[1].length = 0;
419
+ if (n === null || e.ge && !e.ln) releaseQueues(e); else e.un[0].length = e.un[1].length = 0;
420
420
  }
421
421
 
422
422
  /** Lanes. A lane's node is read by its reader's kind: an authoritative
@@ -433,7 +433,11 @@ function supersede(e, n, s) {
433
433
  * has shown, or one the seam has not judged yet (its run waits on the
434
434
  * verdict: released if the lane shows, held if it blocks) — and sees the
435
435
  * lane's latest. NOT_PENDING falls through: lane work's read of a pending
436
- * member throws like any. */ function laneRead(e, n) {
436
+ * member throws like any. A verdict reader entering a lane the seam has
437
+ * not judged reads ahead of it like a staging read: if the seam holds the
438
+ * lane, the pass re-derives on the screen (`entered`, #4284) — `latest()`
439
+ * beside the lane's nodes tears ahead of the hold however the reads are
440
+ * grouped into effects. */ function laneRead(e, n) {
437
441
  const s = n.l & CONFIG_GUESS;
438
442
  const t = txOf(n);
439
443
  // A lane a correction folded under (D-34): store/optimistic.ts reads it.
@@ -450,6 +454,7 @@ function supersede(e, n, s) {
450
454
  // An errored member's lane value predates its error; the error is the answer (#4106).
451
455
  if (!s && u & STATUS_ERROR) return NOT_PENDING;
452
456
  if (e === null) return laneValueOf(n);
457
+ const i = !s && u & STATUS_PENDING;
453
458
  if (!tracking || e.l & CONFIG_CHILDREN_FORBIDDEN) {
454
459
  // An untracked read inside lane work derives from the lane like a
455
460
  // tracked one, minus the subscription — `untrack` is about
@@ -458,39 +463,45 @@ function supersede(e, n, s) {
458
463
  // lanes read by one pass link, as for tracked reads). Outside lane
459
464
  // work, the screen.
460
465
  if (passLane === null || e.l & CONFIG_CHILDREN_FORBIDDEN) return display(n);
461
- enterLane(t, e);
462
- if (!s && u & STATUS_PENDING) return NOT_PENDING;
463
- return laneValueOf(n);
464
- }
465
- if (e.i === EFFECT_RENDER && (passLane === null || !sameLane(passLane, t))) {
466
- if (!s) {
467
- // A flight whose value has never shown: nothing to show — the leaf
468
- // waits on it, and its own frame holds (A15, #3334), not the lane's
469
- // parent. The landing lands the frame: its own pass (the flush
470
- // joined its transaction) reads the answer it waited on — the lane's
471
- // staging, revealed at this seam.
472
- if (u & STATUS_PENDING && n.T.v === NOT_PENDING) return NOT_PENDING;
473
- if (n.ue !== NOT_PENDING && e.l & CONFIG_HELD && flushTransaction !== null && resolveTx(flushTransaction) === txOf(e)) return n.ue;
474
- }
475
- if (t.ln || !s && u & STATUS_PENDING) {
476
- if (!s && !t.ke && u & STATUS_UNINITIALIZED) throw new NotReadyError(null);
477
- // Re-derived at the reveal; once per pass (the pass may also be a stale
478
- // reader of a transaction, REACTIVE_FRAME_READ — both reruns apply).
479
- if (!(e.R & REACTIVE_SCREEN_READ)) {
480
- e.R |= REACTIVE_FRAME_READ | REACTIVE_SCREEN_READ;
481
- t.En.push(e);
466
+ } else if (e.i === EFFECT_RENDER) {
467
+ // A flight whose value has never shown: nothing to show — the leaf
468
+ // waits on it, and its own frame holds (A15, #3334), not the lane's
469
+ // parent. The landing lands the frame: its own pass (the flush joined
470
+ // its transaction) reads the answer it waited on — the lane's staging,
471
+ // revealed at this seam.
472
+ const l = i && n.T.P === NOT_PENDING;
473
+ // D-28: a leaf a verdict read moved into the lane still throws on such
474
+ // a flight — the pass leaves the lane, and its frame holds as if the
475
+ // read had come first (S-39, #4275). Nor does a verdict lane's seat carry
476
+ // the leaf into another lane (no link): it reads that lane as from the
477
+ // frame's seat (#4284).
478
+ if ((l || passLane !== t) && passLane?._parent.Pe === passLane) setPassLane(null);
479
+ if (passLane === null || !sameLane(passLane, t)) {
480
+ // (A lane that has never shown: the screen is the committed value.)
481
+ if (l && t.ge) return NOT_PENDING;
482
+ if (!s && n.ie !== NOT_PENDING && e.l & CONFIG_HELD && flushTransaction !== null && resolveTx(flushTransaction) === txOf(e)) return n.ie;
483
+ if (t.ln || i) {
484
+ if (!s && !t.ge && u & STATUS_UNINITIALIZED) throw new NotReadyError(null);
485
+ // Re-derived at the reveal; once per pass (the pass may also be a stale
486
+ // reader of a transaction, REACTIVE_FRAME_READ — both reruns apply).
487
+ if (!(e.R & REACTIVE_SCREEN_READ)) {
488
+ e.R |= REACTIVE_FRAME_READ | REACTIVE_SCREEN_READ;
489
+ t.En.push(e);
490
+ }
491
+ return display(n);
482
492
  }
483
- return display(n);
493
+ // A verdict reader reads ahead of the seam's verdict: re-derived on the
494
+ // screen if the lane holds (#4284).
495
+ if (e.l & CONFIG_VERDICT && t._parent.Pe !== t) entered.push(e);
484
496
  }
485
497
  }
486
498
  enterLane(t, e);
487
- if (!s && u & STATUS_PENDING) return NOT_PENDING;
488
- return laneValueOf(n);
499
+ return i ? NOT_PENDING : laneValueOf(n);
489
500
  }
490
501
 
491
502
  /** The value a guess covered: the node's committed value — a store slot's
492
503
  * asked of the store (a chained link follows the inner store's commits). */ function covered(e) {
493
- return e.l & CONFIG_SLOT_NODE && GlobalQueue.fn !== undefined ? GlobalQueue.fn(e) : e.Ie;
504
+ return e.l & CONFIG_SLOT_NODE && GlobalQueue.fn !== undefined ? GlobalQueue.fn(e) : e.le;
494
505
  }
495
506
 
496
507
  /** A guess in `l` whose own truth is in flight (its refetch — authoritative:
@@ -521,7 +532,7 @@ function supersede(e, n, s) {
521
532
  const t = n[s];
522
533
  if (lanes.indexOf(t) === -1) continue;
523
534
  const l = resolveTx(t._parent);
524
- if (!l.nt || l.tt !== 0 || l.v || ownFlights(l) || guessFlights(t)) continue;
535
+ if (!l.nt || l.tt !== 0 || l.P || ownFlights(l) || guessFlights(t)) continue;
525
536
  e = true;
526
537
  // Each guess's truth: the one beneath it (a landing held there), else
527
538
  // the one it covered. (A correction dissolves the lane — the others are
@@ -529,8 +540,8 @@ function supersede(e, n, s) {
529
540
  for (let e = 0; e < t.tn.length && lanes.indexOf(t) !== -1; e++) {
530
541
  const n = t.tn[e];
531
542
  if (n.l & CONFIG_GUESS && n.T.Re === t) {
532
- const e = n.ue !== NOT_PENDING ? n.ue : covered(n);
533
- supersede(n, e, !n.xe || !n.xe(n.T.v, e));
543
+ const e = n.ie !== NOT_PENDING ? n.ie : covered(n);
544
+ supersede(n, e, !n.xe || !n.xe(n.T.P, e));
534
545
  }
535
546
  }
536
547
  }
@@ -545,7 +556,7 @@ function laneSeam(e, n) {
545
556
  return;
546
557
  }
547
558
  e.ln = false;
548
- e.ke = true;
559
+ e.ge = true;
549
560
  reruns(e);
550
561
  for (let n = 0; n < e.tn.length; n++) {
551
562
  const s = e.tn[n];
@@ -555,9 +566,9 @@ function laneSeam(e, n) {
555
566
  }
556
567
  const t = s.T;
557
568
  if (t.Re !== e) continue;
558
- if (!(s.l & CONFIG_GUESS) && !s.i && s.ue !== NOT_PENDING) {
559
- t.v = s.ue;
560
- s.ue = NOT_PENDING;
569
+ if (!(s.l & CONFIG_GUESS) && !s.i && s.ie !== NOT_PENDING) {
570
+ t.P = s.ie;
571
+ s.ie = NOT_PENDING;
561
572
  }
562
573
  // The frame this pass built is the screen's now; the one it replaced
563
574
  // goes (as `commitPendingNode` retires a committed pass's).
@@ -582,7 +593,7 @@ function laneSeam(e, n) {
582
593
  * frame is not complete without it (A15) — landing it would commit the write
583
594
  * beside a derivation still showing the old one. A guess whose own flight is
584
595
  * up likewise: the question was asked in this frame. */ function lanesBlocked(e) {
585
- return e.v && linkBlocked(e) || nestedBlocked(e);
596
+ return e.P && linkBlocked(e) || nestedBlocked(e);
586
597
  }
587
598
 
588
599
  /** The lanes under `t` (its own; a link group's are each other's). */ function nestedBlocked(e) {
@@ -611,17 +622,17 @@ function laneSeam(e, n) {
611
622
  // folds a current one beneath it (D-34): true.
612
623
  const s = stale(e, question);
613
624
  if (GlobalQueue.an?.(e, n, s) || s) {
614
- e.ue = n;
625
+ e.ie = n;
615
626
  e.l |= CONFIG_HELD;
616
627
  schedule();
617
628
  return n;
618
629
  }
619
- supersede(e, n, !e.xe || !e.xe(e.T.v, n));
630
+ supersede(e, n, !e.xe || !e.xe(e.T.P, n));
620
631
  } else {
621
632
  const s = txOf(e);
622
633
  if (e.xe && e.xe(laneValueOf(e), n)) return n;
623
- if (s.ke) e.ue = n; else e.T.v = n;
624
- if (e.X !== undefined) e.ie = clock;
634
+ if (s.ge) e.ie = n; else e.T.P = n;
635
+ if (e.X !== undefined) e.Se = clock;
625
636
  insertSubs(e);
626
637
  laneDirty(e, s);
627
638
  }
@@ -643,18 +654,18 @@ function laneSeam(e, n) {
643
654
  * A24). The guess's own question answering supersedes as usual. */ function laneOutcome(e, n, s) {
644
655
  if (s) return true;
645
656
  if (stale(e, answered(e))) {
646
- e.ue = n;
657
+ e.ie = n;
647
658
  e.l |= CONFIG_HELD;
648
659
  return true;
649
660
  }
650
- supersede(e, n, !e.xe || !e.xe(e.T.v, n));
661
+ supersede(e, n, !e.xe || !e.xe(e.T.P, n));
651
662
  return true;
652
663
  }
653
664
 
654
665
  /** THE provenance test, for a derivation's pass and a write alike: an
655
666
  * answer to question `q` landing on a guess is stale when `q` is older
656
667
  * than the guess's own; unstamped (0) and mainline are current. */ function stale(e, n) {
657
- return n !== 0 && n < e.T.Ee;
668
+ return n !== 0 && n < e.T.Te;
658
669
  }
659
670
 
660
671
  /** The question a derivation's pass answered: the newest among the stamped
@@ -663,7 +674,7 @@ function laneSeam(e, n) {
663
674
  let n = 0;
664
675
  for (let s = e.C; s !== null; s = s.G) {
665
676
  const e = s.S;
666
- if (e.T !== null && e.T.Ee > n && e.ie === clock) n = e.T.Ee;
677
+ if (e.T !== null && e.T.Te > n && e.Se === clock) n = e.T.Te;
667
678
  }
668
679
  return n;
669
680
  }
@@ -693,20 +704,29 @@ const laneSeams = e => {
693
704
  // now (one run — #3322, #3540). Other verdict-lane work re-derives only
694
705
  // if the frame stays parked: a transaction landing at this seam makes
695
706
  // what it read the screen (one run).
696
- if (t.R & REACTIVE_DISPOSED || l != null && l._parent?.he === l && (t.l & CONFIG_VERDICT ? !(t.R & REACTIVE_PROBE_UNANSWERED) : !blocked(l._parent))) continue;
707
+ if (t.R & REACTIVE_DISPOSED || l != null && l._parent?.Pe === l && (t.l & CONFIG_VERDICT ? !(t.R & REACTIVE_PROBE_UNANSWERED) : !blocked(l._parent))) continue;
697
708
  // A leaked effect re-derives seated in its lane from its first read: it
698
709
  // carries no lane value (`laneStage`), so without this its pass starts
699
710
  // as mainline, joins the parked frame on its first held read and reads
700
711
  // the staging, then re-enters the lane at its guess read and leaks
701
712
  // again — every round (#4014). A computed is already seated by its
702
713
  // override, and a written guess's own pass stays the frame's.
703
- if (l != null && l.v && t.i) t.R |= REACTIVE_LANE_DIRTY;
714
+ if (l != null && l.P && t.i) t.R |= REACTIVE_LANE_DIRTY;
704
715
  enqueueSub(t);
705
- if (l != null && l.v && n.indexOf(l) === -1) n.push(l);
716
+ if (l != null && l.P && n.indexOf(l) === -1) n.push(l);
706
717
  }
707
718
  for (let e = Math.min(judged, lanes.length) - 1; e >= 0; e--) laneSeam(lanes[e], n.indexOf(lanes[e]) !== -1);
719
+ // A verdict reader that entered a lane this seam held: its run waits with
720
+ // the lane, and the verdict beside it would freeze — it re-derives next
721
+ // round from the frame's seat, a stale reader of the lane (#4284).
722
+ for (let e; e = entered.pop(); ) if (e.T.Re?.ln) {
723
+ e.R &= ~REACTIVE_LANE_DIRTY;
724
+ enqueueSub(e);
725
+ }
708
726
  };
709
727
 
728
+ /** Render effects that read a verdict and entered a lane before its seam (#4284). */ const entered = [];
729
+
710
730
  installLaneHooks(laneRead, laneStage, laneOutcome, laneWrite, applyGuessesAt, laneSeams, () => lanes.length !== 0 && laneCorrections(), endLanes, lanesBlocked);
711
731
 
712
732
  GlobalQueue.J = verdictLane;