@solidjs/signals 2.0.0-rc.15 → 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 (89) hide show
  1. package/dist/dev-shared.js +785 -367
  2. package/dist/dev.attribution.js +75 -52
  3. package/dist/dev.js +1120 -567
  4. package/dist/observe/affects-marks.js +86 -0
  5. package/dist/observe/affects.js +22 -73
  6. package/dist/observe/boundaries.js +191 -189
  7. package/dist/observe/core/async.js +175 -131
  8. package/dist/observe/core/attribution-queries.js +1 -1
  9. package/dist/observe/core/attribution.js +176 -159
  10. package/dist/observe/core/constants.js +17 -3
  11. package/dist/observe/core/context.js +3 -3
  12. package/dist/observe/core/core.js +503 -363
  13. package/dist/observe/core/dev.js +66 -38
  14. package/dist/observe/core/effect.js +48 -48
  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 +57 -43
  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 +226 -259
  21. package/dist/observe/core/owner.js +62 -50
  22. package/dist/observe/core/scheduler.js +319 -171
  23. package/dist/observe/core/truth.js +45 -0
  24. package/dist/observe/core/verdict.js +88 -50
  25. package/dist/observe/deferred.js +184 -0
  26. package/dist/observe/index.js +7 -1
  27. package/dist/observe/map.js +345 -260
  28. package/dist/observe/reveal.js +76 -76
  29. package/dist/observe/signals.js +41 -30
  30. package/dist/observe/store/affects.js +6 -6
  31. package/dist/observe/store/edges.js +39 -0
  32. package/dist/observe/store/optimistic.js +41 -36
  33. package/dist/observe/store/projection.js +68 -55
  34. package/dist/observe/store/store.js +157 -104
  35. package/dist/prod/affects-marks.js +86 -0
  36. package/dist/prod/affects.js +23 -72
  37. package/dist/prod/boundaries.js +155 -153
  38. package/dist/prod/core/async.js +171 -127
  39. package/dist/prod/core/constants.js +17 -3
  40. package/dist/prod/core/context.js +3 -3
  41. package/dist/prod/core/core.js +478 -342
  42. package/dist/prod/core/effect.js +68 -68
  43. package/dist/prod/core/error.js +5 -3
  44. package/dist/prod/core/external.js +5 -6
  45. package/dist/prod/core/graph.js +57 -43
  46. package/dist/prod/core/heap.js +38 -38
  47. package/dist/prod/core/identities.js +62 -0
  48. package/dist/prod/core/lanes.js +217 -250
  49. package/dist/prod/core/owner.js +62 -51
  50. package/dist/prod/core/scheduler.js +310 -162
  51. package/dist/prod/core/truth.js +45 -0
  52. package/dist/prod/core/verdict.js +87 -49
  53. package/dist/prod/deferred.js +182 -0
  54. package/dist/prod/index.js +7 -1
  55. package/dist/prod/map.js +360 -275
  56. package/dist/prod/reveal.js +76 -76
  57. package/dist/prod/signals.js +41 -30
  58. package/dist/prod/store/affects.js +6 -6
  59. package/dist/prod/store/edges.js +39 -0
  60. package/dist/prod/store/optimistic.js +37 -33
  61. package/dist/prod/store/projection.js +25 -19
  62. package/dist/prod/store/store.js +142 -96
  63. package/dist/types/affects-marks.d.ts +14 -0
  64. package/dist/types/boundaries.d.ts +1 -1
  65. package/dist/types/core/async.d.ts +10 -0
  66. package/dist/types/core/constants.d.ts +13 -1
  67. package/dist/types/core/core.d.ts +44 -2
  68. package/dist/types/core/dev.d.ts +43 -13
  69. package/dist/types/core/graph.d.ts +11 -0
  70. package/dist/types/core/identities.d.ts +17 -0
  71. package/dist/types/core/index.d.ts +2 -1
  72. package/dist/types/core/lanes.d.ts +2 -14
  73. package/dist/types/core/owner.d.ts +5 -3
  74. package/dist/types/core/scheduler.d.ts +47 -28
  75. package/dist/types/core/truth.d.ts +16 -0
  76. package/dist/types/core/types.d.ts +21 -0
  77. package/dist/types/core/verdict.d.ts +32 -0
  78. package/dist/types/deferred.d.ts +28 -0
  79. package/dist/types/index.d.ts +6 -0
  80. package/dist/types/map.d.ts +2 -2
  81. package/dist/types/signals.d.ts +28 -7
  82. package/dist/types/store/edges.d.ts +9 -0
  83. package/dist/types/store/index.d.ts +10 -3
  84. package/dist/types/store/optimistic.d.ts +3 -2
  85. package/dist/types/store/projection.d.ts +4 -3
  86. package/dist/types/store/store.d.ts +1 -1
  87. package/dist/types/store/target.d.ts +16 -8
  88. package/dist/types/store/types.d.ts +14 -0
  89. package/package.json +1 -1
@@ -1,8 +1,10 @@
1
- import { EFFECT_RENDER, EFFECT_USER, CONFIG_HELD, CONFIG_OVERRIDE, NOT_PENDING, STATUS_UNINITIALIZED, STATUS_PENDING, CONFIG_STAGED, REACTIVE_DISPOSED, REACTIVE_ZOMBIE, CONFIG_VERDICT, CONFIG_HAS_SNAPSHOT, REACTIVE_RECOMPUTING_DEPS, REACTIVE_MISSED_WAKE, CONFIG_IN_SNAPSHOT_SCOPE, REACTIVE_SNAPSHOT_STALE, CONFIG_HELD_FRAME, REACTIVE_LANE_DIRTY, CONFIG_INPUTS_PUBLISHED, EFFECT_TRACKED, REACTIVE_MANUAL_WRITE, CONFIG_GUESS, REACTIVE_FRAME_READ, CONFIG_REDERIVE, STATUS_ERROR } from "./constants.js";
1
+ import { EFFECT_RENDER, EFFECT_USER, CONFIG_HELD, CONFIG_OVERRIDE, NOT_PENDING, STATUS_UNINITIALIZED, STATUS_PENDING, CONFIG_STAGED, REACTIVE_DISPOSED, REACTIVE_ZOMBIE, CONFIG_VERDICT, CONFIG_HAS_SNAPSHOT, REACTIVE_RECOMPUTING_DEPS, REACTIVE_MISSED_WAKE, CONFIG_IN_SNAPSHOT_SCOPE, REACTIVE_SNAPSHOT_STALE, CONFIG_HELD_FRAME, REACTIVE_LANE_DIRTY, CONFIG_STAGED_ERROR, CONFIG_INPUTS_PUBLISHED, STATUS_ERROR, EFFECT_TRACKED, REACTIVE_MANUAL_WRITE, CONFIG_GUESS, REACTIVE_FRAME_READ, CONFIG_REDERIVE } from "./constants.js";
2
2
 
3
3
  import { attrHooks } from "./attribution-hooks.js";
4
4
 
5
- import { resyncUnflushedCompanions, recompute, markUnflushedStaged, ext } from "./core.js";
5
+ import { notifyStatus } from "./async.js";
6
+
7
+ import { resyncUnflushedCompanions, isSame, recompute, markUnflushedStaged, ext } from "./core.js";
6
8
 
7
9
  import { DEV, GRAPH_SIZE_WARN_AT, noteFanOut } from "./dev.js";
8
10
 
