@solidjs/signals 2.0.0-rc.14 → 2.0.0-rc.16

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 (98) hide show
  1. package/dist/dev-shared.js +882 -405
  2. package/dist/dev.attribution.js +172 -66
  3. package/dist/dev.js +1529 -745
  4. package/dist/observe/affects-marks.js +86 -0
  5. package/dist/observe/affects.js +32 -80
  6. package/dist/observe/boundaries.js +202 -166
  7. package/dist/observe/core/async.js +192 -141
  8. package/dist/observe/core/attribution-queries.js +1 -1
  9. package/dist/observe/core/attribution.js +315 -214
  10. package/dist/observe/core/constants.js +23 -4
  11. package/dist/observe/core/context.js +3 -3
  12. package/dist/observe/core/core.js +532 -360
  13. package/dist/observe/core/dev.js +63 -35
  14. package/dist/observe/core/effect.js +47 -47
  15. package/dist/observe/core/error.js +5 -3
  16. package/dist/observe/core/external.js +5 -6
  17. package/dist/observe/core/graph.js +56 -42
  18. package/dist/observe/core/heap.js +33 -33
  19. package/dist/observe/core/identities.js +62 -0
  20. package/dist/observe/core/lanes.js +242 -229
  21. package/dist/observe/core/owner.js +62 -50
  22. package/dist/observe/core/scheduler.js +322 -168
  23. package/dist/observe/core/truth.js +45 -0
  24. package/dist/observe/core/verdict.js +114 -64
  25. package/dist/observe/deferred.js +184 -0
  26. package/dist/observe/index.js +7 -1
  27. package/dist/observe/map.js +339 -254
  28. package/dist/observe/reveal.js +77 -77
  29. package/dist/observe/signals.js +54 -33
  30. package/dist/observe/store/affects.js +76 -69
  31. package/dist/observe/store/edges.js +39 -0
  32. package/dist/observe/store/hooks.js +13 -0
  33. package/dist/observe/store/index.js +0 -2
  34. package/dist/observe/store/optimistic.js +82 -44
  35. package/dist/observe/store/projection.js +83 -64
  36. package/dist/observe/store/reconcile.js +32 -30
  37. package/dist/observe/store/store.js +219 -123
  38. package/dist/prod/affects-marks.js +86 -0
  39. package/dist/prod/affects.js +33 -79
  40. package/dist/prod/boundaries.js +185 -149
  41. package/dist/prod/core/async.js +176 -135
  42. package/dist/prod/core/constants.js +23 -4
  43. package/dist/prod/core/context.js +3 -3
  44. package/dist/prod/core/core.js +521 -353
  45. package/dist/prod/core/effect.js +66 -66
  46. package/dist/prod/core/error.js +5 -3
  47. package/dist/prod/core/external.js +5 -6
  48. package/dist/prod/core/graph.js +56 -42
  49. package/dist/prod/core/heap.js +38 -38
  50. package/dist/prod/core/identities.js +62 -0
  51. package/dist/prod/core/lanes.js +237 -224
  52. package/dist/prod/core/owner.js +62 -51
  53. package/dist/prod/core/scheduler.js +312 -158
  54. package/dist/prod/core/truth.js +45 -0
  55. package/dist/prod/core/verdict.js +113 -63
  56. package/dist/prod/deferred.js +182 -0
  57. package/dist/prod/index.js +7 -1
  58. package/dist/prod/map.js +366 -281
  59. package/dist/prod/reveal.js +77 -77
  60. package/dist/prod/signals.js +59 -38
  61. package/dist/prod/store/affects.js +76 -69
  62. package/dist/prod/store/edges.js +39 -0
  63. package/dist/prod/store/hooks.js +13 -0
  64. package/dist/prod/store/index.js +0 -2
  65. package/dist/prod/store/optimistic.js +121 -84
  66. package/dist/prod/store/projection.js +46 -34
  67. package/dist/prod/store/reconcile.js +32 -30
  68. package/dist/prod/store/store.js +205 -116
  69. package/dist/types/affects-marks.d.ts +14 -0
  70. package/dist/types/boundaries.d.ts +5 -1
  71. package/dist/types/core/async.d.ts +10 -0
  72. package/dist/types/core/attribution.d.ts +6 -2
  73. package/dist/types/core/constants.d.ts +18 -1
  74. package/dist/types/core/core.d.ts +77 -5
  75. package/dist/types/core/dev.d.ts +43 -13
  76. package/dist/types/core/graph.d.ts +11 -0
  77. package/dist/types/core/identities.d.ts +17 -0
  78. package/dist/types/core/index.d.ts +2 -1
  79. package/dist/types/core/lanes.d.ts +2 -4
  80. package/dist/types/core/owner.d.ts +5 -3
  81. package/dist/types/core/scheduler.d.ts +59 -34
  82. package/dist/types/core/truth.d.ts +16 -0
  83. package/dist/types/core/types.d.ts +21 -6
  84. package/dist/types/core/verdict.d.ts +32 -0
  85. package/dist/types/deferred.d.ts +28 -0
  86. package/dist/types/index.d.ts +6 -0
  87. package/dist/types/map.d.ts +2 -2
  88. package/dist/types/signals.d.ts +28 -7
  89. package/dist/types/store/affects.d.ts +11 -0
  90. package/dist/types/store/edges.d.ts +9 -0
  91. package/dist/types/store/hooks.d.ts +48 -0
  92. package/dist/types/store/index.d.ts +10 -4
  93. package/dist/types/store/optimistic.d.ts +3 -2
  94. package/dist/types/store/projection.d.ts +4 -3
  95. package/dist/types/store/store.d.ts +4 -39
  96. package/dist/types/store/target.d.ts +16 -8
  97. package/dist/types/store/types.d.ts +14 -0
  98. package/package.json +1 -1
@@ -1,12 +1,14 @@
1
- import { CONFIG_GUESS, NOT_PENDING, CONFIG_OVERRIDE, REACTIVE_DISPOSED, CONFIG_VERDICT, REACTIVE_PROBE_UNANSWERED, CONFIG_AUTHORITATIVE, CONFIG_CHILDREN_FORBIDDEN, STATUS_PENDING, EFFECT_RENDER, CONFIG_HELD, STATUS_UNINITIALIZED, REACTIVE_SCREEN_READ, REACTIVE_FRAME_READ, REACTIVE_LANE_READ, REACTIVE_RECOMPUTING_DEPS, REACTIVE_LANE_DIRTY, CONFIG_STAGED, REACTIVE_JOINED, CONFIG_SLOT_NODE, REACTIVE_IN_HEAP, REACTIVE_DIRTY, REACTIVE_CHECK, CONFIG_INPUTS_PUBLISHED } 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, 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";
2
2
 
