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

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 (66) hide show
  1. package/dist/dev-shared.js +248 -189
  2. package/dist/dev.attribution.js +124 -41
  3. package/dist/dev.js +553 -322
  4. package/dist/observe/affects.js +34 -31
  5. package/dist/observe/boundaries.js +166 -132
  6. package/dist/observe/core/async.js +90 -83
  7. package/dist/observe/core/attribution-queries.js +1 -1
  8. package/dist/observe/core/attribution.js +281 -197
  9. package/dist/observe/core/constants.js +7 -2
  10. package/dist/observe/core/context.js +3 -3
  11. package/dist/observe/core/core.js +277 -245
  12. package/dist/observe/core/dev.js +3 -3
  13. package/dist/observe/core/effect.js +21 -21
  14. package/dist/observe/core/external.js +2 -2
  15. package/dist/observe/core/graph.js +25 -25
  16. package/dist/observe/core/heap.js +9 -9
  17. package/dist/observe/core/lanes.js +206 -160
  18. package/dist/observe/core/owner.js +27 -27
  19. package/dist/observe/core/scheduler.js +92 -86
  20. package/dist/observe/core/verdict.js +66 -54
  21. package/dist/observe/map.js +35 -35
  22. package/dist/observe/reveal.js +24 -24
  23. package/dist/observe/signals.js +38 -28
  24. package/dist/observe/store/affects.js +75 -68
  25. package/dist/observe/store/hooks.js +13 -0
  26. package/dist/observe/store/index.js +0 -2
  27. package/dist/observe/store/optimistic.js +67 -34
  28. package/dist/observe/store/projection.js +37 -31
  29. package/dist/observe/store/reconcile.js +32 -30
  30. package/dist/observe/store/store.js +128 -85
  31. package/dist/prod/affects.js +34 -31
  32. package/dist/prod/boundaries.js +143 -109
  33. package/dist/prod/core/async.js +64 -67
  34. package/dist/prod/core/constants.js +7 -2
  35. package/dist/prod/core/context.js +3 -3
  36. package/dist/prod/core/core.js +302 -270
  37. package/dist/prod/core/effect.js +38 -38
  38. package/dist/prod/core/external.js +4 -4
  39. package/dist/prod/core/graph.js +27 -27
  40. package/dist/prod/core/heap.js +30 -30
  41. package/dist/prod/core/lanes.js +257 -211
  42. package/dist/prod/core/owner.js +39 -39
  43. package/dist/prod/core/scheduler.js +125 -119
  44. package/dist/prod/core/verdict.js +70 -58
  45. package/dist/prod/map.js +73 -73
  46. package/dist/prod/reveal.js +38 -38
  47. package/dist/prod/signals.js +30 -20
  48. package/dist/prod/store/affects.js +75 -68
  49. package/dist/prod/store/hooks.js +13 -0
  50. package/dist/prod/store/index.js +0 -2
  51. package/dist/prod/store/optimistic.js +114 -81
  52. package/dist/prod/store/projection.js +30 -24
  53. package/dist/prod/store/reconcile.js +32 -30
  54. package/dist/prod/store/store.js +136 -93
  55. package/dist/types/boundaries.d.ts +4 -0
  56. package/dist/types/core/attribution.d.ts +6 -2
  57. package/dist/types/core/constants.d.ts +5 -0
  58. package/dist/types/core/core.d.ts +33 -3
  59. package/dist/types/core/lanes.d.ts +10 -0
  60. package/dist/types/core/scheduler.d.ts +12 -6
  61. package/dist/types/core/types.d.ts +0 -6
  62. package/dist/types/store/affects.d.ts +11 -0
  63. package/dist/types/store/hooks.d.ts +48 -0
  64. package/dist/types/store/index.d.ts +0 -1
  65. package/dist/types/store/store.d.ts +3 -38
  66. package/package.json +1 -1
@@ -10,7 +10,7 @@ import { enqueueSub } from "./heap.js";
10
10
 
11
11
  import { cleanup } from "./owner.js";
12
12
 
13
- import { question, MAINLINE_QUESTION, passLane, joinFuture, clock, schedule, flush, liveTx, holdNode, globalQueue, txOf, GlobalQueue, queuePendingNode } from "./scheduler.js";
13
+ import { question, MAINLINE_QUESTION, passLane, joinFuture, clock, schedule, flush, globalQueue, txOf, GlobalQueue, queuePendingNode } from "./scheduler.js";
14
14
 