@@ -12,29 +14,136 @@ import { runHeap, enqueueSub, deleteFromHeap } from "./heap.js";
12
14
 
13
15
  import { devCheckQuiescent } from "./invariants.js";
14
16
 
17
+ // Optional-module hooks: module bindings, not `GlobalQueue` statics, so a
18
+ // bundle that never imports the installing module never assigns them — its
19
+ // minifier folds every guarded call site (and the branch behind it) away.
20
+ // Each module installs its own set at evaluation (pay-for-use).
21
+ // Lanes (lanes.ts; installed when `createOptimistic` — or verdict.ts — is
22
+ // imported; every call site is behind a bit or a `passLane` nothing else sets).
23
+ let laneReadHook = null;
24
+
25
+ let laneStageHook = null;
26
+
27
+ let laneOutcomeHook = null;
28
+
29
+ let laneWriteHook = null;
30
+
31
+ let applyGuessesHook = null;
32
+
33
+ let laneSeamsHook = null;
34
+
35
+ let laneCorrectionsHook = null;
36
+
37
+ let endLanesHook = null;
38
+
39
+ let lanesBlockedHook = null;
40
+
41
+ function installLaneHooks(e, n, o, t, l, s, u, i, r) {
42
+ laneReadHook = e;
43
+ laneStageHook = n;
44
+ laneOutcomeHook = o;
45
+ laneWriteHook = t;
46
+ applyGuessesHook = l;
47
+ laneSeamsHook = s;
48
+ laneCorrectionsHook = u;
49
+ endLanesHook = i;
50
+ lanesBlockedHook = r;
51
+ }
52
+
53
+ // Boundaries (boundaries.ts): the display consumers between an observer
54
+ // and the root. `catch` — status from a frame reader, nearest boundary
55
+ // first (true: caught, the root never hears of it; a clear — flags 0 —
56
+ // settles the reader there); `fresh` — a pass that read a hold (true: a
57
+ // first pass a loading boundary that has not shown content caught,
58
+ // `joinPass`; `held`: the flush's hold owns it, nothing catches it);
59
+ // `hidden` — a frame reader behind a fallback (the boundary showing it)
60
+ // is not on screen and holds nothing; `boundarySeam` — the seam's sweep (readers
61
+ // gone or settled without a pass reveal; an `on` re-arm resolves);
62
+ // `heldRun` — a queued run under a fallback-showing boundary waits for
63
+ // the reveal (true: held; the boundary re-queues it by type). The
64
+ // synchronous first render on creation builds the subtree, attached or
65
+ // not; its updates and the user effects wait.
66
+ let catchHook = null;
67
+
68
+ let freshHook = null;
69
+
70
+ let hiddenHook = null;
71
+
72
+ let boundarySeamHook = null;
73
+
74
+ let heldRunHook = null;
75
+
76
+ function installBoundaryHooks(e, n, o, t, l) {
77
+ catchHook = e;
78
+ freshHook = n;
79
+ hiddenHook = o;
80
+ boundarySeamHook = t;
81
+ heldRunHook = l;
82
+ }
83
+
84
+ /** Store (store/store.ts): `park` — the flush parked into `t`: the store
85
+ * materializes and holds the container node of every staging that had none
86
+ * (a staging needs the node as its home only when something can read the
87
+ * frame through it; a hold can); `commit` — fold the pending backings whose
88
+ * container nodes this flush committed (the owned-raw model's one mutation
89
+ * point). */ let storeParkHook = null;
90
+
91
+ let storeCommitHook = null;
92
+
93
+ function installStoreHooks(e, n) {
94
+ storeParkHook = e;
95
+ storeCommitHook = n;
96
+ }
97
+
98
+ /** `affects()` marks (affects.ts): the releases at a landing and at the seam
99
+ * (ambient marks). */ let releaseMarksHook = null;
100
+
101
+ let releaseAmbientMarksHook = null;
102
+
103
+ function installMarkHooks(e, n) {
104
+ releaseMarksHook = e;
105
+ releaseAmbientMarksHook = n;
106
+ }
107
+
108
+ /** Verdicts (verdict.ts). */ let observeFlightHook = null;
109
+
110
+ function installVerdictHooks(e) {
111
+ observeFlightHook = e;
112
+ }
113
+
114
+ /** External-source bridge (wired by enableExternalSource(); undefined while
115
+ * no config is active — including after _resetExternalSourceConfig()). */ let wireExternalSourceHook = undefined;
116
+
117
+ let externalUntrackHook = undefined;
118
+
119
+ function setExternalHooks(e, n) {
120
+ wireExternalSourceHook = e;
121
+ externalUntrackHook = n;
122
+ }
123
+
15
124
  /** Live transactions — opened, unmerged, not landed. Scanned at every seam
16
125
  * while non-empty; nothing on the plain path. */ const transactions = [];
17
126
 
18
127
  /** Observe tier: this flush parked its transaction (`holdStart` fired). */ let holding = false;
19
128
 