3
- import { tracking, ext, stagedRead } from "./core.js";
3
+ import { ext, tracking, stagedRead } from "./core.js";
4
4
 
5
5
  import { NotReadyError } from "./error.js";
6
6
 
7
+ import { laneValueOf } from "./truth.js";
8
+
7
9
  import { enqueueSub } from "./heap.js";
8
10
 
9
- import { schedule, question, nextQuestion, GlobalQueue, blocked, txOf, passLane, sameLane, flushTransaction, resolveTx, queuePendingNode, list, clock, insertSubs, laneDirty, merge, newTransaction, reruns, releaseQueues, ownFlights, setPassLane, holdNode, joinFuture, commitPendingNode } from "./scheduler.js";
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";
10
12
 
11
13
  // Lanes (plan sec. 28 replay, 2026-10-02; maintainer rulings 2026-10-01/02). A lane
12
14
  // is "a new base of a transition": the sub-frame an optimistic write opens
@@ -38,24 +40,18 @@ import { schedule, question, nextQuestion, GlobalQueue, blocked, txOf, passLane,
38
40
  /** Live lanes (parented). Scanned at every seam while non-empty. */
39
41
  const lanes = [];
40
42
 
43
+ /** A pass left a shown slot the equality gate can no longer see (#3892). */ const LEFT_SHOWN = 1 << 20;
44
+
41
45
  function newLane(e) {
42
46
  const n = newTransaction(true, e);
43
47
  lanes.push(n);
44
48
  return n;
45
49
  }
46
50
 
47
- /** A lane node's current value: its guess, or the latest it derived — the
48
- * staging a shown lane holds for its next reveal, else its slot; the
49
- * committed value while it has none (its first lane pass in flight). */ function laneValueOf(e) {
50
- if (!(e.u & CONFIG_GUESS) && e.Ae !== NOT_PENDING) return e.Ae;
51
- const n = e.m.Z;
52
- return n !== NOT_PENDING ? n : e.pe;
53
- }
54
-
55
51
  /** What the screen shows for a lane's node: the lane's value once the lane
56
52
  * has revealed, the committed truth before. */ function display(e) {
57
- const n = e.m.Z;
58
- return e.m.ke.ve && n !== NOT_PENDING ? n : e.pe;
53
+ const n = e.T.v;
54
+ return e.T.Re.ke && n !== NOT_PENDING ? n : e.Ie;
59
55
  }
60
56
 
61
57
  /** Guesses written since the last seam (`[node, value, question, …]`).
@@ -70,7 +66,7 @@ function newLane(e) {
70
66
  * on (a store setter's draft too, store/optimistic.ts). */ function guessedValueOf(e) {
71
67
  const n = pendingGuessOf(e);
72
68
  if (n !== NOT_PENDING) return n;
73
- return e.u & CONFIG_OVERRIDE ? laneValueOf(e) : e.pe;
69
+ return e.l & CONFIG_OVERRIDE ? laneValueOf(e) : e.Ie;
74
70
  }
75
71
 
76
72
  /** The unflushed guess to `n`, else NOT_PENDING. */ function pendingGuessOf(e) {
@@ -84,9 +80,9 @@ function optimisticWrite(e, n) {
84
80
  // again is no guess (the node's comparator, as for any write) — unless
85
81
  // the node already carries one: the user re-asked, and the re-ask renews
86
82
  // the guess's question and entangles its frame (#3347) without notifying.
87
- const u = guessedValueOf(e);
88
- if (typeof n === "function") n = n(u);
89
- if (e.We && e.We(u, n) && !(e.u & CONFIG_GUESS)) return n;
83
+ const s = guessedValueOf(e);
84
+ if (typeof n === "function") n = n(s);
85
+ if (e.xe && e.xe(s, n) && !(e.l & CONFIG_GUESS)) return n;
90
86
  pendingGuesses.push(e, n, question || nextQuestion());
91
87
  schedule();
92
88
  return n;
@@ -104,35 +100,40 @@ function optimisticWrite(e, n) {
104
100
  /** A guess's own truth is in flight: the node's own refetch — or, a store
105
101
  * leaf's, its family's derive (the slot's flight; store/optimistic.ts
106
102
  * installs the resolver). A17: the guess stands in for the flight. */ function inFlight(e) {
107
- return (e.G & STATUS_PENDING) !== 0 || (e.u & CONFIG_SLOT_NODE) !== 0 && GlobalQueue.F?.(e) === true;
103
+ return (e.m & STATUS_PENDING) !== 0 || (e.l & CONFIG_SLOT_NODE) !== 0 && GlobalQueue.k?.(e) === true;
108
104
  }
109
105
 
110
106
  function applyGuesses(e) {
111
107
  let n = null;
112
- for (let u = 0; u < pendingGuesses.length; u += 3) {
113
- const l = pendingGuesses[u];
114
- const t = pendingGuesses[u + 1];
115
- let s = true;
116
- if (l.u & CONFIG_OVERRIDE) {
108
+ for (let s = 0; s < pendingGuesses.length; s += 3) {
109
+ const t = pendingGuesses[s];
110
+ const l = pendingGuesses[s + 1];
111
+ let u = true;
112
+ // The frame already holding the slot: a guess over it is a second
113
+ // suggestion for the slot, and two cannot finish apart (A34 (1)) — the
114
+ // frames entangle.
115
+ let i = null;
116
+ if (t.l & CONFIG_OVERRIDE) {
117
117
  // A lane's node already: a guess re-asked, or a derivation guessed
118
- // over (its staging is void — the guess is the value now). Two
119
- // suggestions for one slot cannot finish apart (A34 (1)): the frames
120
- // entangle. The same value re-asked renews the question; nothing to
121
- // notify.
122
- s = !l.We || !l.We(laneValueOf(l), t);
123
- if (!(l.u & CONFIG_GUESS)) {
124
- l.Ae = NOT_PENDING;
125
- l.u |= CONFIG_GUESS;
118
+ // over (its staging is void — the guess is the value now). The same
119
+ // value re-asked renews the question; nothing to notify.
120
+ u = !t.xe || !t.xe(laneValueOf(t), l);
121
+ if (!(t.l & CONFIG_GUESS)) {
122
+ t.se = NOT_PENDING;
123
+ t.l |= CONFIG_GUESS;
126
124
  }
127
- l.m.Z = t;
128
- const n = txOf(l)._parent;
129
- if (e !== null && n !== null) merge(e, n);
125
+ t.T.v = l;
126
+ i = txOf(t)._parent;
130
127
  } else {
131
- let u;
132
- if (l.u & CONFIG_HELD) u = newLane(txOf(l)); else {
133
- if (e === null && inFlight(l)) e = newTransaction(false);
128
+ let s;
129
+ // A held node: a truth staged there, or what a corrected guess showed.
130
+ // The guess composes on it, so it ends with that hold — and with its
131
+ // own frame's (F-11): it lands only when both have (the board's rapid
132
+ // adds — a later add's row reverted with an earlier add's landing).
133
+ if (t.l & CONFIG_HELD) s = newLane(i = txOf(t)); else {
134
+ if (e === null && inFlight(t)) e = newTransaction(false);
134
135
  if (e === null) continue;
135
- u = n ??= newLane(e);
136
+ s = n ??= newLane(e);
136
137
  }
137
138
  // (A guess equal to a truth staged beneath it is confirmed at birth —
138
139
  // A24 — and still re-derives its readers as the lane's: the truth's
@@ -140,17 +141,18 @@ function applyGuesses(e) {
140
141
  // screen's plus the guess (plan sec. 19) — a derivation reading a held write
141
142
  // beside the guess must not show it. Two flights for one input, when
142
143
  // the worlds coincide, is the price.)
143
- ext(l).Z = t;
144
- l.u |= CONFIG_OVERRIDE | CONFIG_GUESS;
145
- list(l, u);
144
+ ext(t).v = l;
145
+ t.l |= CONFIG_OVERRIDE | CONFIG_GUESS;
146
+ list(t, s);
146
147
  }
147
- ext(l).Oe = pendingGuesses[u + 2];
148
- if (s) {
148
+ if (e !== null && i !== null) merge(e, i);
149
+ ext(t).Ee = pendingGuesses[s + 2];
150
+ if (u) {
149
151
  // The lane's members re-derive as its work (REACTIVE_LANE_DIRTY): a
150
152
  // blocked lane's re-guess does not re-run its render effects as stale
151
153
  // readers republishing the committed view (#3460).
152
- insertSubs(l);
153
- laneDirty(l, txOf(l));
154
+ insertSubs(t);
155
+ laneDirty(t, txOf(t));
154
156
  }
155
157
  }
156
158
  pendingGuesses.length = 0;
@@ -165,38 +167,40 @@ function applyGuesses(e) {
165
167
  * through an ancestor's guess stays its own (the screen plus its own
166
168
  * guesses). */ function enterLane(e, n) {
167
169
  n.R |= REACTIVE_LANE_READ;
168
- const u = passLane;
169
- if (u === null) {
170
+ const s = passLane;
171
+ if (s === null) {
170
172
  setPassLane(e);
171
173
  // The pass read a held write before its first lane read (it joined the
172
174
  // frame's future as mainline would): lane work sees the screen — the
173
175
  // seam re-derives it on the committed world next round (`stagedReaders`,
174
- // the park's repair), as it does a lane pass that read a staging.
175
- if (n.R & REACTIVE_JOINED) stagedRead(n);
176
+ // the park's repair), as it does a lane pass that read a staging. Not a
177
+ // pass whose held reads were all of nodes born held (no staged read,
178
+ // `stagedRead`): it has no committed world to re-derive on (#3969).
179
+ if (n.R & REACTIVE_JOINED && n.R & REACTIVE_STAGED_READ) stagedRead(n);
176
180
  return;
177
181
  }
178
- if (sameLane(u, e)) return setPassLane(e);
179
- if (under(u, e)) return;
180
- if (under(e, u)) return setPassLane(e);
181
- linkLanes(u, e);
182
+ if (sameLane(s, e)) return setPassLane(e);
183
+ if (under(s, e)) return;
184
+ if (under(e, s)) return setPassLane(e);
185
+ linkLanes(s, e);
182
186
  setPassLane(e);
183
187
  }
184
188
 
185
189
  /** Is `l` nested under `a` (an ancestor lane)? */ function under(e, n) {
186
- for (let u = e._parent; u !== null && u.Z; u = u._parent) if (u === n) return true;
190
+ for (let s = e._parent; s !== null && s.v; s = s._parent) if (s === n) return true;
187
191
  return false;
188
192
  }
189
193
 
190
194
  /** One link group (a shared array) for both lanes' groups. */ function linkLanes(e, n) {
191
- const u = e.nn ?? (e.nn = [ e ]);
192
- const l = n.nn;
193
- if (l === u) return;
194
- if (l === null) {
195
- u.push(n);
196
- n.nn = u;
197
- } else for (let e = 0; e < l.length; e++) {
198
- u.push(l[e]);
199
- l[e].nn = u;
195
+ const s = e.en ?? (e.en = [ e ]);
196
+ const t = n.en;
197
+ if (t === s) return;
198
+ if (t === null) {
199
+ s.push(n);
200
+ n.en = s;
201
+ } else for (let e = 0; e < t.length; e++) {
202
+ s.push(t[e]);
203
+ t[e].en = s;
200
204
  }
201
205
  }
202
206
 
@@ -204,20 +208,20 @@ function applyGuesses(e) {
204
208
  * without the group recursion. (A guess in `k` whose own truth is in flight
205
209
  * blocks `k`'s parent, not `k` — nor, through the link, `l`: the guess
206
210
  * shows, A17.) */ function linkBlocked(e) {
207
- const n = e.nn;
208
- if (n !== null) for (let u = 0; u < n.length; u++) {
209
- const l = n[u];
210
- if (l !== e && (l.tt !== 0 || ownFlights(l) || nestedBlocked(l))) return true;
211
+ const n = e.en;
212
+ if (n !== null) for (let s = 0; s < n.length; s++) {
213
+ const t = n[s];
214
+ if (t !== e && (t.tt !== 0 || ownFlights(t) || nestedBlocked(t))) return true;
211
215
  }
212
216
  return false;
213
217
  }
214
218
 
215
219
  function unlink(e) {
216
- const n = e.nn;
220
+ const n = e.en;
217
221
  if (n === null) return;
218
- const u = n.indexOf(e);
219
- if (u !== -1) n.splice(u, 1);
220
- e.nn = null;
222
+ const s = n.indexOf(e);
223
+ if (s !== -1) n.splice(s, 1);
224
+ e.en = null;
221
225
  }
222
226
 
223
227
  /** Verdicts (maintainer, 2026-10-01): `isPending` and `latest` are
@@ -227,7 +231,7 @@ function unlink(e) {
227
231
  * lane under the holder, shown now, re-derived at the landing, ending with
228
232
  * it. Judged at the seam like any lane: blocked while a verdict reader's
229
233
  * own derivation is in flight (lane rule 3), shown otherwise. */ function verdictLane(e) {
230
- return e.ye ??= newLane(e);
234
+ return e.he ??= newLane(e);
231
235
  }
232
236
 
233
237
  /** A lane pass's node (core.ts `recompute`, before its staging; a pending
@@ -244,19 +248,24 @@ function unlink(e) {
244
248
  * not leave (A30: it never got there). A first pass under a lane is the
245
249
  * lane's (ruling A); a guess is written, not derived — it never leaves this
246
250
  * way. `errored`: the pass has no answer — or, a lane pass's pending
247
- * propagation (async.ts `propagateStatus`), the node gone pending. */ function laneStage(e, n, u, l) {
248
- if (!(u || l || e.R & REACTIVE_LANE_READ || e.u & CONFIG_GUESS)) {
249
- if (e.m !== null) {
250
- if (e.m.ke?.Z) e.m.ke = null;
251
- e.m.Z = NOT_PENDING;
251
+ * propagation (async.ts `propagateStatus`), the node gone pending. */ function laneStage(e, n, s, t) {
252
+ if (!(s || t || e.R & REACTIVE_LANE_READ || e.l & CONFIG_GUESS)) {
253
+ const n = e.T;
254
+ if (n !== null) {
255
+ const s = n.Re;
256
+ // Cleared before equality, so a return to the committed value notifies
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;
252
261
  }
253
- e.u &= -2305;
262
+ e.l &= -1050881;
254
263
  return false;
255
264
  }
256
265
  if (!e.i) {
257
- if (!(e.u & CONFIG_OVERRIDE)) {
258
- e.Ae = NOT_PENDING;
259
- e.u = e.u & ~CONFIG_HELD | CONFIG_OVERRIDE;
266
+ if (!(e.l & CONFIG_OVERRIDE)) {
267
+ e.se = NOT_PENDING;
268
+ e.l = e.l & -1048833 | CONFIG_OVERRIDE;
260
269
  ext(e);
261
270
  }
262
271
  // A written guess whose own pass is the lane's work — its source is a
@@ -265,7 +274,7 @@ function unlink(e) {
265
274
  // of the lane from here (its value the lane's, its fate the lane's), no
266
275
  // longer a written guess. A pass with no answer (pending, errored)
267
276
  // leaves the guess.
268
- if (!l) e.u &= ~CONFIG_GUESS;
277
+ if (!t) e.l &= ~CONFIG_GUESS;
269
278
  }
270
279
  // A leaf has no lane value to seat it (`recompute`): one left waiting on
271
280
  // the lane's flight runs its next pass as the lane's — the landing that
@@ -277,8 +286,8 @@ function unlink(e) {
277
286
  // `laneRead` decides — its frame holds). Its pending is the frame's: queued
278
287
  // for the commit sweep as mainline's (async.ts). A node born in the lane
279
288
  // has nothing on screen: its leaf waits as the lane's.
280
- else if (l) {
281
- if (l !== true && !(l.G & STATUS_UNINITIALIZED) && (e.u & CONFIG_HELD || e.R & REACTIVE_RECOMPUTING_DEPS) && !e.m?.ke?.Z) {
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) {
282
291
  queuePendingNode(e);
283
292
  return false;
284
293
  }
@@ -288,29 +297,32 @@ function unlink(e) {
288
297
  return true;
289
298
  }
290
299
 
291
- function supersede(e, n, u) {
292
- const l = txOf(e);
300
+ function supersede(e, n, s) {
301
+ const t = txOf(e);
293
302
  // Resolved: the parent may have merged into another transaction since the
294
303
  // lane opened (two actions guessing one slot entangle, A34 (1)) — the
295
304
  // truth is held by the transaction that lands, not the merged-away one.
296
- const t = resolveTx(l._parent ?? l);
297
- if (u) {
298
- dissolveLane(l, t, e);
305
+ const l = resolveTx(t._parent ?? t);
306
+ // A store row answered by a new object the store would reconcile into
307
+ // the guessed one unchanged is an echo, not a correction (#3898): the
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;
310
+ if (s) {
311
+ dissolveLane(t, l, e);
299
312
  // What the screen showed stays the screen until the parent lands (A18
300
313
  // (c): display and untracked reads keep the override until the commit).
301
- if (l.ve) e.pe = e.m.Z;
302
- e.u &= -10241;
303
- e.m.Z = NOT_PENDING;
304
- e.Ae = n;
305
- holdNode(e, t);
306
- joinFuture(t);
307
- if (e.t !== null) insertSubs(e);
314
+ if (t.ke) e.Ie = e.T.v;
315
+ e.l &= -10241;
316
+ e.T.v = NOT_PENDING;
317
+ holdNode(e, l);
318
+ if (e.o !== null) insertSubs(e);
308
319
  } else {
309
- e.Ae = n;
310
- e.u |= CONFIG_HELD;
311
- joinFuture(t);
312
- for (let n = e.t; n !== null; n = n.l) if (n.o.u & CONFIG_AUTHORITATIVE) enqueueSub(n.o);
320
+ e.l |= CONFIG_HELD;
321
+ // A confirmation is silent (A17); only truth readers are told.
322
+ GlobalQueue.sn?.(t);
313
323
  }
324
+ e.se = n;
325
+ joinFuture(l);
314
326
  }
315
327
 
316
328
  /** A lane's end, two ways. `into === null`: the parent landed — the lane's
@@ -322,52 +334,52 @@ function supersede(e, n, u) {
322
334
  * the screen (`_value` takes it, so the parent's re-derivation compares
323
335
  * against what is seen), a truth staged beneath a guess is the parent's to
324
336
  * land, and the runs it held (showing the void guess) are dropped: the
325
- * parent's re-derivation makes the runs that show. */ function dissolveLane(e, n, u) {
326
- const l = lanes.indexOf(e);
327
- if (l !== -1) lanes.splice(l, 1);
337
+ * parent's re-derivation makes the runs that show. */ function dissolveLane(e, n, s) {
338
+ const t = lanes.indexOf(e);
339
+ if (t !== -1) lanes.splice(t, 1);
328
340
  unlink(e);
329
341
  // Its verdicts end with it (a correction's dissolution reaches here before
330
342
  // `endLanes` would): the readers re-derive from the truth's notification.
331
- const t = e.ye;
332
- if (t !== null) {
333
- e.ye = null;
334
- if (lanes.indexOf(t) !== -1) dissolveLane(t, null);
343
+ const l = e.he;
344
+ if (l !== null) {
345
+ e.he = null;
346
+ if (lanes.indexOf(l) !== -1) dissolveLane(l, null);
335
347
  }
336
- for (let l = 0; l < e.un.length; l++) {
337
- const t = e.un[l];
338
- const s = t.m;
339
- if (t === u || s.ke !== e) continue;
340
- const i = t.i;
341
- const r = t.u & CONFIG_GUESS;
342
- const o = s.Z;
348
+ for (let t = 0; t < e.tn.length; t++) {
349
+ const l = e.tn[t];
350
+ const u = l.T;
351
+ if (l === s || u.Re !== e) continue;
352
+ const i = l.i;
353
+ const r = l.l & CONFIG_GUESS;
354
+ const o = u.v;
343
355
  // What the screen shows of it (NOT_PENDING: nothing — a lane pass that
344
356
  // errored or pends staged no value), and the lane's latest.
345
- const E = e.ve && !i ? o : t.pe;
346
- const f = laneValueOf(t);
347
- s.Z = NOT_PENDING;
348
- t.u &= -10241;
357
+ const E = e.ke && !i ? o : l.Ie;
358
+ const f = laneValueOf(l);
359
+ u.v = NOT_PENDING;
360
+ l.l &= -10241;
349
361
  if (n === null) {
350
362
  // A derivation the revert re-derives (dirtied by the guess's
351
363
  // notification — listed before it), or one still in flight, shows the
352
364
  // lane's answer beside inputs that are the truth now: a fresh reader
353
365
  // of its flight observes it (#3648, #3651; #3305's commit beneath a
354
366
  // flight).
355
- s.ke = null;
356
- if (!i && !r) t.Ae = f;
357
- commitPendingNode(t);
367
+ u.Re = null;
368
+ if (!i && !r) l.se = f;
369
+ commitPendingNode(l);
358
370
  if (!i) {
359
- if (t.R & (REACTIVE_IN_HEAP | REACTIVE_DIRTY | REACTIVE_CHECK) || t.G & STATUS_PENDING) t.u |= CONFIG_INPUTS_PUBLISHED;
360
- if (E !== NOT_PENDING && (!t.We || !t.We(E, t.pe))) insertSubs(t);
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);
361
373
  }
362
374
  } else if (r) {
363
375
  // A guess of a dissolving lane: its truth — a landing held beneath it,
364
376
  // else the value it covered — is the parent's to land, and its readers
365
377
  // re-derive from it there. What the screen showed stays the screen
366
378
  // until then (A18 (c)).
367
- if (t.Ae === NOT_PENDING) t.Ae = covered(t);
368
- if (e.ve) t.pe = o;
369
- holdNode(t, n);
370
- insertSubs(t);
379
+ if (l.se === NOT_PENDING) l.se = covered(l);
380
+ if (e.ke) l.Ie = o;
381
+ holdNode(l, n);
382
+ insertSubs(l);
371
383
  } else {
372
384
  // A correction: the lane's derivations are void. Shown, what the
373
385
  // screen showed stays the screen (committed, inputs published — every
@@ -376,20 +388,20 @@ function supersede(e, n, u) {
376
388
  // flight is asking the void world's question: its landing is nobody's
377
389
  // answer — it re-asks from the truth (whose notification may not reach
378
390
  // it: an input's truth equal to its committed value is silent).
379
- s.ke = null;
391
+ u.Re = null;
380
392
  if (!i) {
381
- if (E !== NOT_PENDING && e.ve) t.Ae = E;
382
- if (t.G & STATUS_PENDING) {
383
- s.De = null;
384
- enqueueSub(t);
393
+ if (E !== NOT_PENDING && e.ke) l.se = E;
394
+ if (l.m & STATUS_PENDING) {
395
+ u.Se = null;
396
+ enqueueSub(l);
385
397
  }
386
398
  }
387
- if (e.ve) {
388
- commitPendingNode(t);
389
- if (!i) t.u |= CONFIG_INPUTS_PUBLISHED;
399
+ if (e.ke) {
400
+ commitPendingNode(l);
401
+ if (!i) l.l |= CONFIG_INPUTS_PUBLISHED;
390
402
  } else {
391
- if (s.Me !== null || s.Be !== null) GlobalQueue.he(t, false, true);
392
- t.u &= -385;
403
+ if (u.Ue !== null || u.me !== null) GlobalQueue.Ce(l, false, true);
404
+ l.l &= -1048961;
393
405
  }
394
406
  }
395
407
  }
@@ -404,7 +416,7 @@ function supersede(e, n, u) {
404
416
  // void: nothing of it reached the screen. So are the runs a blocked lane
405
417
  // parked: they show a re-guess the seam never revealed, beside derivations
406
418
  // that keep what the screen showed.
407
- if (n === null || e.ve && !e.ln) releaseQueues(e); else e.tn[0].length = e.tn[1].length = 0;
419
+ if (n === null || e.ke && !e.ln) releaseQueues(e); else e.un[0].length = e.un[1].length = 0;
408
420
  }
409
421
 
410
422
  /** Lanes. A lane's node is read by its reader's kind: an authoritative
@@ -422,59 +434,61 @@ function supersede(e, n, u) {
422
434
  * verdict: released if the lane shows, held if it blocks) — and sees the
423
435
  * lane's latest. NOT_PENDING falls through: lane work's read of a pending
424
436
  * member throws like any. */ function laneRead(e, n) {
425
- const u = n.u & CONFIG_GUESS;
426
- if (e !== null && e.u & CONFIG_AUTHORITATIVE) return u && n.Ae !== NOT_PENDING ? n.Ae : n.pe;
437
+ const s = n.l & CONFIG_GUESS;
438
+ if (e !== null && e.l & CONFIG_AUTHORITATIVE) return GlobalQueue.rn(n);
439
+ const t = n.m;
440
+ // An errored member's lane value predates its error; the error is the answer (#4106).
441
+ if (!s && t & STATUS_ERROR) return NOT_PENDING;
427
442
  if (e === null) return laneValueOf(n);
428
443
  const l = txOf(n);
429
- const t = n.G;
430
- if (!tracking || e.u & CONFIG_CHILDREN_FORBIDDEN) {
444
+ if (!tracking || e.l & CONFIG_CHILDREN_FORBIDDEN) {
431
445
  // An untracked read inside lane work derives from the lane like a
432
446
  // tracked one, minus the subscription — `untrack` is about
433
447
  // dependencies, not about which world a pass derives from (a mapper's
434
448
  // row reads under its root, store/map): the pass enters the lane (two
435
449
  // lanes read by one pass link, as for tracked reads). Outside lane
436
450
  // work, the screen.
437
- if (passLane === null || e.u & CONFIG_CHILDREN_FORBIDDEN) return display(n);
451
+ if (passLane === null || e.l & CONFIG_CHILDREN_FORBIDDEN) return display(n);
438
452
  enterLane(l, e);
439
- if (!u && t & STATUS_PENDING) return NOT_PENDING;
453
+ if (!s && t & STATUS_PENDING) return NOT_PENDING;
440
454
  return laneValueOf(n);
441
455
  }
442
456
  if (e.i === EFFECT_RENDER && (passLane === null || !sameLane(passLane, l))) {
443
- if (!u) {
457
+ if (!s) {
444
458
  // A flight whose value has never shown: nothing to show — the leaf
445
459
  // waits on it, and its own frame holds (A15, #3334), not the lane's
446
460
  // parent. The landing lands the frame: its own pass (the flush
447
461
  // joined its transaction) reads the answer it waited on — the lane's
448
462
  // staging, revealed at this seam.
449
- if (t & STATUS_PENDING && n.m.Z === NOT_PENDING) return NOT_PENDING;
450
- if (n.Ae !== NOT_PENDING && e.u & CONFIG_HELD && flushTransaction !== null && resolveTx(flushTransaction) === txOf(e)) return n.Ae;
463
+ if (t & STATUS_PENDING && n.T.v === NOT_PENDING) return NOT_PENDING;
464
+ if (n.se !== NOT_PENDING && e.l & CONFIG_HELD && flushTransaction !== null && resolveTx(flushTransaction) === txOf(e)) return n.se;
451
465
  }
452
- if (l.ln || !u && t & STATUS_PENDING) {
453
- if (!u && !l.ve && t & STATUS_UNINITIALIZED) throw new NotReadyError(null);
466
+ if (l.ln || !s && t & STATUS_PENDING) {
467
+ if (!s && !l.ke && t & STATUS_UNINITIALIZED) throw new NotReadyError(null);
454
468
  // Re-derived at the reveal; once per pass (the pass may also be a stale
455
469
  // reader of a transaction, REACTIVE_FRAME_READ — both reruns apply).
456
470
  if (!(e.R & REACTIVE_SCREEN_READ)) {
457
471
  e.R |= REACTIVE_FRAME_READ | REACTIVE_SCREEN_READ;
458
- l.sn.push(e);
472
+ l.En.push(e);
459
473
  }
460
474
  return display(n);
461
475
  }
462
476
  }
463
477
  enterLane(l, e);
464
- if (!u && t & STATUS_PENDING) return NOT_PENDING;
478
+ if (!s && t & STATUS_PENDING) return NOT_PENDING;
465
479
  return laneValueOf(n);
466
480
  }
467
481
 
468
482
  /** The value a guess covered: the node's committed value — a store slot's
469
483
  * asked of the store (a chained link follows the inner store's commits). */ function covered(e) {
470
- return e.u & CONFIG_SLOT_NODE && GlobalQueue.rn !== undefined ? GlobalQueue.rn(e) : e.pe;
484
+ return e.l & CONFIG_SLOT_NODE && GlobalQueue.fn !== undefined ? GlobalQueue.fn(e) : e.Ie;
471
485
  }
472
486
 
473
487
  /** A guess in `l` whose own truth is in flight (its refetch — authoritative:
474
488
  * the landing supersedes, not the body's end). */ function guessFlights(e) {
475
- for (let n = 0; n < e.un.length; n++) {
476
- const u = e.un[n];
477
- if (u.u & CONFIG_GUESS && u.m.ke === e && inFlight(u)) return true;
489
+ for (let n = 0; n < e.tn.length; n++) {
490
+ const s = e.tn[n];
491
+ if (s.l & CONFIG_GUESS && s.T.Re === e && inFlight(s)) return true;
478
492
  }
479
493
  return false;
480
494
  }
@@ -494,20 +508,20 @@ function supersede(e, n, u) {
494
508
  * landing.) True when a lane was judged. */ function laneCorrections() {
495
509
  let e = false;
496
510
  const n = lanes.slice();
497
- for (let u = 0; u < n.length; u++) {
498
- const l = n[u];
499
- if (lanes.indexOf(l) === -1) continue;
500
- const t = resolveTx(l._parent);
501
- if (!t.nt || t.tt !== 0 || t.Z || ownFlights(t) || guessFlights(l)) continue;
511
+ for (let s = 0; s < n.length; s++) {
512
+ const t = n[s];
513
+ if (lanes.indexOf(t) === -1) continue;
514
+ const l = resolveTx(t._parent);
515
+ if (!l.nt || l.tt !== 0 || l.v || ownFlights(l) || guessFlights(t)) continue;
502
516
  e = true;
503
517
  // Each guess's truth: the one beneath it (a landing held there), else
504
518
  // the one it covered. (A correction dissolves the lane — the others are
505
519
  // re-homed with theirs, `dissolveLane`.)
506
- for (let e = 0; e < l.un.length && lanes.indexOf(l) !== -1; e++) {
507
- const n = l.un[e];
508
- if (n.u & CONFIG_GUESS && n.m.ke === l) {
509
- const e = n.Ae !== NOT_PENDING ? n.Ae : covered(n);
510
- supersede(n, e, !n.We || !n.We(n.m.Z, e));
520
+ for (let e = 0; e < t.tn.length && lanes.indexOf(t) !== -1; e++) {
521
+ const n = t.tn[e];
522
+ if (n.l & CONFIG_GUESS && n.T.Re === t) {
523
+ const e = n.se !== NOT_PENDING ? n.se : covered(n);
524
+ supersede(n, e, !n.xe || !n.xe(n.T.v, e));
511
525
  }
512
526
  }
513
527
  }
@@ -522,20 +536,24 @@ function laneSeam(e, n) {
522
536
  return;
523
537
  }
524
538
  e.ln = false;
525
- e.ve = true;
539
+ e.ke = true;
526
540
  reruns(e);
527
- for (let n = 0; n < e.un.length; n++) {
528
- const u = e.un[n];
529
- const l = u.m;
530
- if (l.ke !== e) continue;
531
- if (!(u.u & CONFIG_GUESS) && !u.i && u.Ae !== NOT_PENDING) {
532
- l.Z = u.Ae;
533
- u.Ae = NOT_PENDING;
541
+ for (let n = 0; n < e.tn.length; n++) {
542
+ const s = e.tn[n];
543
+ if (s.R & LEFT_SHOWN) {
544
+ s.R ^= LEFT_SHOWN;
545
+ insertSubs(s);
546
+ }
547
+ const t = s.T;
548
+ if (t.Re !== e) continue;
549
+ if (!(s.l & CONFIG_GUESS) && !s.i && s.se !== NOT_PENDING) {
550
+ t.v = s.se;
551
+ s.se = NOT_PENDING;
534
552
  }
535
553
  // The frame this pass built is the screen's now; the one it replaced
536
554
  // goes (as `commitPendingNode` retires a committed pass's).
537
- if (l.Me !== null || l.Be !== null) GlobalQueue.he(u, false, true);
538
- u.u &= ~CONFIG_STAGED;
555
+ if (t.Ue !== null || t.me !== null) GlobalQueue.Ce(s, false, true);
556
+ s.l &= ~CONFIG_STAGED;
539
557
  }
540
558
  releaseQueues(e);
541
559
  }
@@ -543,10 +561,10 @@ function laneSeam(e, n) {
543
561
  /** The parent landed: its lanes end, nested first. (None is blocked: a
544
562
  * blocked lane blocks its parent.) */ function endLanes(e) {
545
563
  for (let n = lanes.length - 1; n >= 0; n--) {
546
- const u = lanes[n];
547
- if (resolveTx(u._parent) !== e) continue;
548
- endLanes(u);
549
- dissolveLane(u, null);
564
+ const s = lanes[n];
565
+ if (resolveTx(s._parent) !== e) continue;
566
+ endLanes(s);
567
+ dissolveLane(s, null);
550
568
  }
551
569
  }
552
570
 
@@ -555,14 +573,14 @@ function laneSeam(e, n) {
555
573
  * frame is not complete without it (A15) — landing it would commit the write
556
574
  * beside a derivation still showing the old one. A guess whose own flight is
557
575
  * up likewise: the question was asked in this frame. */ function lanesBlocked(e) {
558
- return e.Z && linkBlocked(e) || nestedBlocked(e);
576
+ return e.v && linkBlocked(e) || nestedBlocked(e);
559
577
  }
560
578
 
561
579
  /** The lanes under `t` (its own; a link group's are each other's). */ function nestedBlocked(e) {
562
580
  for (let n = 0; n < lanes.length; n++) {
563
- const u = lanes[n];
564
- if (resolveTx(u._parent) !== e) continue;
565
- if (blocked(u) || guessFlights(u)) return true;
581
+ const s = lanes[n];
582
+ if (resolveTx(s._parent) !== e) continue;
583
+ if (blocked(s) || guessFlights(s)) return true;
566
584
  }
567
585
  return false;
568
586
  }
@@ -572,7 +590,7 @@ function laneSeam(e, n) {
572
590
  * landing), judged against the guess. On a derivation it is the lane's
573
591
  * latest: its staging once the lane has shown (promoted at the next
574
592
  * reveal), its slot before; the lane's members re-derive as its work. */ function laneWrite(e, n) {
575
- if (e.u & CONFIG_GUESS) {
593
+ if (e.l & CONFIG_GUESS) {
576
594
  // Provenance (A18, #3331; Q-D, plan sec. 39): a write asking an OLDER
577
595
  // question than the guess's — another action's landing beneath it —
578
596
  // is not its answer: held beneath (the truth for the commit; the
@@ -581,20 +599,20 @@ function laneSeam(e, n) {
581
599
  // continuation's — the flight's); unstamped writes and mainline are
582
600
  // current.
583
601
  if (stale(e, question)) {
584
- e.Ae = n;
585
- e.u |= CONFIG_HELD;
586
- GlobalQueue.En?.(e, n);
602
+ e.se = n;
603
+ e.l |= CONFIG_HELD;
604
+ GlobalQueue.an?.(e, n);
587
605
  schedule();
588
606
  return n;
589
607
  }
590
- supersede(e, n, !e.We || !e.We(e.m.Z, n));
608
+ supersede(e, n, !e.xe || !e.xe(e.T.v, n));
591
609
  } else {
592
- const u = txOf(e);
593
- if (e.We && e.We(laneValueOf(e), n)) return n;
594
- if (u.ve) e.Ae = n; else e.m.Z = n;
595
- if (e.re !== undefined) e.Ne = clock;
610
+ const s = txOf(e);
611
+ if (e.xe && e.xe(laneValueOf(e), n)) return n;
612
+ if (s.ke) e.se = n; else e.T.v = n;
613
+ if (e.X !== undefined) e.ie = clock;
596
614
  insertSubs(e);
597
- laneDirty(e, u);
615
+ laneDirty(e, s);
598
616
  }
599
617
  schedule();
600
618
  return n;
@@ -611,80 +629,75 @@ function laneSeam(e, n) {
611
629
  * It is staged beneath the guess, for the commit like any landing, and
612
630
  * nothing moves: no downstream re-ask, no pending flip on the guess's
613
631
  * readers (`isPending` of the guess itself says the held truth differs,
614
- * A24). The guess's own question answering supersedes as usual. */ function laneOutcome(e, n, u) {
615
- if (u) return true;
632
+ * A24). The guess's own question answering supersedes as usual. */ function laneOutcome(e, n, s) {
633
+ if (s) return true;
616
634
  if (stale(e, answered(e))) {
617
- e.Ae = n;
618
- e.u |= CONFIG_HELD;
635
+ e.se = n;
636
+ e.l |= CONFIG_HELD;
619
637
  return true;
620
638
  }
621
- supersede(e, n, !e.We || !e.We(e.m.Z, n));
639
+ supersede(e, n, !e.xe || !e.xe(e.T.v, n));
622
640
  return true;
623
641
  }
624
642
 
625
643
  /** THE provenance test, for a derivation's pass and a write alike: an
626
644
  * answer to question `q` landing on a guess is stale when `q` is older
627
645
  * than the guess's own; unstamped (0) and mainline are current. */ function stale(e, n) {
628
- return n !== 0 && n < e.m.Oe;
646
+ return n !== 0 && n < e.T.Ee;
629
647
  }
630
648
 
631
649
  /** The question a derivation's pass answered: the newest among the stamped
632
650
  * sources that changed this round (a flight's landing carries the question
633
651
  * that started it); 0 when none is stamped. */ function answered(e) {
634
652
  let n = 0;
635
- for (let u = e._; u !== null; u = u.p) {
636
- const e = u.I;
637
- if (e.m !== null && e.m.Oe > n && e.Ne === clock) n = e.m.Oe;
653
+ for (let s = e.C; s !== null; s = s.G) {
654
+ const e = s.S;
655
+ if (e.T !== null && e.T.Ee > n && e.ie === clock) n = e.T.Ee;
638
656
  }
639
657
  return n;
640
658
  }
641
659
 
642
- GlobalQueue.Nt = laneRead;
643
-
644
- GlobalQueue.M = laneStage;
645
-
646
- GlobalQueue.Qe = laneOutcome;
647
-
648
- GlobalQueue.Tt = laneWrite;
649
-
650
660
  /** The lanes alive before this seam's guesses opened theirs (a prefix of
651
661
  * `lanes`; nothing dissolves one between here and the seam loop): a lane
652
662
  * born at the seam has no work to judge yet (its passes run next round) —
653
663
  * it is neither shown nor blocked until it has. */ let judged = 0;
654
664
 
655
- GlobalQueue.fn = e => {
665
+ const applyGuessesAt = e => {
656
666
  judged = lanes.length;
657
667
  if (pendingGuesses.length !== 0) applyGuesses(e);
658
668
  };
659
669
 
660
- GlobalQueue.Nn = e => {
670
+ const laneSeams = e => {
661
671
  // Passes that read a write the parked frame holds as the screen
662
672
  // (`stagedReaders`: lane work, a verdict reader before the verdict): they
663
673
  // re-derive on the committed world next round (and register as stale
664
674
  // readers of the transaction there); a lane's runs wait that round — a
665
675
  // lane sees the screen plus its own guesses.
666
676
  const n = [];
667
- if (e !== null) for (let u = 0; u < e.length; u++) {
668
- const l = e[u];
669
- const t = l.m?.ke;
677
+ if (e !== null) for (let s = 0; s < e.length; s++) {
678
+ const t = e[s];
679
+ const l = t.T?.Re;
670
680
  // A verdict reader a later read of the same pass routed into a verdict
671
681
  // lane answered for itself: it re-derives at the holder's landing, not
672
682
  // now (one run — #3322, #3540). Other verdict-lane work re-derives only
673
683
  // if the frame stays parked: a transaction landing at this seam makes
674
684
  // what it read the screen (one run).
675
- if (l.R & REACTIVE_DISPOSED || t != null && t._parent?.ye === t && (l.u & CONFIG_VERDICT ? !(l.R & REACTIVE_PROBE_UNANSWERED) : !blocked(t._parent))) continue;
676
- enqueueSub(l);
677
- if (t != null && t.Z && n.indexOf(t) === -1) n.push(t);
685
+ if (t.R & REACTIVE_DISPOSED || l != null && l._parent?.he === l && (t.l & CONFIG_VERDICT ? !(t.R & REACTIVE_PROBE_UNANSWERED) : !blocked(l._parent))) continue;
686
+ // A leaked effect re-derives seated in its lane from its first read: it
687
+ // carries no lane value (`laneStage`), so without this its pass starts
688
+ // as mainline, joins the parked frame on its first held read and reads
689
+ // the staging, then re-enters the lane at its guess read and leaks
690
+ // again — every round (#4014). A computed is already seated by its
691
+ // override, and a written guess's own pass stays the frame's.
692
+ if (l != null && l.v && t.i) t.R |= REACTIVE_LANE_DIRTY;
693
+ enqueueSub(t);
694
+ if (l != null && l.v && n.indexOf(l) === -1) n.push(l);
678
695
  }
679
696
  for (let e = Math.min(judged, lanes.length) - 1; e >= 0; e--) laneSeam(lanes[e], n.indexOf(lanes[e]) !== -1);
680
697
  };
681
698
 
682
- GlobalQueue.an = () => lanes.length !== 0 && laneCorrections();
683
-
684
- GlobalQueue.In = endLanes;
685
-
686
- GlobalQueue.cn = lanesBlocked;
699
+ installLaneHooks(laneRead, laneStage, laneOutcome, laneWrite, applyGuessesAt, laneSeams, () => lanes.length !== 0 && laneCorrections(), endLanes, lanesBlocked);
687
700
 
688
- GlobalQueue.ne = verdictLane;
701
+ GlobalQueue.J = verdictLane;
689
702
 
690
703
  export { display, enterLane, guessedValueOf, laneRead, laneStage, laneValueOf, optimisticWrite, pendingGuessOf, supersede, verdictLane };