15
15
  // The lazily-created Set is the ONE container for pending sources. Its
16
16
  // predecessor — a singular slot promoted to a Set on the second source —
@@ -42,7 +42,7 @@ function clearPendingSources(e) {
42
42
  // (pending sources propagate the origin node, so this covers any depth).
43
43
  // Also guards branch-local recovery: another dependency may still need the source.
44
44
  function retryReaches(e, t) {
45
- for (let n = e._; n; n = n.p) {
45
+ for (let n = e.p; n; n = n._) {
46
46
  const e = n.I;
47
47
  if (e === t || e.m?.Se?.has(t)) return true;
48
48
  }
@@ -56,32 +56,32 @@ function retryReaches(e, t) {
56
56
  * with NO read-visible pending status and no downstream propagation. Commit
57
57
  * #0 keeps serving.
58
58
  */ function parkLoadingWindow(e, t) {
59
- ext(e).Ie = true;
59
+ ext(e).de = true;
60
60
  if (t.source) addPendingSource(e, t.source);
61
61
  // A settled error is the node's answer ("the error stays the answer until
62
62
  // this retry can actually run") — the park must not replace it: reads
63
63
  // throw `_error` while STATUS_ERROR is set, and overwriting it here leaks
64
64
  // a pending-class NotReadyError from a read-invisible park (#2989).
65
- if (!(e.G & STATUS_ERROR)) setPendingError(e, t.source, t);
65
+ if (!(e.S & STATUS_ERROR)) setPendingError(e, t.source, t);
66
66
  }
67
67
 
68
68
  function setPendingError(e, t, n) {
69
69
  if (!t) {
70
- if (e.m !== null) e.m.V = null;
70
+ if (e.m !== null) e.m.F = null;
71
71
  return;
72
72
  }
73
73
  if (n instanceof NotReadyError && n.source === t) {
74
- ext(e).V = n;
74
+ ext(e).F = n;
75
75
  return;
76
76
  }
77
- const r = e.m?.V;
77
+ const r = e.m?.F;
78
78
  if (!(r instanceof NotReadyError) || r.source !== t) {
79
- ext(e).V = new NotReadyError(t);
79
+ ext(e).F = new NotReadyError(t);
80
80
  }
81
81
  }
82
82
 
83
83
  function forEachDependent(e, t) {
84
- for (let n = e.t; n !== null; n = n.l) t(n.o, n);
84
+ for (let n = e.t; n !== null; n = n.o) t(n.l, n);
85
85
  }
86
86
 
87
87
  // Queue a node to re-run on the next flush (used both when a pending source
@@ -95,7 +95,7 @@ function forEachDependent(e, t) {
95
95
  // callbacks handle their own release (settleAutodispose in handleAsync); this
96
96
  // covers derivatively-pending dependents, which have no callbacks of their own.
97
97
  function releaseIfSettledUnobserved(e) {
98
- e.re && e.u & CONFIG_AUTO_DISPOSE && !e.t && !(e.R & REACTIVE_ZOMBIE) && !(e.G & STATUS_PENDING) && unobserved(e);
98
+ e.ee && e.i & CONFIG_AUTO_DISPOSE && !e.t && !(e.R & REACTIVE_ZOMBIE) && !(e.S & STATUS_PENDING) && unobserved(e);
99
99
  }
100
100
 
101
101
  // Error-path sweep: notifyStatus(STATUS_ERROR) clears dependents' pending
@@ -108,7 +108,7 @@ function releaseSettledDependents(e) {
108
108
  const visit = e => {
109
109
  if (n.has(e)) return;
110
110
  n.add(e);
111
- if (!e.t && e.u & CONFIG_AUTO_DISPOSE) (t ??= []).push(e);
111
+ if (!e.t && e.i & CONFIG_AUTO_DISPOSE) (t ??= []).push(e);
112
112
  forEachDependent(e, visit);
113
113
  };
114
114
  forEachDependent(e, visit);
@@ -136,7 +136,7 @@ function settleErroredDependents(e, t) {
136
136
  const visit = e => {
137
137
  if (r.has(e)) return;
138
138
  r.add(e);
139
- if (e.m?.V === t) {
139
+ if (e.m?.F === t) {
140
140
  enqueueSub(e);
141
141
  n = true;
142
142
  }
@@ -171,35 +171,35 @@ function settlePendingSource(e, t = e) {
171
171
  // when the source went pending, `propagateStatus`), and a landing
172
172
  // equal to the committed value notifies nobody — the source settling
173
173
  // is its verdict changing: it runs again.
174
- return f.u & CONFIG_VERDICT && enqueueSub(f);
174
+ return f.i & CONFIG_VERDICT && enqueueSub(f);
175
175
  o.add(f);
176
- f.Ne = clock;
176
+ f.Ie = clock;
177
177
  const u = f.m?.Se?.values().next().value;
178
178
  // STATUS_ERROR + pending sources only coexist via an errored loading
179
179
  // window's park (notifyStatus(STATUS_ERROR) clears pending sources
180
180
  // otherwise): the settled error stays the answer through the settle —
181
181
  // nulling it here would have reads throw `null` until the re-enqueued
182
182
  // retry lands, or lose it entirely if that retry parks again (#2989).
183
- const i = f.G & STATUS_ERROR;
183
+ const i = f.S & STATUS_ERROR;
184
184
  if (u) {
185
185
  if (!i) setPendingError(f, u);
186
186
  } else {
187
- f.G &= ~STATUS_PENDING;
187
+ f.S &= ~STATUS_PENDING;
188
188
  if (!i) setPendingError(f);
189
189
  // L2: a landing resumes the transaction waiting on it (maintainer: "it
190
190
  // resumes the sync frame") — a held reader's re-pass over the landed
191
191
  // value is that transaction's work, and the flush that carries it
192
192
  // parks into it.
193
- if (f.u & CONFIG_HELD) joinFuture(txOf(f));
194
- if (f.m?.Ie) {
193
+ if (f.i & CONFIG_HELD) joinFuture(txOf(f));
194
+ if (f.m?.de) {
195
195
  enqueueSub(f);
196
196
  n = true;
197
197
  }
198
- if (f.m !== null) f.m.Ie = false;
198
+ if (f.m !== null) f.m.de = false;
199
199
  // Fully settled with nobody watching: release candidate (#2934). Checked
200
200
  // again at release time — deferred so unobserved() can't unlink subs
201
201
  // lists this walk is still iterating.
202
- if (!f.t && f.u & CONFIG_AUTO_DISPOSE) (r ??= []).push(f);
202
+ if (!f.t && f.i & CONFIG_AUTO_DISPOSE) (r ??= []).push(f);
203
203
  }
204
204
  forEachDependent(f, settle);
205
205
  };
@@ -216,9 +216,9 @@ function isThenable(e) {
216
216
  }
217
217
 
218
218
  /** Fire and clear a node's iterator-flight cancellation hook (#3122). */ function releaseFlightTeardown(e) {
219
- const t = e.m?.Te;
219
+ const t = e.m?.Ne;
220
220
  if (t != null) {
221
- e.m.Te = null;
221
+ e.m.Ne = null;
222
222
  t();
223
223
  }
224
224
  }
@@ -238,9 +238,9 @@ r) {
238
238
  });
239
239
  }
240
240
  if (!f && !o) {
241
- if (e.m !== null) e.m.De = null;
241
+ if (e.m !== null) e.m.Te = null;
242
242
  // A sync landing is the first real answer for a loadingValue node.
243
- e._e = false;
243
+ e.De = false;
244
244
  return t;
245
245
  }
246
246
  // Flight replacement relies on recompute's supersede release for iterator
@@ -248,10 +248,10 @@ r) {
248
248
  // self-registration — runs during a recompute of `el`, which has already
249
249
  // fired _flightTeardown. A future non-recompute registration path must
250
250
  // release it here before overwriting _inFlight.
251
- ext(e).De = t;
251
+ ext(e).Te = t;
252
252
  // The question this flight answers (A18 provenance, lanes.ts): the action
253
253
  // whose slice asked it; mainline is always the current question.
254
- e.m.Oe = question || MAINLINE_QUESTION;
254
+ e.m._e = question || MAINLINE_QUESTION;
255
255
  // The run that asked this flight read every input without throwing: an
256
256
  // input still in flight was masked for it (an active override, A17), so
257
257
  // pending state those inputs propagated onto the node earlier does not
@@ -261,17 +261,17 @@ r) {
261
261
  e.m.Se = undefined;
262
262
  let u;
263
263
  const handleError = n => {
264
- if (e.m?.De !== t) return;
264
+ if (e.m?.Te !== t) return;
265
265
  // NotReadyError from rejected promises should be treated as pending, not error
266
266
  let o = n instanceof NotReadyError;
267
- if (o && e._e) {
267
+ if (o && e.De) {
268
268
  // Loading window: the flight died waiting on an unready source. Keep
269
269
  // serving commit #0 — same parking as recompute's catch for sync
270
270
  // dependency throws. The dead flight is released so the clock-gated
271
271
  // error-retry pull (updateIfNecessary) can also re-ask.
272
- if (e.m !== null) e.m.De = null;
272
+ if (e.m !== null) e.m.Te = null;
273
273
  parkLoadingWindow(e, n);
274
- e.Ne = clock;
274
+ e.Ie = clock;
275
275
  return;
276
276
  }
277
277
  notifyStatus(e, o ? STATUS_PENDING : STATUS_ERROR, n);
@@ -279,7 +279,7 @@ r) {
279
279
  // rejected flight will never settle its self entry, so transfer ownership
280
280
  // after notifyStatus has propagated the replacement source.
281
281
  if (o) settlePendingSource(e);
282
- e.Ne = clock;
282
+ e.Ie = clock;
283
283
  // A real error settles derivatively-pending dependents (notifyStatus
284
284
  // cleared their pending sources), so stranded lazy ones release here —
285
285
  // the error twin of settlePendingSource's release (#2934).
@@ -287,12 +287,12 @@ r) {
287
287
  r?.(n, o);
288
288
  };
289
289
  const asyncWrite = (r, o) => {
290
- if (e.m?.De !== t) return;
290
+ if (e.m?.Te !== t) return;
291
291
  // If the node was dirtied by a newer write (optimistic override or regular),
292
292
  // skip this stale async result — the upcoming flush will recompute the node
293
293
  // with the new value, creating a fresh Promise that supersedes this one.
294
294
  if (e.R & REACTIVE_DIRTY) return;
295
- const f = !!(e.G & STATUS_UNINITIALIZED);
295
+ const f = !!(e.S & STATUS_UNINITIALIZED);
296
296
  landStatus(e);
297
297
  if (n) {
298
298
  try {
@@ -305,11 +305,8 @@ r) {
305
305
  } else {
306
306
  // CARVE 2: the override-covered landing (hold + A18 supersession) and the
307
307
  // lane-routed landing (derived override, lane effect queue) went with
308
- // the optimistic engine; every landing is the plain setSignal. A first
309
- // answer born into a hold still live lands into it (A29, #3800).
310
- let t = e.m.Re;
311
- e.m.Re = null;
312
- if (f && t && (t = liveTx(t))) holdNode(e, t);
308
+ // the optimistic engine; every landing is the plain setSignal. A node
309
+ // already held stages its answer into that hold (`setSignal`).
313
310
  try {
314
311
  setSignal(e, () => r);
315
312
  } catch (t) {
@@ -323,8 +320,8 @@ r) {
323
320
  // (`_pendingValue` set inside setSignal) is not — commitPendingNode closes
324
321
  // the window when the flush commits it, so no one-frame pulse can leak to
325
322
  // observers between the landing and its commit (#2990).
326
- if (e.Ae === NOT_PENDING) {
327
- e._e = false;
323
+ if (e.Oe === NOT_PENDING) {
324
+ e.De = false;
328
325
  // The landing published: the dependency tail the flight's pass left
329
326
  // linked goes now (A30, #3410). A staged landing has not replaced the
330
327
  // committed frame yet; `commitPendingNode` trims it.
@@ -343,7 +340,7 @@ r) {
343
340
  // Returns whether the node released, so the iterator branch can stop
344
341
  // pulling values instead of pumping an unobserved stream forever (#2935).
345
342
  const settleAutodispose = () => {
346
- if (e.u & CONFIG_AUTO_DISPOSE && !e.t && !(e.G & STATUS_PENDING)) {
343
+ if (e.i & CONFIG_AUTO_DISPOSE && !e.t && !(e.S & STATUS_PENDING)) {
347
344
  unobserved(e);
348
345
  return true;
349
346
  }
@@ -377,7 +374,7 @@ r) {
377
374
  // Flight-identity cancellation (#3122): the registration above is the
378
375
  // owner-death backstop; the teardown slot fires at the _inFlight release
379
376
  // sites so supersede stops this stream immediately.
380
- ext(e).Te = close;
377
+ ext(e).Ne = close;
381
378
  // Release check before each next pull: an unobserved lazy node must tear
382
379
  // down (its close above runs via disposal, closing the iterator) instead
383
380
  // of pumping the stream forever with zero subscribers (#2935).
@@ -392,10 +389,10 @@ r) {
392
389
  // buffered (seroval's deserialized streams do), so a bare result is
393
390
  // assimilated as an already-settled step instead of crashing on `.then`.
394
391
  const S = o.next();
395
- const d = isThenable(S) ? S : {
392
+ const E = isThenable(S) ? S : {
396
393
  then: e => void e(S)
397
394
  };
398
- d.then(r => {
395
+ E.then(r => {
399
396
  // The sync stash only serves the INITIAL drain (handleAsync's caller
400
397
  // consumes syncValue / throws NotReady from it). A sync-settled step
401
398
  // after an async gap — seroval buffering values between pulls, a
@@ -407,7 +404,7 @@ r) {
407
404
  n = r;
408
405
  l = true;
409
406
  if (r.done) i = true;
410
- } else if (e.m?.De !== t) {
407
+ } else if (e.m?.Te !== t) {
411
408
  return;
412
409
  } else if (!r.done) {
413
410
  f = true;
@@ -427,7 +424,7 @@ r) {
427
424
  if (c && s) {
428
425
  r = n;
429
426
  a = true;
430
- } else if (e.m?.De === t) {
427
+ } else if (e.m?.Te === t) {
431
428
  i = true;
432
429
  handleError(n);
433
430
  settleAutodispose();
@@ -483,13 +480,13 @@ r) {
483
480
  // have put it. Only a flight that actually flattens becomes
484
481
  // disposal-bearing.
485
482
  const registerDeferredClose = t => {
486
- if (!e.Pe) e.Pe = t; else if (Array.isArray(e.Pe)) e.Pe.push(t); else e.Pe = [ e.Pe, t ];
483
+ if (!e.Re) e.Re = t; else if (Array.isArray(e.Re)) e.Re.push(t); else e.Re = [ e.Re, t ];
487
484
  };
488
485
  t.then(r => {
489
486
  if (f) {
490
487
  u = r;
491
488
  n = true;
492
- } else if (e.m?.De === t && !(e.R & REACTIVE_DISPOSED) && flattenIfIterable(r, registerDeferredClose)) ; else {
489
+ } else if (e.m?.Te === t && !(e.R & REACTIVE_DISPOSED) && flattenIfIterable(r, registerDeferredClose)) ; else {
493
490
  asyncWrite(r);
494
491
  settleAutodispose();
495
492
  }
@@ -514,11 +511,11 @@ r) {
514
511
  // work on a loadingValue node is loading-class (invisible to
515
512
  // boundaries); the flight itself is already registered in _inFlight and
516
513
  // lands through asyncWrite.
517
- if (e._e) return e.pe;
514
+ if (e.De) return e.Ae;
518
515
  throw new NotReadyError(context);
519
516
  } else if (!flattenIfIterable(u)) {
520
517
  // Synchronously-resolved promise: the first real answer landed.
521
- e._e = false;
518
+ e.De = false;
522
519
  }
523
520
  // A sync-resolved promise holding an AsyncIterable flattened LIVE (we
524
521
  // are still inside the synchronous read): full initial-drain semantics
@@ -528,21 +525,21 @@ r) {
528
525
  if (i !== null) {
529
526
  if (!i) {
530
527
  // Loading window: serve commit #0 (see the promise branch above).
531
- if (e._e) return e.pe;
528
+ if (e.De) return e.Ae;
532
529
  throw new NotReadyError(context);
533
530
  }
534
531
  // A sync first yield (or immediate empty completion) is the first real
535
532
  // answer; async yields clear inside asyncWrite.
536
- e._e = false;
533
+ e.De = false;
537
534
  }
538
535
  return u;
539
536
  }
540
537
 
541
538
  function clearStatus(e, t = false) {
542
539
  if (e.m?.Se) clearPendingSources(e);
543
- if (e.m?.Ie) if (e.m !== null) e.m.Ie = false;
544
- e.G = t ? 0 : e.G & STATUS_UNINITIALIZED;
545
- if (e.m?.V) setPendingError(e);
540
+ if (e.m?.de) if (e.m !== null) e.m.de = false;
541
+ e.S = t ? 0 : e.S & STATUS_UNINITIALIZED;
542
+ if (e.m?.F) setPendingError(e);
546
543
  const n = statusNotifierOf(e);
547
544
  if (n) n.call(e);
548
545
  }
@@ -575,8 +572,8 @@ function clearStatus(e, t = false) {
575
572
  const n = e.m?.Se;
576
573
  // (The full clear below drops the set whether or not self was retired first.)
577
574
  if (n && (n.delete(e), n.size)) {
578
- e.m.Ie = false;
579
- if (t) e.G = STATUS_PENDING;
575
+ e.m.de = false;
576
+ if (t) e.S = STATUS_PENDING;
580
577
  setPendingError(e, n.values().next().value);
581
578
  } else clearStatus(e, t);
582
579
  }
@@ -589,14 +586,14 @@ function notifyStatus(e, t, n, r) {
589
586
  {
590
587
  if (t === STATUS_PENDING && o) {
591
588
  addPendingSource(e, o);
592
- e.G = STATUS_PENDING | e.G & STATUS_UNINITIALIZED;
589
+ e.S = STATUS_PENDING | e.S & STATUS_UNINITIALIZED;
593
590
  // Preserve the current source on this propagation so readers park on
594
591
  // the distinct pending source.
595
592
  setPendingError(e, o, n);
596
593
  } else {
597
594
  clearPendingSources(e);
598
- e.G = t | (t !== STATUS_ERROR ? e.G & STATUS_UNINITIALIZED : 0);
599
- ext(e).V = n;
595
+ e.S = t | (t !== STATUS_ERROR ? e.S & STATUS_UNINITIALIZED : 0);
596
+ ext(e).F = n;
600
597
  }
601
598
  }
602
599
  // Lanes: a written guess is an optimistic boundary (A17 — "the optimistic
@@ -605,7 +602,7 @@ function notifyStatus(e, t, n, r) {
605
602
  // transition's to wait on — the frame it was asked in holds (A17: "a
606
603
  // transition whose optimistic node is still pending on its own fetch is
607
604
  // not complete"), through the node itself (`blocked`).
608
- if (t === STATUS_PENDING && e.u & CONFIG_GUESS) {
605
+ if (t === STATUS_PENDING && e.i & CONFIG_GUESS) {
609
606
  if (passLane === null) joinFuture(null);
610
607
  return;
611
608
  }
@@ -626,7 +623,7 @@ function notifyStatus(e, t, n, r) {
626
623
  * (store/projection.ts `wakeFamily`), exactly as a memo's would reach its. */ function propagateStatus(e, t, n, r) {
627
624
  const o = t === STATUS_PENDING && n instanceof NotReadyError ? n.source : undefined;
628
625
  forEachDependent(e, (r, f) => {
629
- r.Ne = clock;
626
+ r.Ie = clock;
630
627
  // A pending mark on a kept-tail link re-derives the subscriber instead of
631
628
  // marking it (A30, #3494 review; fuzzer latest-1 #2141; #3519 review).
632
629
  // Past `_depsTail` lie the committed frame's deps, kept by A30 because
@@ -646,7 +643,7 @@ function notifyStatus(e, t, n, r) {
646
643
  // Inheriting the error would make a probe's reader errored. A boundary's
647
644
  // output (CONFIG_REDERIVE, boundaries.ts) the same: content or fallback
648
645
  // is its pass's call.
649
- if (r.u & (CONFIG_REDERIVE | CONFIG_VERDICT) || t === STATUS_PENDING && f.Ue !== r.Ge) {
646
+ if (r.i & (CONFIG_REDERIVE | CONFIG_VERDICT) || t === STATUS_PENDING && f.Pe !== r.pe) {
650
647
  enqueueSub(r);
651
648
  schedule();
652
649
  return;
@@ -659,24 +656,24 @@ function notifyStatus(e, t, n, r) {
659
656
  // shape: the unmount it stages makes the observer a zombie whose say is
660
657
  // moot for this transaction, A15 #3463).
661
658
  if (t === STATUS_PENDING && o && r.m?.Se?.has(o)) {
662
- if (passLane === null && (r.u & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && globalQueue.ee) joinFuture(txOf(r));
659
+ if (passLane === null && (r.i & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && globalQueue.X) joinFuture(txOf(r));
663
660
  return;
664
661
  }
665
- if (t === STATUS_PENDING && o || t !== STATUS_PENDING && (r.m?.V !== n || r.m?.Se)) {
662
+ if (t === STATUS_PENDING && o || t !== STATUS_PENDING && (r.m?.F !== n || r.m?.Se)) {
666
663
  // The marked subscriber is queued for the commit sweep so its status
667
664
  // bookkeeping (loading window, uninitialized clear) runs with the flush
668
665
  // — with the lane, when the pass propagating is the lane's work and
669
666
  // the dependent's pending is the lane's own flight (`laneStage`).
670
667
  {
671
668
  // (No answer: a pending propagation leaves a written guess a guess.)
672
- if (passLane !== null) GlobalQueue.M(r, passLane, true, e); else {
669
+ if (passLane !== null) GlobalQueue.W(r, passLane, true, e); else {
673
670
  queuePendingNode(r);
674
671
  // A15 (#3443): pending propagates onto a held memo without
675
672
  // recomputing it, and the propagation itself enters the memo's
676
673
  // transaction — the flight flows into a memo that transaction
677
674
  // holds, so the write that started it is held with it. A render
678
675
  // effect's membership is its pass's (`notify`), never sticky.
679
- if (t === STATUS_PENDING && (r.u & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && !r.i) joinFuture(txOf(r));
676
+ if (t === STATUS_PENDING && (r.i & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && !r.u) joinFuture(txOf(r));
680
677
  }
681
678
  }
682
679
  notifyStatus(r, t, n);
@@ -97,7 +97,7 @@ const CONFIG_SYNC = 1 << 6;
97
97
  // CONFIG_HELD_CHILDREN, CONFIG_INPUTS_PUBLISHED and CONFIG_ADOPTED_UNFLUSHED
98
98
  // (transaction holds, zombies, until()'s authoritative view) went with the
99
99
  // transactions.
100
- // L2 (step 2): three bits, all maintained by the node's commit.
100
+ // L2 (step 2): four bits, all maintained by the node's commit.
101
101
  /** The node has a pass awaiting commit: its live children (and `_disposal`)
102
102
  * are that pass's and were never shown — a re-pass tears them down on the
103
103
  * spot, while the frame parked on `_x._pendingFirstChild` keeps waiting for
@@ -110,6 +110,11 @@ const CONFIG_SYNC = 1 << 6;
110
110
  * parking flush they see the committed value and hold nothing, and are
111
111
  * re-derived at the landing. Set at the park seam on every staged node. */ const CONFIG_HELD = 1 << 8;
112
112
 
113
+ /** A member of the uncommitted frame a held pass built (ruling A): set at
114
+ * the park seam on every computed under a staged node (`holdFrame`). Never
115
+ * shown, it has no screen: its reads are its transaction's, whichever flush
116
+ * runs it (`bornInto`, #4010). Cleared by its commit. */ const CONFIG_HELD_FRAME = 1 << 20;
117
+
113
118
  /** A15's reveal corollary (#3305): a commit published this flight's inputs
114
119
  * beneath it — the node was pending, nothing staged, when it committed — so
115
120
  * its committed value is torn against the visible frame. A render effect
@@ -209,4 +214,4 @@ const defaultContext = {};
209
214
  * @internal
210
215
  */ const $REFRESH = Symbol("refresh");
211
216
 
212
- export { $REFRESH, CONFIG_AUTHORITATIVE, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_FRESH_READ, CONFIG_GUESS, CONFIG_HAS_SNAPSHOT, CONFIG_HELD, CONFIG_INPUTS_PUBLISHED, CONFIG_IN_SNAPSHOT_SCOPE, CONFIG_MANUAL_WRITE, CONFIG_NO_SNAPSHOT, CONFIG_OVERRIDE, CONFIG_OWNED_WRITE, CONFIG_PROMOTED, CONFIG_REDERIVE, CONFIG_SLOT_NODE, CONFIG_STAGED, CONFIG_SYNC, CONFIG_TRANSPARENT, CONFIG_VERDICT, EFFECT_RENDER, EFFECT_TRACKED, EFFECT_USER, NOT_PENDING, NO_SNAPSHOT, REACTIVE_CHECK, REACTIVE_DIRTY, REACTIVE_DISPOSED, REACTIVE_FRAME_READ, REACTIVE_IN_HEAP, REACTIVE_IN_HEAP_HEIGHT, REACTIVE_JOINED, REACTIVE_LANE_DIRTY, REACTIVE_LANE_READ, REACTIVE_LAZY, REACTIVE_MANUAL_WRITE, REACTIVE_MISSED_WAKE, REACTIVE_NONE, REACTIVE_PROBED, REACTIVE_PROBE_UNANSWERED, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, REACTIVE_SCREEN_READ, REACTIVE_SNAPSHOT_STALE, REACTIVE_STAGED_READ, REACTIVE_ZOMBIE, STATUS_ERROR, STATUS_PENDING, STATUS_UNINITIALIZED, SUPPORTS_PROXY, defaultContext };
217
+ export { $REFRESH, CONFIG_AUTHORITATIVE, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_FRESH_READ, CONFIG_GUESS, CONFIG_HAS_SNAPSHOT, CONFIG_HELD, CONFIG_HELD_FRAME, CONFIG_INPUTS_PUBLISHED, CONFIG_IN_SNAPSHOT_SCOPE, CONFIG_MANUAL_WRITE, CONFIG_NO_SNAPSHOT, CONFIG_OVERRIDE, CONFIG_OWNED_WRITE, CONFIG_PROMOTED, CONFIG_REDERIVE, CONFIG_SLOT_NODE, CONFIG_STAGED, CONFIG_SYNC, CONFIG_TRANSPARENT, CONFIG_VERDICT, EFFECT_RENDER, EFFECT_TRACKED, EFFECT_USER, NOT_PENDING, NO_SNAPSHOT, REACTIVE_CHECK, REACTIVE_DIRTY, REACTIVE_DISPOSED, REACTIVE_FRAME_READ, REACTIVE_IN_HEAP, REACTIVE_IN_HEAP_HEIGHT, REACTIVE_JOINED, REACTIVE_LANE_DIRTY, REACTIVE_LANE_READ, REACTIVE_LAZY, REACTIVE_MANUAL_WRITE, REACTIVE_MISSED_WAKE, REACTIVE_NONE, REACTIVE_PROBED, REACTIVE_PROBE_UNANSWERED, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, REACTIVE_SCREEN_READ, REACTIVE_SNAPSHOT_STALE, REACTIVE_STAGED_READ, REACTIVE_ZOMBIE, STATUS_ERROR, STATUS_PENDING, STATUS_UNINITIALIZED, SUPPORTS_PROXY, defaultContext };
@@ -30,7 +30,7 @@ import { getOwner } from "./owner.js";
30
30
  throw new NoOwnerError;
31
31
  }
32
32
  // `undefined` alone means unset — a provided `null` is a value (no `??`).
33
- let r = t.U[e.id];
33
+ let r = t.D[e.id];
34
34
  if (r === undefined) r = e.defaultValue;
35
35
  if (r === undefined) {
36
36
  throw new ContextNotFoundError;
@@ -52,8 +52,8 @@ import { getOwner } from "./owner.js";
52
52
  }
53
53
  // We're creating a new object to avoid child context values being exposed to parent owners. If
54
54
  // we don't do this, everything will be a singleton and all hell will break lose.
55
- r.U = {
56
- ...r.U,
55
+ r.D = {
56
+ ...r.D,
57
57
  [e.id]: t === undefined ? e.defaultValue : t
58
58
  };
59
59
  }