20
129
  /** A transaction (listed here) or a lane (lanes.ts lists its own). */ function newTransaction(e, n = null) {
21
- const t = {
22
- Je: [],
23
- En: [ [], [] ],
24
- an: [],
25
- Sn: null,
130
+ const o = {
131
+ je: [],
132
+ un: [ [], [] ],
133
+ En: [],
134
+ cn: null,
26
135
  _parent: n,
27
- B: e,
28
- rt: null,
136
+ V: e,
137
+ it: null,
29
138
  tt: 0,
30
139
  nt: false,
31
- un: null,
32
- Tt: false,
33
- fn: false,
34
- T: null
140
+ nn: null,
141
+ It: false,
142
+ ln: false,
143
+ I: null
35
144
  };
36
- if (!e) transactions.push(t);
37
- return t;
145
+ if (!e) transactions.push(o);
146
+ return o;
38
147
  }
39
148
 
40
149
  // Lanes (plan sec. 28, 2026-10-02; lanes.ts). A lane is "a new base of a transition":
@@ -78,14 +187,14 @@ function setPassLane(e) {
78
187
  * set it. */ let passTx = null;
79
188
 
80
189
  function joinPassTx(e, n) {
81
- if (globalQueue.X && !n || flushTransaction !== null) return joinFuture(e);
190
+ if (globalQueue.q && !n || flushTransaction !== null) return joinFuture(e);
82
191
  if (passTx === null) passTx = resolveTx(e); else merge(resolveTx(e), passTx);
83
192
  schedule();
84
193
  }
85
194
 
86
195
  /** The transaction holding a node (CONFIG_HELD set), resolved through
87
196
  * merges; the path is compressed. */ function txOf(e) {
88
- return e.m._t = resolveTx(e.m._t);
197
+ return e.T.Je = resolveTx(e.T.Je);
89
198
  }
90
199
 
91
200
  /** `t` resolved through merges while it is still parked or open; null once
@@ -95,7 +204,7 @@ function joinPassTx(e, n) {
95
204
  }
96
205
 
97
206
  function resolveTx(e) {
98
- while (e.Sn !== null) e = e.Sn;
207
+ while (e.cn !== null) e = e.cn;
99
208
  return e;
100
209
  }
101
210
 
@@ -106,7 +215,7 @@ function resolveTx(e) {
106
215
  if (n === null) {
107
216
  flushTransaction = e === null ? newTransaction(false) : resolveTx(e);
108
217
  } else if (e !== null) merge(resolveTx(e), n);
109
- if (!globalQueue.X) schedule();
218
+ if (!globalQueue.q) schedule();
110
219
  }
111
220
 
112
221
  /** `t` merges into `f`: the work that touched both entangles them (A15).
@@ -116,16 +225,16 @@ function resolveTx(e) {
116
225
  // into the other would close a cycle `resolveTx` never leaves.
117
226
  e = resolveTx(e);
118
227
  n = resolveTx(n);
119
- if (e === n || e.B || n.B) return;
228
+ if (e === n || e.V || n.V) return;
120
229
  if (attrHooks !== null) attrHooks.transitionMerged(n, e);
121
- e.Sn = n;
230
+ e.cn = n;
122
231
  n.tt += e.tt;
123
232
  n.nt ||= e.nt;
124
- append(n.Je, e.Je);
125
- append(n.En[0], e.En[0]);
126
- append(n.En[1], e.En[1]);
127
- append(n.an, e.an);
128
- if (e.T !== null) append(n.T ??= [], e.T);
233
+ append(n.je, e.je);
234
+ append(n.un[0], e.un[0]);
235
+ append(n.un[1], e.un[1]);
236
+ append(n.En, e.En);
237
+ if (e.I !== null) append(n.I ??= [], e.I);
129
238
  transactions.splice(transactions.indexOf(e), 1);
130
239
  }
131
240
 
@@ -151,9 +260,9 @@ function resolveTx(e) {
151
260
  judge ??= e;
152
261
  // An action still running in it holds it open (action.ts). Its lanes
153
262
  // (lanes.ts): a lane under `t` blocks it while blocked itself.
154
- const t = e.tt !== 0 || blockedBy(e.Je, e) || !!GlobalQueue.dn && GlobalQueue.dn(e);
263
+ const o = e.tt !== 0 || blockedBy(e.je, e) || !!lanesBlockedHook?.(e);
155
264
  judge = n;
156
- return t;
265
+ return o;
157
266
  }
158
267
 
159
268
  let judge = null;
@@ -162,9 +271,9 @@ let judge = null;
162
271
  * frame reader observes (`blockedBy`'s predicate, collected; the readers
163
272
  * themselves are not sources). */ function blockersOf(e) {
164
273
  const n = [];
165
- for (let t = 0; t < e.Je.length; t++) {
166
- const l = e.Je[t];
167
- if (!l.u && l.S & STATUS_PENDING && !(l.R & REACTIVE_DISPOSED) && (l.m._t === null || txOf(l) === e) && blockedBy([ l ], e)) n.push(l);
274
+ for (let o = 0; o < e.je.length; o++) {
275
+ const t = e.je[o];
276
+ if (!t.i && t.m & STATUS_PENDING && !(t.R & REACTIVE_DISPOSED) && (t.T.Je === null || txOf(t) === e) && blockedBy([ t ], e)) n.push(t);
168
277
  }
169
278
  return n;
170
279
  }
@@ -174,33 +283,33 @@ let judge = null;
174
283
  * not (lanes.ts, the body-end corollary). A pending reader counts only if
175
284
  * one of the sources it waits on is `t`'s (a render effect marked pending
176
285
  * by a lane flight, never re-run, is the lane's wait, not the frame's). */ function ownFlights(e) {
177
- return blockedBy(e.Je, e, true);
286
+ return blockedBy(e.je, e, true);
178
287
  }
179
288
 
180
289
  /** A source the pending node waits on that is `t`'s (held by it, or by no
181
290
  * one) — not another transaction's or lane's work. Itself, when it is the
182
291
  * source. */ function ownSource(e, n) {
183
- const t = e.m?.Se;
184
- if (t === undefined) return true;
185
- for (const e of t) {
186
- const t = e.m?._t;
187
- if (t == null || resolveTx(t) === n) return true;
292
+ const o = e.T?.fe;
293
+ if (o === undefined) return true;
294
+ for (const e of o) {
295
+ const o = e.T?.Je;
296
+ if (o == null || resolveTx(o) === n) return true;
188
297
  }
189
298
  return false;
190
299
  }
191
300
 
192
- function blockedBy(e, n, t = false) {
193
- for (let l = 0; l < e.length; l++) {
194
- const o = e[l];
195
- if (!(o.S & STATUS_PENDING) || o.R & REACTIVE_DISPOSED || o.i & CONFIG_GUESS || o.m._t !== null && txOf(o) !== n || t && !ownSource(o, n)) continue;
301
+ function blockedBy(e, n, o = false) {
302
+ for (let t = 0; t < e.length; t++) {
303
+ const l = e[t];
304
+ if (!(l.m & STATUS_PENDING) || l.R & REACTIVE_DISPOSED || l.l & CONFIG_GUESS || l.T.Je !== null && txOf(l) !== n || o && !ownSource(l, n)) continue;
196
305
  // The frame's own pending observer (off screen: this one holds nothing;
197
306
  // the next listed node may).
198
- if (o.u === EFFECT_RENDER) {
199
- if (onScreen(o, judge ?? n)) return true;
307
+ if (l.i === EFFECT_RENDER) {
308
+ if (onScreen(l, judge ?? n)) return true;
200
309
  continue;
201
310
  }
202
- for (let e = o.t; e !== null; e = e.o) {
203
- const t = e.l;
311
+ for (let e = l.o; e !== null; e = e.t) {
312
+ const o = e.u;
204
313
  // A frame reader: a render effect, or a stale reader of the flight
205
314
  // (REACTIVE_FRAME_READ — a verdict reader, `observeFlight`; lane work,
206
315
  // `frameRead`): served committed instead of going pending, it derives
@@ -212,7 +321,7 @@ function blockedBy(e, n, t = false) {
212
321
  // lane-membership ruling, 2026-10-05). An output that never committed
213
322
  // shows nothing — a mount the frame has not revealed — and holds
214
323
  // nothing.
215
- if ((t.u === EFFECT_RENDER && t.S & STATUS_PENDING || t.R & REACTIVE_FRAME_READ || t.i & CONFIG_REDERIVE && t.S === STATUS_PENDING) && (e.Pe === t.pe || t.m?.F != null) && !(t.R & REACTIVE_DISPOSED) && onScreen(t, judge ?? n)) return true;
324
+ if ((o.i === EFFECT_RENDER && o.m & STATUS_PENDING || o.R & REACTIVE_FRAME_READ || o.l & CONFIG_REDERIVE && o.m === STATUS_PENDING) && (e.Te === o.Ne || o.T?.F != null) && !(o.R & REACTIVE_DISPOSED) && onScreen(o, judge ?? n)) return true;
216
325
  }
217
326
  }
218
327
  return false;
@@ -226,7 +335,7 @@ function blockedBy(e, n, t = false) {
226
335
  * makes its say moot), and not behind a fallback (A33: a boundary showing its fallback is the display of
227
336
  * everything under it, so a reader there is not on screen and holds
228
337
  * nothing — boundaries.ts). */ function onScreen(e, n) {
229
- return !(e.R & REACTIVE_ZOMBIE && removalStagedBy(e, n)) && !(GlobalQueue.se && GlobalQueue.se(e));
338
+ return !(e.R & REACTIVE_ZOMBIE && removalStagedBy(e, n)) && !hiddenHook?.(e);
230
339
  }
231
340
 
232
341
  /** A15 (#3463): a reader whose removal is staged — a zombie, parked by a
@@ -235,9 +344,9 @@ function blockedBy(e, n, t = false) {
235
344
  * (done, and the commit disposes it; not done, and it stays parked). The
236
345
  * staging transaction is the one holding the pass that parked the frame:
237
346
  * the nearest non-zombie ancestor. */ function removalStagedBy(e, n) {
238
- let t = e;
239
- while (t !== null && t.R & REACTIVE_ZOMBIE) t = t._parent;
240
- return t !== null && (t.i & CONFIG_HELD) !== 0 && t.m?._t != null && txOf(t) === resolveTx(n);
347
+ let o = e;
348
+ while (o?.R & REACTIVE_ZOMBIE) o = o._parent;
349
+ return o?.l & CONFIG_HELD && o.T?.Je != null && txOf(o) === resolveTx(n);
241
350
  }
242
351
 
243
352
  /** Unchanged passes this flush whose stale dependency tail awaits the
@@ -264,17 +373,17 @@ function deferZombie(e) {
264
373
 
265
374
  /** Put a staged node in a transaction: flagged, stamped, on its landing
266
375
  * list. */ function holdNode(e, n) {
267
- e.i |= CONFIG_HELD;
376
+ e.l |= CONFIG_HELD;
268
377
  list(e, n);
269
378
  }
270
379
 
271
380
  /** Put a node on a transaction's list, once: a node's `_transaction` is the
272
381
  * transaction whose `_nodes` it is on (every site that sets one does the
273
382
  * other), so a re-pass, a re-landing or a re-staging adds nothing. */ function list(e, n) {
274
- const t = ext(e);
275
- if (t._t === n) return;
276
- t._t = n;
277
- n.Je.push(e);
383
+ const o = ext(e);
384
+ if (o.Je === n) return;
385
+ o.Je = n;
386
+ n.je.push(e);
278
387
  }
279
388
 
280
389
  /** Hold the (uncommitted) frame under a held pass: every computed in the
@@ -290,21 +399,34 @@ function deferZombie(e) {
290
399
  * next read of it trips over (`laneRead` → `txOf`). Its frame is the lane's
291
400
  * too (ruling A: a lane pass's children are the lane's), revealed and
292
401
  * retired at the lane's seam. */ function holdFrame(e, n) {
293
- for (let t = e.nn; t !== null; t = t.tn) {
294
- if (t.m?._t?.B) continue;
295
- if (t.ee !== undefined) {
296
- if (!(t.i & CONFIG_HELD)) holdNode(t, n);
297
- t.i |= CONFIG_HELD_FRAME;
402
+ for (let o = e.ze; o !== null; o = o.Xe) {
403
+ if (o.T?.Je?.V) continue;
404
+ if (o.X !== undefined) {
405
+ if (!(o.l & CONFIG_HELD)) holdNode(o, n);
406
+ o.l |= CONFIG_HELD_FRAME;
298
407
  }
299
- holdFrame(t, n);
408
+ holdFrame(o, n);
409
+ }
410
+ }
411
+
412
+ /** The nodes under `owner` a transaction other than `t` holds (boundaries.ts:
413
+ * what an earlier hold staged under a re-armed boundary). */ function heldUnder(e, n, o) {
414
+ for (let t = e.ze; t !== null; t = t.Xe) {
415
+ if ((t.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && txOf(t) !== n) o(t);
416
+ heldUnder(t, n, o);
300
417
  }
301
418
  }
302
419
 
420
+ /** `n` leaves the hold it was staged in: its next pass publishes mainline. */ function unhold(e) {
421
+ e.T.Je = null;
422
+ e.l &= ~CONFIG_HELD;
423
+ }
424
+
303
425
  const dirtyQueue = {
304
- jt: new Array(2e3).fill(undefined),
305
- N: false,
306
- ut: 0,
307
- Kt: 0
426
+ gt: new Array(2e3).fill(undefined),
427
+ p: false,
428
+ st: 0,
429
+ jt: 0
308
430
  };
309
431
 
310
432
  let clock = 0;
@@ -367,7 +489,7 @@ function schedule() {
367
489
  }
368
490
  if (scheduled) return;
369
491
  scheduled = true;
370
- if (!syncDepth && !globalQueue.X) {
492
+ if (!syncDepth && !globalQueue.q) {
371
493
  queueMicrotask(flush);
372
494
  }
373
495
  }
@@ -398,9 +520,9 @@ function haltReactivity(e) {
398
520
  // nothing an app or its telemetry can act on (#3338 — an uncaught throw
399
521
  // during the hydration render). The rethrow may reach the top as well in
400
522
  // the non-swallowed cases; a duplicate report beats a silent one.
401
- const t = e !== undefined && globalThis.reportError;
402
- t || e === undefined ? console.error(n) : console.error(n, e);
403
- t && t(e);
523
+ const o = e !== undefined && globalThis.reportError;
524
+ o || e === undefined ? console.error(n) : console.error(n, e);
525
+ o && o(e);
404
526
  }
405
527
 
406
528
  // Logs on the first write after a halt so a frozen interaction is traceable.
@@ -416,11 +538,11 @@ function notifyHalted() {
416
538
  }
417
539
 
418
540
  class GlobalQueue {
419
- En=[ [], [] ];
420
- X=false;
541
+ un=[ [], [] ];
542
+ q=false;
421
543
  flush() {
422
- if (this.X) return;
423
- this.X = true;
544
+ if (this.q) return;
545
+ this.q = true;
424
546
  // A28: companions of nodes written since the last flush mirror the
425
547
  // flushed world — re-synced inside the running window (the write is
426
548
  // "flushed" from here on).
@@ -433,12 +555,12 @@ class GlobalQueue {
433
555
  // recomputed; late subscribers (an effect reading a swept memo this
434
556
  // flush) revive it, which is the pay-for-use contract.
435
557
  sweepDormant();
436
- runHeap(dirtyQueue, GlobalQueue.et);
558
+ runHeap(dirtyQueue, GlobalQueue.Ze);
437
559
  this.settle();
438
560
  clock++;
439
561
  // A write the commit sweep staged with no subscriber to dirty is work
440
562
  // too — the next round commits it.
441
- scheduled = dirtyQueue.Kt >= dirtyQueue.ut || pendingNodes.length !== 0;
563
+ scheduled = dirtyQueue.jt >= dirtyQueue.st || pendingNodes.length !== 0;
442
564
  this.run(EFFECT_RENDER);
443
565
  this.run(EFFECT_USER);
444
566
  if (true && holding) {
@@ -448,7 +570,7 @@ class GlobalQueue {
448
570
  if (false && !scheduled) ;
449
571
  if (false) ;
450
572
  } finally {
451
- this.X = false;
573
+ this.q = false;
452
574
  passTx = null;
453
575
  }
454
576
  }
@@ -461,7 +583,7 @@ class GlobalQueue {
461
583
  // Lanes: an ended action body judges its guesses now that their passes
462
584
  // have run (lanes.ts); a correction's re-derivations run in one more
463
585
  // pure round — the parent's flights before the parent is judged below.
464
- if (GlobalQueue.On?.()) runHeap(dirtyQueue, GlobalQueue.et);
586
+ if (laneCorrectionsHook?.()) runHeap(dirtyQueue, GlobalQueue.Ze);
465
587
  const e = flushTransaction;
466
588
  flushTransaction = null;
467
589
  // The frame's verdict is in: the guesses written since the last seam
@@ -469,21 +591,21 @@ class GlobalQueue {
469
591
  // parents a nested lane to it), or are dropped — the frame commits, and
470
592
  // there is nothing to be optimistic over. Their passes run next round;
471
593
  // a parent landing at this very seam ends the lane before they do.
472
- GlobalQueue.Gn?.(e);
594
+ applyGuessesHook?.(e);
473
595
  // A lane's own flush (its flight landing, its reveal) parks nothing: the
474
596
  // lane's work reached it per pass; the frame's plain writes commit.
475
597
  // (Resolved: a guess over another transaction's guess merged them.)
476
- const n = e !== null && !e.B ? resolveTx(e) : null;
598
+ const n = e !== null && !e.V ? resolveTx(e) : null;
477
599
  if (n !== null) {
478
600
  // `t._nodes` grows under the walk (holdFrame pushes); the bound is
479
601
  // this flush's list, which does not.
480
602
  const e = pendingNodes.length;
481
- for (let t = 0; t < e; t++) {
482
- const e = pendingNodes[t];
603
+ for (let o = 0; o < e; o++) {
604
+ const e = pendingNodes[o];
483
605
  // Already held: the pass that re-staged it joined its transaction,
484
606
  // which is `t` (or merged into it). Lane work is the lane's (a
485
607
  // pending mark propagated onto it queued it here too).
486
- if (!(e.i & (CONFIG_HELD | CONFIG_OVERRIDE)) && (e.m === null || e.m._t === null || !e.m._t.B)) {
608
+ if (!(e.l & (CONFIG_HELD | CONFIG_OVERRIDE)) && (e.T === null || e.T.Je === null || !e.T.Je.V)) {
487
609
  // A loading source — pending with nothing staged and no committed
488
610
  // value (A16, A19 exc. 1: uninitialized is loading, not pending)
489
611
  // that is not an observer — is nobody's frame: not held. Its
@@ -492,15 +614,19 @@ class GlobalQueue {
492
614
  // stale stamp was the bridge that entangled unrelated updates
493
615
  // with a never-resolving flight). Its observers are held and
494
616
  // wait on its flight (`blocked`).
495
- if (e.Oe === NOT_PENDING && e.S & STATUS_UNINITIALIZED && e.u !== EFFECT_RENDER) continue;
617
+ if (e.ue === NOT_PENDING && e.m & STATUS_UNINITIALIZED && e.i !== EFFECT_RENDER) continue;
496
618
  // A34 (2): a tick whose writes net to the committed value made no
497
619
  // proposal (`setShow(false); setShow(true)` on a committed true) —
498
620
  // not staged, not held, pends nothing; a later write to it is
499
621
  // plain mainline. (A node already held stays held when written
500
622
  // back: A34 (1).)
501
- if (e.Oe !== NOT_PENDING && !(e.S & (STATUS_PENDING | STATUS_UNINITIALIZED)) && e.en && e.en(e.Ae, e.Oe) && e.m?.St == null && e.m?.ct == null) {
502
- e.Oe = NOT_PENDING;
503
- e.i &= ~CONFIG_STAGED;
623
+ if (e.ue !== NOT_PENDING && !(e.m & (STATUS_PENDING | STATUS_UNINITIALIZED)) && e.T?.Nt == null && e.T?.ft == null &&
624
+ // The comparator last: a pass that created children (an object
625
+ // owning a fresh async memo, #4111) must not have it read them.
626
+ // A NotReady read there is a change (`isSame`).
627
+ isSame(e, e.Ie, e.ue)) {
628
+ e.ue = NOT_PENDING;
629
+ e.l &= ~CONFIG_STAGED;
504
630
  continue;
505
631
  }
506
632
  holdNode(e, n);
@@ -508,10 +634,10 @@ class GlobalQueue {
508
634
  // A held pass's frame is held with it (ruling A, O2): the children it
509
635
  // created are the transaction's — they compute, and a pass over them
510
636
  // or a write that reaches them joins; they effect at the landing.
511
- if (e.i & CONFIG_STAGED) holdFrame(e, n);
637
+ if (e.l & CONFIG_STAGED) holdFrame(e, n);
512
638
  }
513
639
  pendingNodes.length = 0;
514
- GlobalQueue.An?.(n);
640
+ storeParkHook?.(n);
515
641
  // (This flush's runs are stashed with `t` below — after the landings,
516
642
  // so a `t` that lands at this very seam runs them first, ahead of
517
643
  // the runs it held from earlier flushes.)
@@ -521,8 +647,12 @@ class GlobalQueue {
521
647
  // through like the same read outside): it re-runs now, as the
522
648
  // holder's verdict lane's work — before the lane seams, which reveal
523
649
  // it (nothing commits this seam that could dispose it).
524
- const t = deferredZombies.splice(0).sort((e, n) => e.it - n.it);
525
- for (let e = 0; e < t.length; e++) if ((t[e].R & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE)) === REACTIVE_ZOMBIE && t[e].i & CONFIG_VERDICT) recompute(t[e]);
650
+ // (Verdict readers exist only with the verdict engine installed.)
651
+ const o = deferredZombies.splice(0);
652
+ if (observeFlightHook) {
653
+ o.sort((e, n) => e.Et - n.Et);
654
+ for (let e = 0; e < o.length; e++) if ((o[e].R & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE)) === REACTIVE_ZOMBIE && o[e].l & CONFIG_VERDICT) recompute(o[e]);
655
+ }
526
656
  // The unchanged passes' tails stay linked (A30, #3469): their inputs
527
657
  // are held, and the committed frame still derives from them — no trim.
528
658
  } else {
@@ -534,7 +664,7 @@ class GlobalQueue {
534
664
  // `recompute`'s own gates.
535
665
  for (let e = 0; e < heldTrims.length; e++) {
536
666
  const n = heldTrims[e];
537
- if (n.m?.F == null && !n.lt) trimStaleDeps(n);
667
+ if (n.T?.F == null && !n.Qe) trimStaleDeps(n);
538
668
  }
539
669
  }
540
670
  // The list is the flush's either way. Reset only when there is something
@@ -548,19 +678,21 @@ class GlobalQueue {
548
678
  // removes its entry.
549
679
  // This flush's own runs, the lanes' reveals, and the landings' held runs
550
680
  // are collected apart and ordered below.
551
- const t = this.En;
552
- const l = this.En = [ [], [] ];
681
+ const o = this.un;
682
+ const t = this.un = [ [], [] ];
553
683
  // The passes that read this frame's stagings as the screen read held
554
684
  // writes if it parked: the lane seam re-derives them on the committed
555
685
  // world (a lane's runs wait this round).
556
- GlobalQueue.cn?.(n !== null ? stagedReaders : null);
557
- if (stagedReaders.length) stagedReaders.length = 0;
558
- this.En = [ [], [] ];
686
+ if (laneSeamsHook) {
687
+ laneSeamsHook(n !== null ? stagedReaders : null);
688
+ if (stagedReaders.length) stagedReaders.length = 0;
689
+ }
690
+ this.un = [ [], [] ];
559
691
  for (let e = transactions.length - 1; e >= 0; e--) {
560
692
  const n = transactions[e];
561
693
  if (blocked(n)) continue;
562
694
  transactions.splice(e, 1);
563
- GlobalQueue.Tn?.(n);
695
+ endLanesHook?.(n);
564
696
  land(n);
565
697
  // A landing's commits can dispose a zombie a transaction judged above
566
698
  // was blocked on (#3463: live "until the commit that disposes it") —
@@ -569,13 +701,13 @@ class GlobalQueue {
569
701
  }
570
702
  // The store folds the pending backings whose container nodes committed
571
703
  // — this flush's, or a landing's (store/store.ts installs it).
572
- GlobalQueue.Rn?.();
704
+ storeCommitHook?.();
573
705
  // Marks declared outside a transaction: the flush that carried them
574
706
  // parked (something async below) — the window is the frame's, the marks
575
707
  // are its transaction's; else they release at the seam, verdict-only,
576
708
  // nothing to show (affects.ts).
577
- const o = n && liveTx(n);
578
- GlobalQueue.A?.(o);
709
+ const l = n && liveTx(n);
710
+ releaseAmbientMarksHook?.(l);
579
711
  // The effect phase: lane work first (displayed ahead of the frame), then
580
712
  // this flush's runs, then the runs the landings held from earlier
581
713
  // flushes — as one pass would have queued them (#3540: a shell
@@ -583,48 +715,48 @@ class GlobalQueue {
583
715
  // write; #3528: a display-ahead swap before the count it is shown
584
716
  // beside). A parked frame's runs wait with its transaction instead: the
585
717
  // effect phase applies a committed frame.
586
- const u = o !== null;
718
+ const s = l !== null;
587
719
  // Attribution hook: this flush found its transaction incomplete — its
588
720
  // writes stay staged, its runs are stashed below. Before the effect
589
721
  // phase (the lanes' display-ahead runs are the visible acknowledgers);
590
722
  // `holdEnd` fires after it (`flush`).
591
- if (u && attrHooks !== null) {
592
- attrHooks.holdStart(o);
723
+ if (s && attrHooks !== null) {
724
+ attrHooks.holdStart(l);
593
725
  holding = true;
594
726
  }
595
727
  for (let e = 0; e < 2; e++) {
596
- if (u) append(o.En[e], t[e]);
728
+ if (s) append(l.un[e], o[e]);
597
729
  // The plain flush — no reveal, no landing, not parked — has nothing to
598
730
  // order around its own runs: they are the queue as they stand (the
599
731
  // same array, not a copy; `run` takes it whole). Every other seam
600
732
  // builds the ordered queue above.
601
- this.En[e] = u || l[e].length || this.En[e].length ? l[e].concat(u ? [] : t[e], this.En[e]) : t[e];
733
+ this.un[e] = s || t[e].length || this.un[e].length ? t[e].concat(s ? [] : o[e], this.un[e]) : o[e];
602
734
  }
603
735
  if (deferredZombies.length !== 0) {
604
736
  // Survivors are the displayed frame of a held pass: they rerun for the
605
737
  // live write, parents before children.
606
- const e = deferredZombies.splice(0).sort((e, n) => e.it - n.it);
738
+ const e = deferredZombies.splice(0).sort((e, n) => e.Et - n.Et);
607
739
  for (let n = 0; n < e.length; n++) {
608
740
  if (!(e[n].R & REACTIVE_DISPOSED)) recompute(e[n]);
609
741
  }
610
742
  }
611
743
  // Boundaries: readers that settled, landed or died this flush are
612
744
  // dropped; a fallback with none left reveals next round.
613
- GlobalQueue.ce?.();
745
+ boundarySeamHook?.();
614
746
  }
615
747
  run(e) {
616
- const n = this.En[e - 1];
748
+ const n = this.un[e - 1];
617
749
  if (n.length) {
618
- this.En[e - 1] = [];
750
+ this.un[e - 1] = [];
619
751
  runQueue(n, e);
620
752
  }
621
753
  }
622
- enqueue(e, n, t = passLane) {
754
+ enqueue(e, n, o = passLane) {
623
755
  // Lane work's runs are the lane's: they run at its reveal, not with
624
756
  // the frame (which may park). A lane pass that read the frame's own
625
757
  // staging is the frame's (`recompute` passes null): its run waits with
626
758
  // the frame.
627
- if (e) (t !== null ? t : this).En[e - 1].push(n);
759
+ if (e) (o !== null ? o : this).un[e - 1].push(n);
628
760
  schedule();
629
761
  }
630
762
  /** Status reaching the root: pending is absorbed (the root mount defers —
@@ -640,10 +772,10 @@ class GlobalQueue {
640
772
  *
641
773
  * A boundary between the observer and the root (boundaries.ts) is asked
642
774
  * first: a fallback catches what is not ready under it, and the root
643
- * never hears of it. */ notify(e, n, t, l) {
644
- if (GlobalQueue.ie && GlobalQueue.ie(e, t & n, l)) return true;
775
+ * never hears of it. */ notify(e, n, o, t) {
776
+ if (catchHook?.(e, o & n, t)) return true;
645
777
  if (n & STATUS_PENDING) {
646
- if (t & STATUS_PENDING) {
778
+ if (o & STATUS_PENDING) {
647
779
  // A pass that went pending holds its frame: the async's own
648
780
  // synchronous frame is not ready (A15 reveal corollary: a reveal
649
781
  // that discovers a flight whose inputs are visible holds and joins
@@ -675,23 +807,23 @@ class GlobalQueue {
675
807
  * for it is void (#3322: an effect has one value slot, and the stale pass
676
808
  * overwrote the value that run was for) — the re-derivation's run replaces
677
809
  * it. */ function reruns(e) {
678
- for (let n = 0; n < e.an.length; n++) {
679
- const t = e.an[n];
810
+ for (let n = 0; n < e.En.length; n++) {
811
+ const o = e.En[n];
680
812
  // An errored reader's display is its error (D-39): the landing gives it
681
813
  // nothing to re-derive, and a re-run would be a read that retries the
682
814
  // errored source (#3945).
683
- if (t.R & REACTIVE_DISPOSED || t.S & STATUS_ERROR) continue;
684
- if (t.R & REACTIVE_FRAME_READ || t.i & CONFIG_VERDICT) {
685
- t.R &= ~REACTIVE_FRAME_READ;
686
- t.lt = false;
815
+ if (o.R & REACTIVE_DISPOSED || o.m & STATUS_ERROR) continue;
816
+ if (o.R & REACTIVE_FRAME_READ || o.l & CONFIG_VERDICT) {
817
+ o.R &= ~REACTIVE_FRAME_READ;
818
+ o.Qe = false;
687
819
  // Its frame is replaced by the re-derivation: a run one of its
688
820
  // children queued this flush (re-run by the same landing) is for the
689
821
  // frame being replaced — void too (#3404).
690
- for (let e = t.nn; e !== null; e = e.tn) if (e.u) e.lt = false;
691
- enqueueSub(t);
822
+ for (let e = o.ze; e !== null; e = e.Xe) if (e.i) e.Qe = false;
823
+ enqueueSub(o);
692
824
  }
693
825
  }
694
- e.an.length = 0;
826
+ e.En.length = 0;
695
827
  }
696
828
 
697
829
  /** The landing: the held frame becomes the frame. */ function land(e) {
@@ -699,16 +831,20 @@ class GlobalQueue {
699
831
  // (`_nodes` still lists them).
700
832
  if (attrHooks !== null) attrHooks.transitionSettled(e);
701
833
  reruns(e);
702
- if (e.T !== null) GlobalQueue.k(e.T);
834
+ if (e.I !== null) releaseMarksHook(e.I);
703
835
  // Old children die in the commits (cleanups first), then the stashed
704
836
  // effects run ahead of this flush's own. A node a lane took over since
705
837
  // (a guess written over the staged truth) is the lane's to land.
706
- for (let n = 0; n < e.Je.length; n++) {
707
- const t = e.Je[n];
708
- if (t.m._t === null || txOf(t) !== e) continue;
709
- t.m._t = null;
710
- commitPendingNode(t);
838
+ for (let n = 0; n < e.je.length; n++) {
839
+ const o = e.je[n];
840
+ if (o.T.Je === null || txOf(o) !== e) continue;
841
+ o.T.Je = null;
842
+ commitPendingNode(o);
711
843
  }
844
+ // A cleanup those commits ran that wrote a node `u` still held joined
845
+ // `u`, which has left `transactions`: the write is this landing's, and
846
+ // the next flush must not park in it (#4089).
847
+ if (flushTransaction === e) flushTransaction = null;
712
848
  releaseQueues(e);
713
849
  }
714
850
 
@@ -717,13 +853,13 @@ class GlobalQueue {
717
853
  * pass would have queued them — a shell re-derived at the landing before a
718
854
  * boundary swap held since the write (#3540's log order). */ function releaseQueues(e) {
719
855
  for (let n = 0; n < 2; n++) {
720
- append(globalQueue.En[n], e.En[n]);
721
- e.En[n] = [];
856
+ append(globalQueue.un[n], e.un[n]);
857
+ e.un[n] = [];
722
858
  }
723
859
  }
724
860
 
725
861
  /** `a.push(...b)` without the argument-count limit. */ function append(e, n) {
726
- for (let t = 0; t < n.length; t++) e.push(n[t]);
862
+ for (let o = 0; o < n.length; o++) e.push(n[o]);
727
863
  }
728
864
 
729
865
  /** Nodes staged this flush (`_pendingValue` set), committed at its end. */ const pendingNodes = [];
@@ -738,13 +874,13 @@ class GlobalQueue {
738
874
  * after `t`'s landing (`_reruns`). Once per pass. */ function staleReader(e, n) {
739
875
  if (!(e.R & REACTIVE_FRAME_READ)) {
740
876
  e.R |= REACTIVE_FRAME_READ;
741
- n.an.push(e);
877
+ n.En.push(e);
742
878
  }
743
879
  }
744
880
 
745
881
  function queuePendingNode(e) {
746
882
  pendingNodes.push(e);
747
- if (!globalQueue.X) markUnflushedStaged();
883
+ if (!globalQueue.q) markUnflushedStaged();
748
884
  // A28
749
885
  }
750
886
 
@@ -760,18 +896,18 @@ function bumpNotifyEpoch() {
760
896
  function insertSubs(e) {
761
897
  // §12d: stamp before walking — setSignal's staged-rewrite fast path skips
762
898
  // the next walk for this node while the epoch holds (marking is idempotent).
763
- e.Pt = notifyEpoch;
899
+ e.Ot = notifyEpoch;
764
900
  // Presence bits gate the optional-slot probes (see constants.ts): one
765
901
  // masked read of the always-present _config instead of missing-property
766
902
  // lookups in the hottest notify loop.
767
- const n = e.i;
768
- const t = (n & CONFIG_HAS_SNAPSHOT) !== 0 && e.m?.ot !== undefined;
903
+ const n = e.l;
904
+ const o = (n & CONFIG_HAS_SNAPSHOT) !== 0 && e.T?.lt !== undefined;
769
905
  // Observe-tier fan-out: this walk visits every subscriber edge anyway, so
770
906
  // the graph-size count is one local increment here and no field anywhere.
771
- let l = 0;
772
- for (let n = e.t; n !== null; n = n.o) {
773
- const e = n.l;
774
- l++;
907
+ let t = 0;
908
+ for (let n = e.o; n !== null; n = n.t) {
909
+ const e = n.u;
910
+ t++;
775
911
  // Missed-wake latch (#3037): this write is landing while the subscriber
776
912
  // is mid-recompute (a nested pull committing beneath its reads), and the
777
913
  // heap refuses RECOMPUTING nodes. A gen-current link means the pass
@@ -780,14 +916,14 @@ function insertSubs(e) {
780
916
  // pass either re-reads them fresh or trims them), and neither does the
781
917
  // tail link: it is the read IN FLIGHT — read() links before it pulls, so
782
918
  // this very commit is what that read returns.
783
- if (e.R & REACTIVE_RECOMPUTING_DEPS && n.Pe === e.pe && n !== e.p) e.R |= REACTIVE_MISSED_WAKE;
784
- if (t && e.i & CONFIG_IN_SNAPSHOT_SCOPE) {
919
+ if (e.R & REACTIVE_RECOMPUTING_DEPS && n.Te === e.Ne && n !== e._) e.R |= REACTIVE_MISSED_WAKE;
920
+ if (o && e.l & CONFIG_IN_SNAPSHOT_SCOPE) {
785
921
  e.R |= REACTIVE_SNAPSHOT_STALE;
786
922
  continue;
787
923
  }
788
924
  enqueueSub(e);
789
925
  }
790
- if (l >= GRAPH_SIZE_WARN_AT) noteFanOut(e, l);
926
+ if (t >= GRAPH_SIZE_WARN_AT) noteFanOut(e, t);
791
927
  }
792
928
 
793
929
  /** Lane work re-staged (lanes.ts; `recompute`): the lane's members among
@@ -798,14 +934,14 @@ function insertSubs(e) {
798
934
  * is a live write if the effect becomes a zombie later this flush — an
799
935
  * on-screen reader whose removal an adopted write stages follows the lane
800
936
  * (the lane-membership ruling, 2026-10-05; `_update`). */ function laneDirty(e, n) {
801
- for (let t = e.t; t !== null; t = t.o) {
802
- const e = t.l.m?._t;
803
- if (e?.B ? sameLane(e, n) : t.l.u) t.l.R |= REACTIVE_LANE_DIRTY;
937
+ for (let o = e.o; o !== null; o = o.t) {
938
+ const e = o.u.T?.Je;
939
+ if (e?.V ? sameLane(e, n) : o.u.i) o.u.R |= REACTIVE_LANE_DIRTY;
804
940
  }
805
941
  }
806
942
 
807
943
  /** One lane, or two of one link group (#3335): one reveal unit. */ function sameLane(e, n) {
808
- return e === n || e.un !== null && e.un === n.un;
944
+ return e === n || e.nn !== null && e.nn === n.nn;
809
945
  }
810
946
 
811
947
  function commitPendingNode(e) {
@@ -815,40 +951,52 @@ function commitPendingNode(e) {
815
951
  // staged) stays uncommitted: a re-pass disposes its children on the spot,
816
952
  // and the frame it parked stays the frame until a pass of this node
817
953
  // commits a value.
818
- if (!n.ee) {
819
- e.i &= -385;
820
- if (e.Oe !== NOT_PENDING) {
821
- e.Ae = e.Oe;
822
- e.Oe = NOT_PENDING;
954
+ if (!n.X) {
955
+ e.l &= -385;
956
+ if (e.ue !== NOT_PENDING) {
957
+ e.Ie = e.ue;
958
+ e.ue = NOT_PENDING;
823
959
  }
824
960
  return;
825
961
  }
826
962
  // Computeds only from here (`_statusFlags` is not a signal field). A
827
963
  // commit beneath a flight publishes its inputs (A15 reveal corollary,
828
964
  // #3305): a reveal of it must observe, not show the pre-flight value.
829
- const t = e.Oe === NOT_PENDING && (n.S & STATUS_PENDING) !== 0;
830
- e.i = t ? e.i & -1048833 | CONFIG_INPUTS_PUBLISHED : e.i & -1049985;
831
- if (e.Oe !== NOT_PENDING) {
832
- e.Ae = e.Oe;
833
- e.Oe = NOT_PENDING;
965
+ const o = e.ue === NOT_PENDING && (n.m & STATUS_PENDING) !== 0;
966
+ const t = e.l & CONFIG_STAGED_ERROR;
967
+ // An answer commits: the error it replaces leaves the display (D-41).
968
+ if (!o && n.T) n.T.de = undefined;
969
+ e.l = o ? e.l & -1048833 | CONFIG_INPUTS_PUBLISHED : e.l & -3147137;
970
+ // D-41: the staged answer is an error — published now, when a value would
971
+ // show, through the ordinary error path (`stageError`). Its readers first
972
+ // see it in the cycle after this seam: a tracked re-read there is not a
973
+ // retry (`read`), or a boundary re-derived by it would retry it forever.
974
+ if (t) {
975
+ const o = e.ue;
976
+ e.ue = NOT_PENDING;
977
+ e.ie = clock + 1;
978
+ notifyStatus(n, STATUS_ERROR, o);
979
+ } else if (e.ue !== NOT_PENDING) {
980
+ e.Ie = e.ue;
981
+ e.ue = NOT_PENDING;
834
982
  // A node born staged (recompute) initializes at this commit.
835
- n.S &= ~STATUS_UNINITIALIZED;
983
+ n.m &= ~STATUS_UNINITIALIZED;
836
984
  // A quiet re-ask's classification survives its landing and dies with
837
985
  // the landed value's commit (A19 exc. 2, #3178): verdict-quiet through
838
986
  // the reveal. (The sweep of a node still in flight is not a landing.)
839
987
  // The A28 stash goes with it.
840
- if (n.m != null) n.m.It = false, n.m.ht = NOT_PENDING;
988
+ if (n.T != null) n.T.ut = false, n.T.Gt = NOT_PENDING;
841
989
  // An effect with a staged value was born held (L2): its first run is
842
990
  // this commit's, not its creation's (A29) — queue it now.
843
- if (e.u && e.u !== EFFECT_TRACKED) {
844
- e.lt = true;
845
- globalQueue.enqueue(e.u, e.Y ??= GlobalQueue.q.bind(null, n));
991
+ if (e.i && e.i !== EFFECT_TRACKED) {
992
+ e.Qe = true;
993
+ globalQueue.enqueue(e.i, e.W ??= GlobalQueue.K.bind(null, n));
846
994
  }
847
995
  }
848
996
  // The committed value is the first observable answer for a loading-window
849
997
  // node — the window closes here, not at compute time (#2990). Unconditional
850
998
  // store to an always-present computed slot.
851
- n.De = false;
999
+ n.ce = false;
852
1000
  n.R &= ~REACTIVE_MANUAL_WRITE;
853
1001
  // The dependencies of the pass that produced the value are the frame's now:
854
1002
  // the previous frame's tail goes (A30, #3410; `recompute` left it for a
@@ -856,11 +1004,11 @@ function commitPendingNode(e) {
856
1004
  // pass or by the node's own landing (whose pass was clean), so a set
857
1005
  // `_error` means the last pass threw, kept its full list, and `_depsTail`
858
1006
  // marks where it stopped.
859
- if (n.m?.F == null) trimStaleDeps(n);
860
- if (!(n.S & STATUS_PENDING)) n.S &= ~STATUS_UNINITIALIZED;
1007
+ if (n.T?.F == null) trimStaleDeps(n);
1008
+ if (!(n.m & STATUS_PENDING)) n.m &= ~STATUS_UNINITIALIZED;
861
1009
  // L2: the children this commit publishes are the frame's now — the frame
862
1010
  // they replace, parked by the pass (`recompute`), goes.
863
- if (!t && n.m != null && (n.m.St !== null || n.m.ct !== null)) GlobalQueue.Et(n, false, true);
1011
+ if (!o && n.T != null && (n.T.Nt !== null || n.T.ft !== null)) GlobalQueue.et(n, false, true);
864
1012
  }
865
1013
 
866
1014
  function commitPendingNodes() {
@@ -869,7 +1017,7 @@ function commitPendingNodes() {
869
1017
  // A node a lane pass re-staged this round is the lane's to reveal; one
870
1018
  // a transaction holds (born held by a mainline pass, `passTx`) is that
871
1019
  // transaction's to commit, at its landing.
872
- if (!(n.i & (CONFIG_OVERRIDE | CONFIG_HELD))) commitPendingNode(n);
1020
+ if (!(n.l & (CONFIG_OVERRIDE | CONFIG_HELD))) commitPendingNode(n);
873
1021
  }
874
1022
  pendingNodes.length = 0;
875
1023
  }
@@ -894,7 +1042,7 @@ function flush(e) {
894
1042
  }
895
1043
  }
896
1044
  }
897
- if (globalQueue.X) {
1045
+ if (globalQueue.q) {
898
1046
  return;
899
1047
  }
900
1048
  if (halted) return;
@@ -918,7 +1066,7 @@ function flush(e) {
918
1066
  }
919
1067
 
920
1068
  function runQueue(e, n) {
921
- for (let t = 0; t < e.length; t++) e[t](n);
1069
+ for (let o = 0; o < e.length; o++) e[o](n);
922
1070
  }
923
1071
 
924
- export { GlobalQueue, MAINLINE_QUESTION, ROOT_ERROR_HOOK, actionDepth, blocked, blockersOf, bumpNotifyEpoch, clock, commitPendingNode, deferZombie, dirtyQueue, enforceLoadingBoundary, enterAction, exitAction, flush, flushTransaction, globalQueue, haltReactivity, heldTrim, holdNode, insertSubs, joinFuture, joinPassTx, laneDirty, list, liveTx, merge, newTransaction, nextQuestion, notifyEpoch, ownFlights, passLane, passTx, question, queuePendingNode, releaseQueues, reruns, resetErrorHalt, resolveTx, sameLane, schedule, setPassLane, setQuestion, stagedReaders, staleReader, txOf };
1072
+ export { GlobalQueue, MAINLINE_QUESTION, ROOT_ERROR_HOOK, actionDepth, applyGuessesHook, blocked, blockersOf, boundarySeamHook, bumpNotifyEpoch, catchHook, clock, commitPendingNode, deferZombie, dirtyQueue, endLanesHook, enforceLoadingBoundary, enterAction, exitAction, externalUntrackHook, flush, flushTransaction, freshHook, globalQueue, haltReactivity, heldRunHook, heldTrim, heldUnder, hiddenHook, holdNode, insertSubs, installBoundaryHooks, installLaneHooks, installMarkHooks, installStoreHooks, installVerdictHooks, joinFuture, joinPassTx, laneCorrectionsHook, laneDirty, laneOutcomeHook, laneReadHook, laneSeamsHook, laneStageHook, laneWriteHook, lanesBlockedHook, list, liveTx, merge, newTransaction, nextQuestion, notifyEpoch, observeFlightHook, ownFlights, passLane, passTx, question, queuePendingNode, releaseAmbientMarksHook, releaseMarksHook, releaseQueues, reruns, resetErrorHalt, resolveTx, sameLane, schedule, setExternalHooks, setPassLane, setQuestion, stagedReaders, staleReader, storeCommitHook, storeParkHook, txOf, unhold, wireExternalSourceHook };