@solidjs/signals 2.0.0-rc.7 → 2.0.0-rc.8

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 (117) hide show
  1. package/dist/dev-shared.js +5243 -0
  2. package/dist/dev.attribution.js +2333 -0
  3. package/dist/dev.js +1229 -6834
  4. package/dist/observe/affects.js +127 -0
  5. package/dist/observe/attribution.js +1 -0
  6. package/dist/observe/boundaries.js +586 -0
  7. package/dist/observe/core/action.js +167 -0
  8. package/dist/observe/core/async.js +736 -0
  9. package/dist/observe/core/attribution-hooks.js +60 -0
  10. package/dist/observe/core/attribution.js +2318 -0
  11. package/dist/{types-cjs/core/constants.d.cts → observe/core/constants.js} +129 -73
  12. package/dist/{types-cjs/core/context.d.cts → observe/core/context.js} +37 -12
  13. package/dist/observe/core/core.js +1289 -0
  14. package/dist/observe/core/dev.js +232 -0
  15. package/dist/observe/core/effect.js +179 -0
  16. package/dist/observe/core/error.js +80 -0
  17. package/dist/observe/core/external.js +98 -0
  18. package/dist/observe/core/graph.js +155 -0
  19. package/dist/observe/core/heap.js +147 -0
  20. package/dist/observe/core/invariants.js +43 -0
  21. package/dist/observe/core/lanes.js +168 -0
  22. package/dist/observe/core/optimistic.js +438 -0
  23. package/dist/observe/core/owner.js +308 -0
  24. package/dist/observe/core/scheduler.js +1190 -0
  25. package/dist/observe/core/verdict.js +551 -0
  26. package/dist/observe/index.js +55 -0
  27. package/dist/observe/map.js +482 -0
  28. package/dist/{types-cjs/signals.d.cts → observe/signals.js} +295 -317
  29. package/dist/observe/store/index.js +38 -0
  30. package/dist/observe/store/next/optimistic.js +651 -0
  31. package/dist/observe/store/next/projection.js +242 -0
  32. package/dist/observe/store/next/reconcile.js +373 -0
  33. package/dist/observe/store/next/store.js +2213 -0
  34. package/dist/observe/store/next/target.js +51 -0
  35. package/dist/observe/store/store.js +323 -0
  36. package/dist/observe/store/storePath.js +103 -0
  37. package/dist/observe/store/utils.js +210 -0
  38. package/dist/prod/attribution.js +32 -0
  39. package/dist/prod/core/action.js +52 -32
  40. package/dist/prod/core/async.js +171 -127
  41. package/dist/prod/core/constants.js +24 -1
  42. package/dist/prod/core/context.js +3 -3
  43. package/dist/prod/core/core.js +434 -291
  44. package/dist/prod/core/effect.js +54 -34
  45. package/dist/prod/core/external.js +2 -2
  46. package/dist/prod/core/graph.js +32 -32
  47. package/dist/prod/core/heap.js +49 -44
  48. package/dist/prod/core/lanes.js +45 -38
  49. package/dist/prod/core/optimistic.js +207 -73
  50. package/dist/prod/core/owner.js +43 -39
  51. package/dist/prod/core/scheduler.js +319 -190
  52. package/dist/prod/core/verdict.js +67 -67
  53. package/dist/prod/index.js +9 -3
  54. package/dist/prod/map.js +292 -141
  55. package/dist/prod/signals.js +7 -10
  56. package/dist/prod/store/next/optimistic.js +140 -125
  57. package/dist/prod/store/next/projection.js +3 -3
  58. package/dist/prod/store/next/reconcile.js +87 -84
  59. package/dist/prod/store/next/store.js +524 -280
  60. package/dist/prod/store/next/target.js +32 -10
  61. package/dist/prod/store/store.js +12 -14
  62. package/dist/prod/store/utils.js +36 -27
  63. package/dist/types/attribution.d.ts +15 -0
  64. package/dist/types/attribution.prod.d.ts +13 -0
  65. package/dist/types/core/async.d.ts +1 -1
  66. package/dist/types/core/attribution-hooks.d.ts +119 -6
  67. package/dist/types/core/attribution.d.ts +208 -53
  68. package/dist/types/core/constants.d.ts +23 -0
  69. package/dist/types/core/core.d.ts +7 -0
  70. package/dist/types/core/dev.d.ts +124 -26
  71. package/dist/types/core/effect.d.ts +8 -1
  72. package/dist/types/core/index.d.ts +2 -1
  73. package/dist/types/core/lanes.d.ts +8 -1
  74. package/dist/types/core/scheduler.d.ts +60 -0
  75. package/dist/types/core/types.d.ts +29 -9
  76. package/dist/types/index.d.ts +9 -2
  77. package/dist/types/map.d.ts +2 -0
  78. package/dist/types/store/index.d.ts +1 -0
  79. package/dist/types/store/next/store.d.ts +5 -0
  80. package/dist/types/store/next/target.d.ts +36 -9
  81. package/dist/types/store/utils.d.ts +7 -0
  82. package/package.json +21 -17
  83. package/dist/node.cjs +0 -10541
  84. package/dist/node.dev.cjs +0 -13724
  85. package/dist/types-cjs/affects.d.cts +0 -47
  86. package/dist/types-cjs/boundaries.d.cts +0 -175
  87. package/dist/types-cjs/core/action.d.cts +0 -64
  88. package/dist/types-cjs/core/async.d.cts +0 -23
  89. package/dist/types-cjs/core/attribution-hooks.d.cts +0 -127
  90. package/dist/types-cjs/core/attribution.d.cts +0 -495
  91. package/dist/types-cjs/core/core.d.cts +0 -185
  92. package/dist/types-cjs/core/dev.d.cts +0 -136
  93. package/dist/types-cjs/core/effect.d.cts +0 -30
  94. package/dist/types-cjs/core/error.d.cts +0 -56
  95. package/dist/types-cjs/core/external.d.cts +0 -15
  96. package/dist/types-cjs/core/graph.d.cts +0 -28
  97. package/dist/types-cjs/core/heap.d.cts +0 -24
  98. package/dist/types-cjs/core/index.d.cts +0 -13
  99. package/dist/types-cjs/core/invariants.d.cts +0 -59
  100. package/dist/types-cjs/core/lanes.d.cts +0 -54
  101. package/dist/types-cjs/core/optimistic.d.cts +0 -6
  102. package/dist/types-cjs/core/owner.d.cts +0 -124
  103. package/dist/types-cjs/core/scheduler.d.cts +0 -236
  104. package/dist/types-cjs/core/types.d.cts +0 -204
  105. package/dist/types-cjs/core/verdict.d.cts +0 -2
  106. package/dist/types-cjs/index.d.cts +0 -10
  107. package/dist/types-cjs/map.d.cts +0 -69
  108. package/dist/types-cjs/package.json +0 -3
  109. package/dist/types-cjs/store/index.d.cts +0 -18
  110. package/dist/types-cjs/store/next/optimistic.d.cts +0 -25
  111. package/dist/types-cjs/store/next/projection.d.cts +0 -8
  112. package/dist/types-cjs/store/next/reconcile.d.cts +0 -10
  113. package/dist/types-cjs/store/next/store.d.cts +0 -121
  114. package/dist/types-cjs/store/next/target.d.cts +0 -166
  115. package/dist/types-cjs/store/store.d.cts +0 -143
  116. package/dist/types-cjs/store/storePath.d.cts +0 -58
  117. package/dist/types-cjs/store/utils.d.cts +0 -74
@@ -1,6 +1,6 @@
1
1
  import { releaseFlightTeardown, handleAsync, clearStatus, parkLoadingWindow, notifyStatus, settlePendingSource, settleErroredDependents } from "./async.js";
2
2
 
3
- import { EFFECT_TRACKED, EFFECT_USER, REACTIVE_OPTIMISTIC_DIRTY, CONFIG_OPTIMISTIC, NOT_PENDING, STATUS_UNINITIALIZED, STATUS_ERROR, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, CONFIG_SYNC, CONFIG_HAS_LANE, STATUS_PENDING, REACTIVE_MISSED_WAKE, REACTIVE_NONE, REACTIVE_SNAPSHOT_STALE, unwrapOverride, CONFIG_DIRECT_COMMIT, OVERRIDE_UNDEFINED, CONFIG_AUTHORITATIVE_OBSERVED, CONFIG_HAS_COMPANIONS, REACTIVE_LAZY, REACTIVE_DISPOSED, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_FRESH_READ, CONFIG_AUTHORITATIVE_READ, CONFIG_HELD_TRUTH, REACTIVE_CHECK, REACTIVE_DIRTY, REACTIVE_IN_HEAP, REACTIVE_IN_HEAP_HEIGHT, defaultContext, CONFIG_IN_SNAPSHOT_SCOPE, CONFIG_TRANSPARENT, CONFIG_OWNED_WRITE, CONFIG_NO_SNAPSHOT, CONFIG_FW_CHILDREN, NO_SNAPSHOT, CONFIG_HAS_SNAPSHOT, REACTIVE_MANUAL_WRITE, CONFIG_SLOT_NODE, STORE_SNAPSHOT_PROPS } from "./constants.js";
3
+ import { EFFECT_TRACKED, EFFECT_USER, REACTIVE_OPTIMISTIC_DIRTY, CONFIG_OPTIMISTIC, NOT_PENDING, STATUS_UNINITIALIZED, STATUS_ERROR, STATUS_PENDING, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, CONFIG_SYNC, CONFIG_HAS_LANE, REACTIVE_MISSED_WAKE, REACTIVE_NONE, REACTIVE_SNAPSHOT_STALE, unwrapOverride, CONFIG_DIRECT_COMMIT, OVERRIDE_UNDEFINED, CONFIG_HAS_COMPANIONS, REACTIVE_LAZY, REACTIVE_DISPOSED, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_FRESH_READ, CONFIG_INPUTS_PUBLISHED, CONFIG_AUTHORITATIVE_READ, CONFIG_OVERRIDE_SUPERSEDED, CONFIG_AUTHORITATIVE_OBSERVED, CONFIG_HELD_TRUTH, REACTIVE_CHECK, REACTIVE_DIRTY, REACTIVE_IN_HEAP, REACTIVE_IN_HEAP_HEIGHT, defaultContext, CONFIG_IN_SNAPSHOT_SCOPE, CONFIG_TRANSPARENT, CONFIG_OWNED_WRITE, CONFIG_NO_SNAPSHOT, NO_SNAPSHOT, CONFIG_HAS_SNAPSHOT, REACTIVE_MANUAL_WRITE, CONFIG_FW_CHILDREN, CONFIG_SLOT_NODE, STORE_SNAPSHOT_PROPS } from "./constants.js";
4
4
 
5
5
  import { NotReadyError } from "./error.js";
6
6
 
@@ -8,7 +8,7 @@ import { trimStaleDeps, link, dormantNodes } from "./graph.js";
8
8
 
9
9
  import { deleteFromHeap, queueFor, insertIntoHeapHeight, enqueueSub, markNode, markHeap, insertIntoHeap } from "./heap.js";
10
10
 
11
- import { GlobalQueue, bumpNotifyEpoch, activeTransition, globalQueue, clock, insertSubs, queuePendingNode, runInTransition, schedule, notifyEpoch, dirtyQueue, projectionWriteActive, reaskArmed, armReaskClear } from "./scheduler.js";
11
+ import { GlobalQueue, bumpNotifyEpoch, activeTransition, globalQueue, clock, currentTransition, insertSubs, queuePendingNode, runInTransition, schedule, notifyEpoch, dirtyQueue, projectionWriteActive, reaskArmed, armReaskClear } from "./scheduler.js";
12
12
 
13
13
  import "./invariants.js";
14
14
 
@@ -23,14 +23,14 @@ import { disposeChildren, markDisposal, inheritId } from "./owner.js";
23
23
  // directly into the user queue ran in the SAME pass, read the old value, and
24
24
  // nothing re-notified it when the value landed (#3291).
25
25
  GlobalQueue.Fe = e => {
26
- if (e.ge === EFFECT_TRACKED) {
26
+ if (e.Ce === EFFECT_TRACKED) {
27
27
  deleteFromHeap(e, queueFor(e));
28
28
  e.He = true;
29
29
  e.C.enqueue(EFFECT_USER, e.Ve);
30
30
  } else recompute(e);
31
31
  };
32
32
 
33
- GlobalQueue.ke = disposeChildren;
33
+ GlobalQueue.We = disposeChildren;
34
34
 
35
35
  let tracking = false;
36
36
 
@@ -62,8 +62,8 @@ let snapshotSources = null;
62
62
 
63
63
  function ownerInSnapshotScope(e) {
64
64
  while (e) {
65
- if (e.xe) return true;
66
- e = e.Le;
65
+ if (e.Me) return true;
66
+ e = e.qe;
67
67
  }
68
68
  return false;
69
69
  }
@@ -74,20 +74,20 @@ function setSnapshotCapture(e) {
74
74
  }
75
75
 
76
76
  function markSnapshotScope(e) {
77
- e.xe = true;
77
+ e.Me = true;
78
78
  }
79
79
 
80
80
  function releaseSnapshotScope(e) {
81
- e.xe = false;
81
+ e.Me = false;
82
82
  releaseSubtree(e);
83
83
  schedule();
84
84
  }
85
85
 
86
86
  function releaseSubtree(e) {
87
- let t = e.Qe;
87
+ let t = e.Ye;
88
88
  while (t) {
89
- if (t.xe) {
90
- t = t.We;
89
+ if (t.Me) {
90
+ t = t.Ze;
91
91
  continue;
92
92
  }
93
93
  if (t.oe) {
@@ -96,19 +96,19 @@ function releaseSubtree(e) {
96
96
  if (e.ie & REACTIVE_SNAPSHOT_STALE) {
97
97
  e.ie &= ~REACTIVE_SNAPSHOT_STALE;
98
98
  e.ie |= REACTIVE_DIRTY;
99
- if (dirtyQueue.Me > e.qe) dirtyQueue.Me = e.qe;
99
+ if (dirtyQueue.Ke > e.Be) dirtyQueue.Ke = e.Be;
100
100
  insertIntoHeap(e, dirtyQueue);
101
101
  }
102
102
  }
103
103
  releaseSubtree(t);
104
- t = t.We;
104
+ t = t.Ze;
105
105
  }
106
106
  }
107
107
 
108
108
  function clearSnapshots() {
109
109
  if (snapshotSources) {
110
110
  for (const e of snapshotSources) {
111
- delete e.o?.Ye;
111
+ delete e.o?.ze;
112
112
  // StoreNode targets share one pre-initialized hidden class (see
113
113
  // createStoreProxy) — assign undefined instead of deleting, and only
114
114
  // when present so signal-node sources don't grow the field.
@@ -122,12 +122,12 @@ function clearSnapshots() {
122
122
  function recompute(e, t = false) {
123
123
  // §12d: any recompute can clean a marked subscriber — invalidate skips.
124
124
  bumpNotifyEpoch();
125
- const n = e.ge;
125
+ const n = e.Ce;
126
126
  if (!t) {
127
- if (e.Ae && (!n || activeTransition) && activeTransition !== e.Ae) globalQueue.initTransition(e.Ae);
127
+ if (e.ge && (!n || activeTransition) && activeTransition !== e.ge) globalQueue.initTransition(e.ge);
128
128
  deleteFromHeap(e, queueFor(e));
129
129
  if (e.o !== null) {
130
- e.o.Ie = null;
130
+ e.o.Pe = null;
131
131
  // Supersede is where an iterator flight dies (#3122): close it now.
132
132
  // Its cleanup(close) registration may sit in a zombie-deferred
133
133
  // disposal list that a held transition only drains when the
@@ -136,49 +136,50 @@ function recompute(e, t = false) {
136
136
  releaseFlightTeardown(e);
137
137
  }
138
138
  // Tracked effects run after finalizePureQueue, so dispose immediately instead of deferring
139
- if (e.Ae || n === EFFECT_TRACKED) disposeChildren(e); else if (e.Qe !== null || e.Ge !== null) {
139
+ if (e.ge || n === EFFECT_TRACKED) disposeChildren(e); else if (e.Ye !== null || e.we !== null) {
140
140
  markDisposal(e);
141
141
  const t = ext(e);
142
- t.Ze = e.Ge;
143
- t.Ke = e.Qe;
144
- e.Ge = null;
145
- e.Qe = null;
146
- e.je = 0;
142
+ t.Je = e.we;
143
+ t.Xe = e.Ye;
144
+ e.we = null;
145
+ e.Ye = null;
146
+ e.$e = 0;
147
147
  } else ;
148
148
  }
149
149
  let i = !!(e.ie & REACTIVE_OPTIMISTIC_DIRTY);
150
- const u = (e.T & CONFIG_OPTIMISTIC) !== 0 && e.o?.Pe !== NOT_PENDING && e.o?.Pe !== undefined;
151
- const l = !!(e.S & STATUS_UNINITIALIZED);
152
- // Outgoing error, captured before the compute clears status: if this run
153
- // recovers to an unchanged value, dependents still holding this object must
154
- // be swept (settleErroredDependents, #2949).
150
+ const l = (e.T & CONFIG_OPTIMISTIC) !== 0 && e.o?.be !== NOT_PENDING && e.o?.be !== undefined;
151
+ const u = !!(e.S & STATUS_UNINITIALIZED);
152
+ // Capture both error and pending status before the compute clears them.
153
+ // A conditional can drop its pending source and recover to an unchanged
154
+ // value, leaving blocked dependents outside that source’s settle walk.
155
155
  const o = e.S & STATUS_ERROR ? e.o?._ : undefined;
156
+ const s = e.S & STATUS_PENDING ? e.o?.le : undefined;
156
157
  // Pending SOURCE-hood, captured before the compute clears status: a node
157
158
  // whose own flight parked dependents self-registers in _pendingSources
158
159
  // (notifyStatus, isSource). If this recompute supersedes that flight and
159
160
  // settles synchronously, those dependents settle HERE — asyncWrite's
160
161
  // settlePendingSource walk never runs for a landing that was preempted
161
162
  // (#3181).
162
- const s = e.o?.le?.has(e);
163
+ const a = e.o?.le?.has(e);
163
164
  // Re-ask classification lives in the verdict module; capture the flag before
164
165
  // the recompute wipes _flags below.
165
- const a = (e.ie & REACTIVE_REASK) !== 0;
166
+ const r = (e.ie & REACTIVE_REASK) !== 0;
166
167
  // Captured before the compute clears it on a sync landing: if that landing
167
168
  // is transition-held below, the window must stay open until the hold
168
169
  // commits (commitPendingNode) — a closed window plus a held value reads as
169
170
  // a pending frame to live observers of the verdict (#2990).
170
- const r = e.Ne;
171
+ const c = e.Ae;
171
172
  const _ = context;
172
173
  context = e;
173
- e.Be = null;
174
- e.ze++;
174
+ e.et = null;
175
+ e.tt++;
175
176
  e.ie = REACTIVE_RECOMPUTING_DEPS;
176
- e.Te = clock;
177
- let c = e.Re === NOT_PENDING ? e.be : e.Re;
178
- let f = e.qe;
177
+ e._e = clock;
178
+ let f = e.Ge === NOT_PENDING ? e.me : e.Ge;
179
+ let E = e.Be;
179
180
  let I = false;
180
- let E = tracking;
181
- let N = currentOptimisticLane;
181
+ let N = tracking;
182
+ let T = currentOptimisticLane;
182
183
  tracking = true;
183
184
  // A computed's fn establishes its OWN dependencies, so it must never run
184
185
  // inside a latest() read window: read() short-circuits through the
@@ -186,54 +187,61 @@ function recompute(e, t = false) {
186
187
  // computed) inside latest(fn) came out permanently dependency-less (#2926).
187
188
  // latestRead() already suspends the flag for its pull-recomputes; this
188
189
  // covers creation-time computes and flushes that run inside the window.
189
- const T = latestReadActive;
190
+ const d = latestReadActive;
190
191
  latestReadActive = false;
191
192
  // Lane posture lives with the engine: OPTIMISTIC_DIRTY is only ever set by
192
193
  // engine-driven paths, and _optimisticNodes is only pushed by
193
194
  // _optimisticWrite, so the hook is installed whenever either gate holds.
194
195
  if (i) {
195
- const t = GlobalQueue.Je(e, true);
196
+ const t = GlobalQueue.nt(e, true);
196
197
  if (t) currentOptimisticLane = t;
197
198
  // `false` = wake-only lane demotion: recompute plain so a mid-tick
198
199
  // latest()/isPending() pull stages instead of direct-committing (#3009).
199
200
  // The predicate lives with the engine (recomputeLane).
200
201
  else if (t === false) i = false;
201
- } else if (activeTransition && !t && activeTransition.Xe.length) {
202
+ } else if (activeTransition && !t && activeTransition.it.length) {
202
203
  // Lane adoption: parent-deeper-than-owned-child can run before its OPT-dirty
203
204
  // child propagates. Walk deps once and inherit the OPT lane so this node
204
205
  // recomputes under the right posture and propagates correctly.
205
- const t = GlobalQueue.Je(e, false);
206
+ const t = GlobalQueue.nt(e, false);
206
207
  if (t) {
207
208
  i = true;
208
209
  currentOptimisticLane = t;
209
210
  }
210
211
  }
211
212
  const S = n && n !== EFFECT_USER;
212
- const d = stale;
213
+ const A = stale;
213
214
  if (S) stale = true;
215
+ // An effect recorded for this transaction's commit replay (it once read a
216
+ // node the transaction held and showed the committed value) and now
217
+ // recomputing UNDER the transaction sees its staged view: the value this
218
+ // run produces is applied by the commit itself, and the stale recording
219
+ // would publish the frame a second time. Drop it; the reads below re-record
220
+ // if they are served the committed view again (a lane's committed read).
221
+ if (n && activeTransition !== null && activeTransition.lt.size) activeTransition.lt.delete(e);
214
222
  try {
215
223
  if (!false && e.T & CONFIG_SYNC) {
216
- c = e.oe(c);
217
- if (e.o !== null) e.o.Ie = null;
218
- e.Ne = false;
224
+ f = e.oe(f);
225
+ if (e.o !== null) e.o.Pe = null;
226
+ e.Ae = false;
219
227
  } else {
220
228
  // Snapshot `_inFlight` so we can detect whether `_fn` self-registered an async
221
229
  // subscription (e.g. `createProjection` calls `handleAsync` from inside its body
222
230
  // with a setter callback). In that case, the outer `handleAsync` call below would
223
231
  // clobber the fresh subscription, so we skip it and let the internally-registered
224
232
  // iteration drive updates.
225
- const t = e.o?.Ie;
226
- const n = e.oe(c);
233
+ const t = e.o?.Pe;
234
+ const n = e.oe(f);
227
235
  const i = typeof n === "object" && n !== null;
228
- const u = e.o?.Ie !== t;
229
- c = u || !i ? n : handleAsync(e, n);
230
- if (!u && !i) {
231
- if (e.o !== null) e.o.Ie = null;
236
+ const l = e.o?.Pe !== t;
237
+ f = l || !i ? n : handleAsync(e, n);
238
+ if (!l && !i) {
239
+ if (e.o !== null) e.o.Pe = null;
232
240
  // A sync (non-object) return is the first real answer; async-shaped
233
241
  // results clear inside handleAsync at their own landing points, and a
234
242
  // self-registered flight (inFlightChanged — projections) clears when
235
243
  // its internal handleAsync lands.
236
- e.Ne = false;
244
+ e.Ae = false;
237
245
  }
238
246
  }
239
247
  // On a status-free node clearStatus is a guaranteed no-op: every field
@@ -243,10 +251,10 @@ function recompute(e, t = false) {
243
251
  if (e.S !== 0 || e.o !== null) clearStatus(e, t);
244
252
  // _optimisticLane is only ever assigned by engine paths (CONFIG_HAS_LANE
245
253
  // is their sticky presence mark).
246
- if (e.T & CONFIG_HAS_LANE && e.o?.$e) GlobalQueue.et(e);
254
+ if (e.T & CONFIG_HAS_LANE && e.o?.Oe) GlobalQueue.ut(e);
247
255
  } catch (t) {
248
256
  const n = t instanceof NotReadyError;
249
- if (n && e.Ne) {
257
+ if (n && e.Ae) {
250
258
  // Loading window with an unready sync dependency: register for the
251
259
  // source's settle (the settlePendingSource walk runs off
252
260
  // _pendingSources + _blocked alone) but take NO read-visible pending
@@ -258,22 +266,22 @@ function recompute(e, t = false) {
258
266
  } else {
259
267
  // Track pending async in the lane (not the lane's source — it creates the lane
260
268
  // but doesn't belong to it). Set lane BEFORE notifyStatus for downstream propagation.
261
- if (n && currentOptimisticLane) GlobalQueue.tt(e);
269
+ if (n && currentOptimisticLane) GlobalQueue.ot(e);
262
270
  let i = false;
263
271
  if (n) {
264
- ext(e).fe = true;
265
- if (GlobalQueue.nt !== null) i = GlobalQueue.nt(e, a);
272
+ ext(e).de = true;
273
+ if (GlobalQueue.st !== null) i = GlobalQueue.st(e, r);
266
274
  }
267
- notifyStatus(e, n ? STATUS_PENDING : STATUS_ERROR, t, undefined, n ? e.o?.$e : undefined);
275
+ notifyStatus(e, n ? STATUS_PENDING : STATUS_ERROR, t, undefined, n ? e.o?.Oe : undefined);
268
276
  // The replacement source is fully propagated now. If no new flight
269
277
  // re-owned self, retire the superseded flight and its dependent copies.
270
- if (n && s && !e.o?.Ie) settlePendingSource(e);
278
+ if (n && a && !e.o?.Pe) settlePendingSource(e);
271
279
  if (i) GlobalQueue.k(e);
272
280
  }
273
281
  } finally {
274
- tracking = E;
275
- latestReadActive = T;
276
- if (S) stale = d;
282
+ tracking = N;
283
+ latestReadActive = d;
284
+ if (S) stale = A;
277
285
  // Consume the missed-wake latch (#3037, set by insertSubs): a dep write
278
286
  // landed beneath this pass on a link it had already validated. The wipe
279
287
  // below must not key off DIRTY/CHECK — the read-time pull protocol
@@ -285,10 +293,16 @@ function recompute(e, t = false) {
285
293
  }
286
294
  if (!e.o?._) {
287
295
  trimStaleDeps(e);
288
- const a = u ? unwrapOverride(e.o?.Pe) : e.Re === NOT_PENDING ? e.be : e.Re;
296
+ // INV-11 (#3330): the equality gate compares against the slot this run
297
+ // publishes to. An override-covered node publishes the override; a lane
298
+ // recompute (OPT-dirty) direct-commits `_value` — the lane's own reveal
299
+ // schedule — so a transaction-held `_pendingValue` that already equals
300
+ // the new result is not "unchanged": the screen still shows `_value`.
301
+ // Only a transaction-staged run compares against `_pendingValue`.
302
+ const r = l ? unwrapOverride(e.o?.be) : i || e.Ge === NOT_PENDING ? e.me : e.Ge;
289
303
  let _ = false;
290
304
  try {
291
- _ = !n && l || !e.pe || !e.pe(a, c);
305
+ _ = !n && u || !e.ve || !e.ve(r, f);
292
306
  } catch (t) {
293
307
  // A throwing user comparator is an error of this node's computation.
294
308
  // Route it through the same status path as a compute-phase throw so
@@ -305,10 +319,33 @@ function recompute(e, t = false) {
305
319
  e.He = !e.o?._;
306
320
  // Reuse one bound runner per effect — runEffect no-ops on a stale
307
321
  // `_modified`, so re-enqueueing the same function is harmless.
308
- if (!t) e.C.enqueue(n, e.it ??= GlobalQueue.ut.bind(null, e));
322
+ if (!t) {
323
+ e.C.enqueue(n, e.rt ??= GlobalQueue.ct.bind(null, e));
324
+ // Contested effect (#3322). Effects don't entangle transactions (a
325
+ // shared effect is not shared state), yet they have one value slot:
326
+ // when this write commits under a different transaction
327
+ // (`activeTransition`, null = mainline) than the one that produced the
328
+ // previous value (`_valueTransition`), that view is gone. Rather than
329
+ // merge the two, each commit re-derives the effect against its own
330
+ // committed world (Transition._contested, re-dirtied by
331
+ // finalizePureQueue ahead of the heap run). The previous owner always
332
+ // needs it if still live: its commit is silent (staging already
333
+ // notified) and the value it computed is gone. The new owner needs it
334
+ // too, for the same reason, unless it is mainline — mainline publishes
335
+ // what it computes. A previous owner that was mainline, or already
336
+ // committed, left nothing to protect.
337
+ let t = e._t;
338
+ if (t !== activeTransition) {
339
+ e._t = activeTransition;
340
+ if (t !== null && (t = currentTransition(t)) !== activeTransition && !t.ft) {
341
+ (t.Et ??= []).push(e);
342
+ if (activeTransition !== null) (activeTransition.Et ??= []).push(e);
343
+ }
344
+ }
345
+ }
309
346
  }
310
347
  if (e.o?._) ; else if (_) {
311
- const l = u ? e.o?.Pe : undefined;
348
+ const u = l ? e.o?.be : undefined;
312
349
  if (t ||
313
350
  // Plain sync flush (no transition on either side) commits effect
314
351
  // values directly — the pending round-trip (queuePendingNode +
@@ -318,48 +355,62 @@ function recompute(e, t = false) {
318
355
  // their own held transition: their applies deliver on a microtask,
319
356
  // not the stashed queues, so a staged value would hand the immediate
320
357
  // apply stale state — see CONFIG_DIRECT_COMMIT.
321
- n && (activeTransition !== e.Ae || activeTransition === null || e.T & CONFIG_DIRECT_COMMIT) || i) {
322
- e.be = c;
358
+ n && (activeTransition !== e.ge || activeTransition === null || e.T & CONFIG_DIRECT_COMMIT) || i) {
359
+ e.me = f;
323
360
  // Lane-propagated correction: upstream data is fresh, correct the
324
361
  // override unconditionally. The direct _value commit is the lane's
325
362
  // own reveal schedule; drop any superseded older hold so its queued
326
363
  // commit can't clobber the fresh value.
327
- if (u && i) {
328
- ext(e).Pe = c === undefined ? OVERRIDE_UNDEFINED : c;
329
- e.Re = NOT_PENDING;
364
+ if (l && i) {
365
+ ext(e).be = f === undefined ? OVERRIDE_UNDEFINED : f;
366
+ e.Ge = NOT_PENDING;
330
367
  }
331
368
  } else {
332
- e.Re = c;
369
+ e.Ge = f;
333
370
  // A window landing that gets held re-opens the window until the hold
334
371
  // commits — the verdict's held-value branch is window-gated (#2990).
335
- if (r) e.Ne = true;
372
+ if (c) e.Ae = true;
336
373
  // Transition-held sync recompute is a write path like setSignal/asyncWrite,
337
374
  // so sync derivations of held sources stay visible to isPending()/latest()
338
375
  // (#2831). Both companion writes are transition-scoped (optimistic) and
339
376
  // auto-revert/re-derive at commit. Skipped for plain flushes where the
340
377
  // pending value commits before effects run.
341
- if ((activeTransition || e.Ae) && GlobalQueue.Ue !== null) GlobalQueue.Ue(e, c);
378
+ if ((activeTransition || e.ge) && GlobalQueue.pe !== null) GlobalQueue.pe(e, f);
342
379
  }
343
380
  // insertSubs only walks _subs (no scheduling of its own), so a
344
381
  // subscriber-less node has nothing to notify.
345
- if (e.u !== null && (!u || i || e.o?.Pe !== l)) insertSubs(e, i || u);
346
- } else if (u) {
382
+ if (e.u !== null && (!l || i || e.o?.be !== u)) insertSubs(e, i || l);
383
+ // A18 supersession, sync twin of asyncWrite's override branch (#3331):
384
+ // this pass published truth that differs from the override (the gate
385
+ // compared against it) into the transaction-held slot. Whether the
386
+ // source is this node's own async or an upstream node it derives from
387
+ // synchronously makes no difference — "the source recomputed". The
388
+ // override stays displayed until the commit; the graph moves to the
389
+ // staged truth now (plain channel, lane demoted). Ordering: "a new
390
+ // value from the source" postdates the override — an override written
391
+ // in this same tick (optimisticWrite stamps `_overrideTime`) is the
392
+ // newer intent over whatever this pass derives from the batch's staged
393
+ // inputs, and is not superseded by it.
394
+ else if (l && !i && e.o.It !== clock) GlobalQueue.ye(e, f);
395
+ } else if (l) {
347
396
  // Unchanged value (equals the override) recomputed while the override
348
397
  // is active: _value may still be stale, so hold the authoritative value
349
398
  // for commit on its own transition's schedule — invisibly (A17/A18).
350
- if (e.Re === NOT_PENDING) queuePendingNode(e);
351
- e.Re = c;
352
- if (r) e.Ne = true;
399
+ if (e.Ge === NOT_PENDING) queuePendingNode(e);
400
+ e.Ge = f;
401
+ if (c) e.Ae = true;
353
402
  // see the held branch above (#2990)
354
- // An authoritative-view reader (until()'s predicate, refresh()'s waiter)
355
- // observed this node past its override and "authoritative arrival
356
- // equal to the override" is exactly the acknowledgment it waits for.
357
- // Wake those readers only; A17 silence holds for every ordinary
358
- // subscriber. (Hook installed by both setters of the gating bit, #3303.)
359
- if (e.T & CONFIG_AUTHORITATIVE_OBSERVED) GlobalQueue.he(e);
360
- } else if (e.qe != f) {
361
- for (let t = e.u; t !== null; t = t.ae) {
362
- insertIntoHeapHeight(t.ce, queueFor(t.ce));
403
+ // A confirmation after a supersession restores the override as the
404
+ // graph's value and notifies; a plain confirmation wakes only an
405
+ // authoritative-view reader (until()'s predicate, refresh()'s waiter)
406
+ // that observed this node past its override "authoritative arrival
407
+ // equal to the override" is exactly the acknowledgment it waits for;
408
+ // A17 silence holds for every ordinary subscriber. Both live in the
409
+ // engine's supersedeOverride.
410
+ GlobalQueue.ye(e, f);
411
+ } else if (e.Be != E) {
412
+ for (let t = e.u; t !== null; t = t.Te) {
413
+ insertIntoHeapHeight(t.Ie, queueFor(t.Ie));
363
414
  }
364
415
  }
365
416
  // Silent recovery: errored → unchanged value fires no notification, but
@@ -367,21 +418,26 @@ function recompute(e, t = false) {
367
418
  // in an errored run and may sit on stale commits (#2949). Changed-value
368
419
  // recoveries ride insertSubs above; a comparator throw re-errored the node
369
420
  // (el._x?._error re-set), so this only runs on a genuinely clean recovery.
370
- if (o !== undefined && !_ && !e.o?._) settleErroredDependents(e, o);
421
+ if (!_ && !e.o?._) {
422
+ if (o !== undefined) settleErroredDependents(e, o);
423
+ // Self-registration (this node's own superseded flight) is the #3181
424
+ // sweep's business below — retiring it here too would walk twice.
425
+ if (s) for (const t of s) if (t !== e) settlePendingSource(e, t);
426
+ }
371
427
  // #3181: a synchronous settle supersedes the old landing callback, so
372
428
  // recompute owns its pending-source sweep. An uninitialized node without
373
429
  // a replacement source still has no truth to reveal and must stay parked.
374
- if (s && !(e.S & (STATUS_PENDING | STATUS_UNINITIALIZED))) settlePendingSource(e);
430
+ if (a && !(e.S & (STATUS_PENDING | STATUS_UNINITIALIZED))) settlePendingSource(e);
375
431
  }
376
- currentOptimisticLane = N;
377
- const A = e.Re !== NOT_PENDING || e.o !== null && (e.o.Ke !== null || e.o.Ze !== null) || (e.S & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
432
+ currentOptimisticLane = T;
433
+ const C = e.Ge !== NOT_PENDING || e.o !== null && (e.o.Xe !== null || e.o.Je !== null) || (e.S & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
378
434
  // Override-covered holds (hasOverride) always queue: their commit belongs
379
435
  // to their own transition's schedule (A18 re-rule) and is unobservable
380
436
  // under the override (A17). Revert no longer commits anything, so an
381
437
  // unqueued covered hold would leak (INV-7) once the revert clears
382
438
  // _transition.
383
- A && (!t || e.S & STATUS_PENDING) && (!e.Ae || u) && queuePendingNode(e);
384
- e.Ae && n && activeTransition !== e.Ae && runInTransition(e.Ae, () => recompute(e));
439
+ C && (!t || e.S & STATUS_PENDING) && (!e.ge || l) && queuePendingNode(e);
440
+ e.ge && n && activeTransition !== e.ge && runInTransition(e.ge, () => recompute(e));
385
441
  // Missed-wake reschedule (see the finally above): values this pass read
386
442
  // before the nested commit are stale, so run again now that the heap will
387
443
  // accept the node. Equality gates stop same-value landings from cascading,
@@ -402,9 +458,9 @@ function updateIfNecessary(e) {
402
458
  // would resurrect it (#2983) — readers serve its last value.
403
459
  if (e.ie & (REACTIVE_RECOMPUTING_DEPS | REACTIVE_DISPOSED)) return;
404
460
  if (e.ie & REACTIVE_CHECK) {
405
- for (let t = e.lt; t; t = t.ot) {
406
- const n = t.st;
407
- const i = n.rt || n;
461
+ for (let t = e.fe; t; t = t.ae) {
462
+ const n = t.Se;
463
+ const i = n.ce || n;
408
464
  if (i.oe) {
409
465
  updateIfNecessary(i);
410
466
  }
@@ -413,7 +469,7 @@ function updateIfNecessary(e) {
413
469
  }
414
470
  }
415
471
  }
416
- if (e.ie & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.o?._ && e.Te < clock && !e.o?.Ie) {
472
+ if (e.ie & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.o?._ && e._e < clock && !e.o?.Pe) {
417
473
  recompute(e);
418
474
  }
419
475
  e.ie = e.ie & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
@@ -425,45 +481,53 @@ function computed(e, t) {
425
481
  // `T | undefined` node is a real commit #0. The typeof guard tolerates
426
482
  // non-object option values that older call shapes force through `as any`.
427
483
  const i = t !== null && typeof t === "object" && "loadingValue" in t;
428
- const u = {
484
+ // Two literals, one per tier, selected at build time (the observe flag is
485
+ // a literal after replacement; the untaken branch is dead code). The observe
486
+ // literal is the prod literal plus its `_name` slot — a slot in the
487
+ // boilerplate, because a post-construction `self._name = …` forces a
488
+ // hidden-class transition and an out-of-object property store on EVERY node
489
+ // (measured: the whole of the observe tier's creation overhead). Keep the
490
+ // two in sync — the dist artifact test pins observe's key set to prod's
491
+ // plus `_name`.
492
+ const l = {
429
493
  id: inheritId(t, n, context),
430
494
  T: (n ? CONFIG_TRANSPARENT : 0) | (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (!context || t?.lazy ? CONFIG_AUTO_DISPOSE : 0) | (t?.sync ? CONFIG_SYNC : 0) | (t?.H ? CONFIG_NO_SNAPSHOT : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
431
- pe: t?.equals ?? isEqual,
432
- Ge: null,
495
+ ve: t?.equals ?? isEqual,
496
+ we: null,
433
497
  C: context?.C ?? globalQueue,
434
- we: context?.we ?? defaultContext,
435
- je: 0,
498
+ xe: context?.xe ?? defaultContext,
499
+ $e: 0,
436
500
  oe: e,
437
- be: i ? t.loadingValue : undefined,
438
- qe: 0,
439
- _t: undefined,
440
- ct: null,
441
- lt: null,
442
- Be: null,
443
- ze: 0,
501
+ me: i ? t.loadingValue : undefined,
502
+ Be: 0,
503
+ Nt: undefined,
504
+ Tt: null,
505
+ fe: null,
506
+ et: null,
507
+ tt: 0,
444
508
  u: null,
445
- ft: null,
446
- Le: context,
447
- We: null,
448
- It: null,
449
- Qe: null,
509
+ dt: null,
510
+ qe: context,
511
+ Ze: null,
512
+ St: null,
513
+ Ye: null,
450
514
  ie: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
451
515
  // A loadingValue node is born committed: commit #0 is already in _value.
452
516
  S: i ? 0 : STATUS_UNINITIALIZED,
453
- Te: clock,
454
- Re: NOT_PENDING,
455
- Ae: null,
456
- Et: -1,
457
- Ne: i,
517
+ _e: clock,
518
+ Ge: NOT_PENDING,
519
+ ge: null,
520
+ At: -1,
521
+ Ae: i,
458
522
  // Cold machinery (async/transition/optimistic/verdict slots) lives one
459
523
  // hop away in the lazily-allocated extension — the core literal MUST
460
524
  // stay under V8's in-object boundary (§12: past ~39 fields every
461
525
  // allocation spills to a backing store and creation cost ~4x's).
462
526
  o: null
463
527
  };
464
- if (t?.unobserved) ext(u).Nt = t.unobserved;
465
- setupComputedNode(u, t);
466
- return u;
528
+ if (t?.unobserved) ext(l).Ct = t.unobserved;
529
+ setupComputedNode(l, t);
530
+ return l;
467
531
  }
468
532
 
469
533
  /** Lazily allocate a node's cold extension (ONE shape for signals and
@@ -471,26 +535,28 @@ function computed(e, t) {
471
535
  * this; hot paths read `el._x?._field` gated by the _config presence bits.
472
536
  * Never call ext() just to store a field's default. */ function ext(e) {
473
537
  return e.o ??= {
474
- Pe: undefined,
475
- Tt: undefined,
476
- $e: undefined,
477
- ye: undefined,
478
- Ce: undefined,
479
- St: undefined,
538
+ be: undefined,
539
+ Ot: undefined,
540
+ It: 0,
541
+ Rt: 0,
542
+ Oe: undefined,
543
+ Le: undefined,
544
+ Qe: undefined,
545
+ Gt: undefined,
480
546
  t: 0,
481
- Ie: null,
482
- Ee: null,
547
+ Pe: null,
548
+ De: null,
483
549
  _: undefined,
484
- fe: undefined,
550
+ de: undefined,
485
551
  le: undefined,
486
552
  h: undefined,
487
- De: false,
553
+ Ue: false,
488
554
  i: null,
489
- Nt: undefined,
490
- Ye: undefined,
491
- Ze: null,
492
- Ke: null,
493
- dt: undefined
555
+ Ct: undefined,
556
+ ze: undefined,
557
+ Je: null,
558
+ Xe: null,
559
+ Dt: undefined
494
560
  };
495
561
  }
496
562
 
@@ -499,43 +565,49 @@ function computed(e, t) {
499
565
  * so V8 sees the full hidden class shape at construction time. Effects always run in lazy
500
566
  * mode (recompute is called explicitly by `effect()`), so we hardcode the lazy bits and skip
501
567
  * the auto-dispose CONFIG bit (effect() previously cleared it post-construction).
502
- */ function createEffectNode(e, t, n, i, u) {
503
- const l = u?.transparent ?? false;
504
- const o = {
505
- id: inheritId(u, l, context),
506
- T: (l ? CONFIG_TRANSPARENT : 0) | (u?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (u?.sync ? CONFIG_SYNC : 0) | (u?.At ?? 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
507
- pe: false,
508
- Ge: null,
568
+ */ function createEffectNode(e, t, n, i, l) {
569
+ const u = l?.transparent ?? false;
570
+ // Prod and observe boilerplates — see computed() for why the observe tier
571
+ // gets its `_name` as a literal slot rather than a write after the fact.
572
+ // The default label is the node kind (tracked effects relabel their computed
573
+ // in trackedEffect); the wrappers in signals.ts no longer spread a name into
574
+ // the options to get it.
575
+ const o = {
576
+ id: inheritId(l, u, context),
577
+ T: (u ? CONFIG_TRANSPARENT : 0) | (l?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (l?.sync ? CONFIG_SYNC : 0) | (l?.Pt ?? 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
578
+ ve: false,
579
+ we: null,
509
580
  C: context?.C ?? globalQueue,
510
- we: context?.we ?? defaultContext,
511
- je: 0,
581
+ xe: context?.xe ?? defaultContext,
582
+ $e: 0,
512
583
  oe: e,
513
- be: undefined,
514
- qe: 0,
515
- _t: undefined,
516
- ct: null,
517
- lt: null,
518
- Be: null,
519
- ze: 0,
584
+ me: undefined,
585
+ Be: 0,
586
+ Nt: undefined,
587
+ Tt: null,
588
+ fe: null,
589
+ et: null,
590
+ tt: 0,
520
591
  u: null,
521
- ft: null,
522
- Le: context,
523
- We: null,
524
- It: null,
525
- Qe: null,
592
+ dt: null,
593
+ qe: context,
594
+ Ze: null,
595
+ St: null,
596
+ Ye: null,
526
597
  ie: REACTIVE_LAZY,
527
598
  S: STATUS_UNINITIALIZED,
528
- Te: clock,
529
- Re: NOT_PENDING,
530
- Ae: null,
531
- Et: -1,
532
- Ne: false,
599
+ _e: clock,
600
+ Ge: NOT_PENDING,
601
+ ge: null,
602
+ At: -1,
603
+ Ae: false,
533
604
  He: false,
534
- Ot: undefined,
535
- Ct: t,
536
- Rt: n,
537
- Gt: undefined,
538
- ge: i,
605
+ Ft: undefined,
606
+ ht: t,
607
+ vt: n,
608
+ Ht: undefined,
609
+ Ce: i,
610
+ _t: null,
539
611
  o: null
540
612
  };
541
613
  // Effects dispatch status through the SHARED notifier (statusNotifierOf,
@@ -543,7 +615,7 @@ function computed(e, t) {
543
615
  // allocation on EVERY effect at creation (an alloc + 19 field stores,
544
616
  // +23% effect creation, caught by the creation benches). Only genuinely
545
617
  // per-node channels (boundaries) live on _x.
546
- if (u?.unobserved) ext(o).Nt = u.unobserved;
618
+ if (l?.unobserved) ext(o).Ct = l.unobserved;
547
619
  setupComputedNode(o, lazyOptions);
548
620
  return o;
549
621
  }
@@ -566,7 +638,7 @@ function setEffectStatusNotify(e) {
566
638
  * per-node field did when every effect carried one. */ function statusNotifierOf(e) {
567
639
  const t = e.o?.h;
568
640
  if (t !== undefined) return t;
569
- return e.ge ? effectStatusNotify ?? undefined : undefined;
641
+ return e.Ce ? effectStatusNotify ?? undefined : undefined;
570
642
  }
571
643
 
572
644
  const lazyOptions = {
@@ -574,24 +646,24 @@ const lazyOptions = {
574
646
  };
575
647
 
576
648
  function setupComputedNode(e, t) {
577
- e.ct = e;
578
- const n = context?.Dt ? context.Pt : context;
649
+ e.Tt = e;
650
+ const n = context?.gt ? context.bt : context;
579
651
  if (context) {
580
- const t = context.Qe;
652
+ const t = context.Ye;
581
653
  if (t === null) {
582
- context.Qe = e;
654
+ context.Ye = e;
583
655
  } else {
584
- e.We = t;
585
- t.It = e;
586
- context.Qe = e;
656
+ e.Ze = t;
657
+ t.St = e;
658
+ context.Ye = e;
587
659
  }
588
660
  }
589
- if (n) e.qe = n.qe + 1;
590
- if (GlobalQueue.Ft !== null) GlobalQueue.Ft(e);
661
+ if (n) e.Be = n.Be + 1;
662
+ if (GlobalQueue.kt !== null) GlobalQueue.kt(e);
591
663
  !t?.lazy && recompute(e, true);
592
664
  if (snapshotCaptureActive && !t?.lazy) {
593
665
  if (!(e.S & STATUS_PENDING) && !(e.T & CONFIG_NO_SNAPSHOT)) {
594
- ext(e).Ye = e.be === undefined ? NO_SNAPSHOT : e.be;
666
+ ext(e).ze = e.me === undefined ? NO_SNAPSHOT : e.me;
595
667
  e.T |= CONFIG_HAS_SNAPSHOT;
596
668
  snapshotSources.add(e);
597
669
  }
@@ -599,32 +671,34 @@ function setupComputedNode(e, t) {
599
671
  }
600
672
 
601
673
  function signal(e, t, n = null) {
674
+ // Prod and observe boilerplates — see computed(). The observe literal adds
675
+ // `_name` and `_owner` (the creating owner, stamped by registerGraph for
676
+ // createSignal nodes so ownerPath can locate signal subjects; null here,
677
+ // and staying null on internal signals — one shape either way).
602
678
  const i = {
603
- pe: t?.equals ?? isEqual,
679
+ ve: t?.equals ?? isEqual,
604
680
  T: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.H ? CONFIG_NO_SNAPSHOT : 0),
605
- be: e,
681
+ me: e,
606
682
  u: null,
607
- ft: null,
608
- Te: clock,
609
- rt: n,
610
- Se: n?.o?.i || null,
611
- Re: NOT_PENDING,
683
+ dt: null,
684
+ _e: clock,
685
+ ce: n,
686
+ Ee: n?.o?.i || null,
687
+ Vt: null,
688
+ Ge: NOT_PENDING,
612
689
  // Signal-literal diet (§12e): NO _time/_fn/_statusFlags slots. Stores
613
690
  // materialize one signal per touched leaf, so signal bytes are store
614
691
  // bytes. _time is write-only on signals (every read site is computed-
615
692
  // typed error-retry gating); _fn/_statusFlags read falsy-identically as
616
693
  // missing properties on the shared paths (undefined masks to 0).
617
- Ae: null,
618
- Et: -1,
694
+ ge: null,
695
+ At: -1,
619
696
  o: null
620
697
  };
621
- if (t?.unobserved) ext(i).Nt = t.unobserved;
622
- if (n) {
623
- ext(n).i = i;
624
- n.T |= CONFIG_FW_CHILDREN;
625
- }
698
+ if (t?.unobserved) ext(i).Ct = t.unobserved;
699
+ if (n) linkFirewallChild(n, i);
626
700
  if (snapshotCaptureActive && !(i.T & CONFIG_NO_SNAPSHOT) && !((n?.S ?? 0) & STATUS_PENDING)) {
627
- ext(i).Ye = e === undefined ? NO_SNAPSHOT : e;
701
+ ext(i).ze = e === undefined ? NO_SNAPSHOT : e;
628
702
  i.T |= CONFIG_HAS_SNAPSHOT;
629
703
  snapshotSources.add(i);
630
704
  }
@@ -649,34 +723,60 @@ function signal(e, t, n = null) {
649
723
  slotUnobservedHook = e;
650
724
  }
651
725
 
652
- function slotSignal(e, t, n, i, u, l = null) {
726
+ /** Push a new node onto its firewall's child chain (the literal already
727
+ * points `_nextChild` at the old head). Doubly linked so a released leaf
728
+ * unlinks in O(1) — the chain is walked per mark of the projection and
729
+ * would otherwise grow by one node per leaf ever read (#3351). */ function linkFirewallChild(e, t) {
730
+ const n = t.Ee;
731
+ if (n !== null) n.Vt = t;
732
+ ext(e).i = t;
733
+ e.T |= CONFIG_FW_CHILDREN;
734
+ }
735
+
736
+ /** Release a firewall child the store no longer addresses (unobserved sweep
737
+ * dropped it from its target's cache): unlink it from the chain so the
738
+ * projection stops retaining it and its last value. The node keeps its own
739
+ * `_nextChild` so a walk that is mid-chain on it still terminates. Nodes in
740
+ * `_companionChildren` stay there — companions are permanent by contract
741
+ * and snap through that set, not the chain. */ function unlinkFirewallChild(e) {
742
+ const t = e;
743
+ const n = t.ce;
744
+ if (!n) return;
745
+ const i = t.Vt;
746
+ const l = t.Ee;
747
+ if (i !== null) i.Ee = l; else if (n.o.i === t) n.o.i = l;
748
+ if (l !== null) l.Vt = i;
749
+ t.Vt = null;
750
+ }
751
+
752
+ function slotSignal(e, t, n, i, l, u = null) {
753
+ // Prod and observe boilerplates — see computed(). The store relabels the
754
+ // observe slot (`store.<key>`) when the attribution engine is installed.
653
755
  const o = {
654
- pe: t,
756
+ ve: t,
655
757
  T: CONFIG_OWNED_WRITE | CONFIG_SLOT_NODE,
656
- be: e,
758
+ me: e,
657
759
  u: null,
658
- ft: null,
659
- Te: clock,
660
- rt: l,
661
- Se: l?.o?.i || null,
662
- Re: NOT_PENDING,
663
- Ae: null,
664
- Et: -1,
760
+ dt: null,
761
+ _e: clock,
762
+ ce: u,
763
+ Ee: u?.o?.i || null,
764
+ Vt: null,
765
+ Ge: NOT_PENDING,
766
+ ge: null,
767
+ At: -1,
665
768
  o: null,
666
769
  // Slot backrefs: what the equals/unobserved closures used to capture.
667
- ht: n,
668
- Ht: i,
770
+ Ut: n,
771
+ xt: i,
669
772
  // Store read-path caches, pre-shaped (were post-construction expandos).
670
- acc: u,
773
+ acc: l,
671
774
  px: undefined,
672
775
  pxv: undefined
673
776
  };
674
- if (l) {
675
- ext(l).i = o;
676
- l.T |= CONFIG_FW_CHILDREN;
677
- }
678
- if (snapshotCaptureActive && !((l?.S ?? 0) & STATUS_PENDING)) {
679
- ext(o).Ye = e === undefined ? NO_SNAPSHOT : e;
777
+ if (u) linkFirewallChild(u, o);
778
+ if (snapshotCaptureActive && !((u?.S ?? 0) & STATUS_PENDING)) {
779
+ ext(o).ze = e === undefined ? NO_SNAPSHOT : e;
680
780
  o.T |= CONFIG_HAS_SNAPSHOT;
681
781
  snapshotSources.add(o);
682
782
  }
@@ -685,14 +785,14 @@ function slotSignal(e, t, n, i, u, l = null) {
685
785
 
686
786
  function optimisticSignal(e, t) {
687
787
  const n = signal(e, t);
688
- ext(n).Pe = NOT_PENDING;
788
+ ext(n).be = NOT_PENDING;
689
789
  n.T |= CONFIG_OPTIMISTIC;
690
790
  return n;
691
791
  }
692
792
 
693
793
  function optimisticComputed(e, t) {
694
794
  const n = computed(e, t);
695
- ext(n).Pe = NOT_PENDING;
795
+ ext(n).be = NOT_PENDING;
696
796
  n.T |= CONFIG_OPTIMISTIC;
697
797
  return n;
698
798
  }
@@ -723,11 +823,11 @@ function isEqual(e, t) {
723
823
  * );
724
824
  * ```
725
825
  */ function untrack(e, t) {
726
- if (GlobalQueue.gt === null && !tracking && true) return e();
826
+ if (GlobalQueue.Lt === null && !tracking && true) return e();
727
827
  const n = tracking;
728
828
  tracking = false;
729
829
  try {
730
- if (GlobalQueue.gt !== null) return GlobalQueue.gt(e);
830
+ if (GlobalQueue.Lt !== null) return GlobalQueue.Lt(e);
731
831
  return e();
732
832
  } finally {
733
833
  tracking = n;
@@ -777,14 +877,14 @@ function isEqual(e, t) {
777
877
  * Pay-for-use: reached through GlobalQueue._notifyAuthoritativeObservers,
778
878
  * installed at first until() call — apps that never use until() shake it.
779
879
  */ function notifyAuthoritativeObservers(e) {
780
- for (let t = e.u; t !== null; t = t.ae) {
781
- const e = t.ce;
880
+ for (let t = e.u; t !== null; t = t.Te) {
881
+ const e = t.Ie;
782
882
  if (!(e.T & CONFIG_AUTHORITATIVE_READ)) continue;
783
883
  // Missed-wake latch (#3037), same contract as insertSubs: the reader may
784
884
  // itself have pulled this recompute (updateIfNecessary from its own
785
885
  // read), and the heap refuses RECOMPUTING nodes — latch so recompute's
786
886
  // tail reschedules it with the staged value visible.
787
- if (e.ie & REACTIVE_RECOMPUTING_DEPS && t.vt === e.ze && t !== e.Be) e.ie |= REACTIVE_MISSED_WAKE;
887
+ if (e.ie & REACTIVE_RECOMPUTING_DEPS && t.yt === e.tt && t !== e.et) e.ie |= REACTIVE_MISSED_WAKE;
788
888
  enqueueSub(e);
789
889
  }
790
890
  schedule();
@@ -795,19 +895,44 @@ function isEqual(e, t) {
795
895
  * before its first read (same late-binding contract as the optimistic engine;
796
896
  * the gating bit is only ever set by such a read, so the `!` call sites are
797
897
  * safe once every setter installs, #3303). */ function installAuthoritativeRead() {
798
- if (GlobalQueue.he === null) GlobalQueue.he = notifyAuthoritativeObservers;
898
+ if (GlobalQueue.Qt === null) GlobalQueue.Qt = notifyAuthoritativeObservers;
899
+ }
900
+
901
+ /**
902
+ * Stale-reader term of the value selections below: a render effect reading a
903
+ * node some OTHER live transaction has staged sees the committed value. The
904
+ * commit is silent — the staging walk was the notification — so a reader
905
+ * that linked AFTER that walk (an effect created during the hold, a store
906
+ * key first read under it) would show the old value past the reveal: record
907
+ * it for the transaction's commit replay (the `_gatedSubs` contract lanes
908
+ * already use). An effect the transaction itself computed re-derives at its
909
+ * commit on its own (parked run, or the contested re-derive, #3322) and is
910
+ * not recorded — replaying it too would publish the frame twice.
911
+ */ function heldFromStale(e, t) {
912
+ const n = e.ge;
913
+ if (n === null || n === activeTransition) return false;
914
+ const i = currentTransition(n);
915
+ const l = t._t;
916
+ if (l == null || currentTransition(l) !== i) i.lt.add(t);
917
+ return true;
799
918
  }
800
919
 
801
920
  function readNodeFast(e) {
802
- if (latestReadActive || pendingCheckActive || e.oe || e.rt || e.o?.Pe !== undefined || e.o?.Ye !== undefined || activeTransition !== null || currentOptimisticLane !== null || snapshotCaptureActive || false) return READ_SLOW;
921
+ if (latestReadActive || pendingCheckActive || e.oe || e.ce || e.o?.be !== undefined || e.o?.ze !== undefined || activeTransition !== null || currentOptimisticLane !== null || snapshotCaptureActive || false) return READ_SLOW;
803
922
  let t = context;
804
- if (t?.Dt) t = t.Pt;
923
+ if (t?.gt) t = t.bt;
805
924
  if (t && tracking) link(e, t);
806
925
  // Children-forbidden readers (createTrackedEffect / onSettled callbacks) get
807
926
  // committed visibility: like the effect half of createEffect and event
808
927
  // handlers, effect-phase code never observes its own unsettled write — the
809
928
  // write lands in the same flush's continuation (#3006).
810
- return !t || e.Re === NOT_PENDING || t.T & CONFIG_CHILDREN_FORBIDDEN ? e.be : e.Re;
929
+ // A stale reader (render effect) recomputing with no transaction active is
930
+ // mainline: a write staged by a live transaction (`_transition` stamped —
931
+ // ambient staging never is) stays masked until that transaction's reveal,
932
+ // the same rule the slow path applies (#3322). Without it a zombie
933
+ // recompute, or a commit-time re-derive of a contested effect, published
934
+ // another transaction's uncommitted value.
935
+ return !t || e.Ge === NOT_PENDING || t.T & CONFIG_CHILDREN_FORBIDDEN || stale && heldFromStale(e, t) ? e.me : e.Ge;
811
936
  }
812
937
 
813
938
  function read(e) {
@@ -815,33 +940,34 @@ function read(e) {
815
940
  // Checked before isPending so that isPending(() => latest(x)) checks
816
941
  // the _pendingSignal of _latestValueComputed (async in flight) rather
817
942
  // than the original node (which stays "pending" while held in a transition).
818
- if (latestReadActive) return GlobalQueue.Vt(e);
943
+ if (latestReadActive) return GlobalQueue.wt(e);
819
944
  let t = context;
820
- if (t?.Dt) t = t.Pt;
945
+ if (t?.gt) t = t.bt;
821
946
  const n = e;
822
- const i = e.rt;
823
- const u = i || e;
947
+ const i = e.ce;
948
+ const l = i || e;
824
949
  // Handle isPending() mode: collect pending state while preserving normal read semantics.
825
950
  // Probe mode is suspended while preparing the node so nested reads during a
826
951
  // recompute don't collect into the probe.
827
952
  if (pendingCheckActive) {
828
- GlobalQueue.bt(e, t, u, i);
953
+ GlobalQueue.Wt(e, t, l, i);
829
954
  } else if (typeof n.oe === "function") {
830
955
  prepareComputed(e, false);
831
956
  }
832
- if (!n.oe && u === e && e.o?.Pe === undefined && e.o?.Ye === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
957
+ if (!n.oe && l === e && e.o?.be === undefined && e.o?.ze === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
833
958
  if (t && tracking) link(e, t);
834
- // Committed visibility for children-forbidden readers see readNodeFast.
835
- return !t || e.Re === NOT_PENDING || t.T & CONFIG_CHILDREN_FORBIDDEN ? e.be : e.Re;
959
+ // Committed visibility for children-forbidden readers and for stale
960
+ // readers of a foreign transaction's staged write see readNodeFast.
961
+ return !t || e.Ge === NOT_PENDING || t.T & CONFIG_CHILDREN_FORBIDDEN || stale && heldFromStale(e, t) ? e.me : e.Ge;
836
962
  }
837
963
  if (t && tracking) {
838
964
  link(e, t, pendingCheckActive);
839
- if (u.oe) {
965
+ if (l.oe) {
840
966
  const n = queueFor(e);
841
- if (u.qe >= n.Me) {
967
+ if (l.Be >= n.Ke) {
842
968
  markNode(t);
843
969
  markHeap(n);
844
- updateIfNecessary(u);
970
+ updateIfNecessary(l);
845
971
  }
846
972
  // Fresh-pull readers (awaitable refresh's waiter) recompute a dirty
847
973
  // source inline even when the height gate defers to the flush: the
@@ -849,66 +975,69 @@ function read(e) {
849
975
  // never read the PRE-re-ask value as settled. Self-guarded: a clean
850
976
  // node no-ops and updateIfNecessary refuses disposed nodes (#2983) —
851
977
  // a dead target serves its last value, which is already quiescent.
852
- else if (t.T & CONFIG_FRESH_READ) updateIfNecessary(u);
853
- const i = u.qe;
978
+ else if (t.T & CONFIG_FRESH_READ) updateIfNecessary(l);
979
+ const i = l.Be;
854
980
  // parent check is shallow, might need to be recursive
855
- if (i >= t.qe && e.Le !== t) {
856
- t.qe = i + 1;
981
+ if (i >= t.Be && e.qe !== t) {
982
+ t.Be = i + 1;
857
983
  }
858
984
  }
859
985
  }
860
- if (u.S & STATUS_PENDING) {
861
- if (t && !(stale && u.Ae && activeTransition !== u.Ae)) {
986
+ if (l.S & STATUS_PENDING) {
987
+ // A reader landing on a pending node throws the reveal that discovered
988
+ // the flight holds on it (A15: observed async settles as one unit) — with
989
+ // one carve-out: a stale (render) reader of a node pending in some OTHER
990
+ // transaction keeps showing the node's committed value, no entanglement
991
+ // (parallel transactions; the reader is recorded for that transaction's
992
+ // commit replay, `heldFromStale`). The carve-out is sound only while the
993
+ // committed value is coherent with the visible frame, i.e. while the
994
+ // flight's inputs are themselves unpublished: the stamp alone does not
995
+ // say so (it is pending-node bookkeeping), so it is refused when the
996
+ // inputs are on screen — committed by a batch that left the flight in
997
+ // the air (CONFIG_INPUTS_PUBLISHED, #3305) or revealed through a lane
998
+ // (optimistic / latest, #3334) — and the reader holds instead. An
999
+ // UNINITIALIZED node has no committed value to show and holds too
1000
+ // (firewall-backed store reads always did; plain memos since the #3043
1001
+ // port): falling through served `undefined` as if settled and stranded
1002
+ // the reader outside both transactions, so it never re-ran.
1003
+ if (t && !(stale && !(l.S & STATUS_UNINITIALIZED) && !(l.T & CONFIG_INPUTS_PUBLISHED) && !(l.T & CONFIG_HAS_LANE && GlobalQueue.Mt(l)) && heldFromStale(l, t))) {
862
1004
  // Per-lane suspension lives with the engine (a non-null lane implies it
863
1005
  // is installed): under a lane, only same-lane pending async without an
864
1006
  // active override throws — plus uninitialized sources regardless of
865
1007
  // lane (#3276); that check rides laneSuspends so floor bundles don't
866
1008
  // pay for it.
867
- if (currentOptimisticLane === null || GlobalQueue.kt(u)) {
1009
+ if (currentOptimisticLane === null || GlobalQueue.qt(l)) {
868
1010
  if (!tracking && e !== t) link(e, t);
869
- throw u.o?._;
1011
+ throw l.o?._;
870
1012
  }
871
- } else if (t && u.S & STATUS_UNINITIALIZED) {
872
- // A stale (render) reader of a node held pending in ANOTHER transition
873
- // normally keeps showing the node's committed value instead of
874
- // entangling the two transactions — but an uninitialized node has no
875
- // committed value to show. Suspend on it (firewall-backed store reads
876
- // always took this branch; plain memos now do too): the reader
877
- // registers as a reporter of that source, and its pending-node stamp
878
- // ties it to the active transaction, so the two transactions merge
879
- // when the source settles. Falling through served `undefined` as if
880
- // settled and stranded the reader outside both transactions, so it
881
- // never re-ran when either landed (#3043 port).
882
- if (!tracking && e !== t) link(e, t);
883
- throw u.o?._;
884
- } else if (!t && u.S & STATUS_UNINITIALIZED) {
885
- throw u.o?._;
1013
+ } else if (!t && l.S & STATUS_UNINITIALIZED) {
1014
+ throw l.o?._;
886
1015
  }
887
1016
  }
888
1017
  // `owner` is the computed itself, or the firewall behind a store node —
889
1018
  // firewall-backed reads follow the same rules (memo parity, #2897 ruling):
890
1019
  // an errored derive throws for every late reader instead of silently
891
1020
  // serving node values (the seed, or last-good data after a failed refetch).
892
- if (u.oe && u.S & STATUS_ERROR) {
1021
+ if (l.oe && l.S & STATUS_ERROR) {
893
1022
  // Only a genuine reactive re-read may retry an errored async source:
894
1023
  // - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
895
1024
  // - !pendingCheckActive: an `isPending` probe observes the error, never refetches
896
1025
  // - owner._time < clock: only on a later cycle than the one the error was found
897
- if (tracking && !pendingCheckActive && u.Te < clock) {
898
- recompute(u);
1026
+ if (tracking && !pendingCheckActive && l._e < clock) {
1027
+ recompute(l);
899
1028
  return read(e);
900
- } else throw u.o?._;
1029
+ } else throw l.o?._;
901
1030
  }
902
1031
  if (snapshotCaptureActive && t && t.T & CONFIG_IN_SNAPSHOT_SCOPE) {
903
- const n = e.o?.Ye;
1032
+ const n = e.o?.ze;
904
1033
  if (n !== undefined) {
905
1034
  const i = n === NO_SNAPSHOT ? undefined : n;
906
- const u = e.Re !== NOT_PENDING ? e.Re : e.be;
907
- if (u !== i) t.ie |= REACTIVE_SNAPSHOT_STALE;
1035
+ const l = e.Ge !== NOT_PENDING ? e.Ge : e.me;
1036
+ if (l !== i) t.ie |= REACTIVE_SNAPSHOT_STALE;
908
1037
  return i;
909
1038
  }
910
1039
  }
911
- if (e.o?.Pe !== undefined && e.o?.Pe !== NOT_PENDING) {
1040
+ if (e.o?.be !== undefined && e.o?.be !== NOT_PENDING) {
912
1041
  // A17: the override IS the value for every reader — except an authoritative
913
1042
  // reader (until()'s predicate carries CONFIG_AUTHORITATIVE_READ): it must
914
1043
  // observe independently-arriving truth, and serving it the caller's own
@@ -919,7 +1048,15 @@ function read(e) {
919
1048
  // authoritative — optimism never lives there); the sticky mark makes the
920
1049
  // A17-silent "landing equals override" paths notify this node's subs so
921
1050
  // the reader re-runs when truth arrives.
922
- if (!(t && t.T & CONFIG_AUTHORITATIVE_READ)) return unwrapOverride(e.o?.Pe);
1051
+ if (!(t && t.T & CONFIG_AUTHORITATIVE_READ)) {
1052
+ // A18 supersession (#3331): the node's own source answered with a
1053
+ // DIFFERENT value. The optimism is over for the graph — a tracked
1054
+ // reader sees the staged truth — while the override remains the
1055
+ // DISPLAYED value for untracked reads (and for a stale reader of some
1056
+ // other transaction). The selection lives with the engine.
1057
+ if (t && e.T & CONFIG_OVERRIDE_SUPERSEDED) return GlobalQueue.Yt(e);
1058
+ return unwrapOverride(e.o?.be);
1059
+ }
923
1060
  e.T |= CONFIG_AUTHORITATIVE_OBSERVED;
924
1061
  }
925
1062
  // Entanglement gate: a reader recomputing under an optimistic lane that reads
@@ -929,8 +1066,8 @@ function read(e) {
929
1066
  // _pendingValue for correct fetching. The sub is recorded for replay at commit
930
1067
  // so it re-runs with the new committed view. (Gate details live with the
931
1068
  // engine — a non-null lane implies it is installed.)
932
- if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.Ut(e, u, t)) {
933
- return e.be;
1069
+ if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.Zt(e, l, t)) {
1070
+ return e.me;
934
1071
  }
935
1072
  // In optimistic lane context, return _value for optimistic/lane-assigned signals
936
1073
  // and for regular signals in stale mode (render effects). Non-stale readers (user
@@ -938,7 +1075,7 @@ function read(e) {
938
1075
  // (The lane-context clause lives with the engine.) Children-forbidden readers
939
1076
  // (createTrackedEffect / onSettled callbacks) get committed visibility — see
940
1077
  // readNodeFast (#3006).
941
- const l = !t || currentOptimisticLane !== null && GlobalQueue.xt(e, u, t) || e.Re === NOT_PENDING || t.T & CONFIG_CHILDREN_FORBIDDEN || stale && e.Ae && activeTransition !== e.Ae ||
1078
+ const u = !t || currentOptimisticLane !== null && GlobalQueue.Kt(e, l, t) || e.Ge === NOT_PENDING || t.T & CONFIG_CHILDREN_FORBIDDEN || stale && heldFromStale(e, t) ||
942
1079
  // A17 for HELD truth (#3164, see CONFIG_HELD_TRUTH): staged confirming
943
1080
  // truth — fold-staged onto an armed family, or entangle-stolen by an
944
1081
  // awaited until() — is masked from ordinary readers until its
@@ -947,11 +1084,11 @@ function read(e) {
947
1084
  // compose override + staged truth into a state no timeline contains).
948
1085
  // Authoritative readers (until()'s predicate) and latest() see the
949
1086
  // staged truth — the tunnel that keeps the hold deadlock-free.
950
- e.T & CONFIG_HELD_TRUTH && !latestReadActive && !(t.T & CONFIG_AUTHORITATIVE_READ) ? e.be : e.Re;
1087
+ e.T & CONFIG_HELD_TRUTH && !latestReadActive && !(t.T & CONFIG_AUTHORITATIVE_READ) ? e.me : e.Ge;
951
1088
  // Record that this isPending() probe observed the fresh pending value, so
952
1089
  // the probe doesn't pair "pending" with the new value (#2831).
953
- if (pendingCheckActive) GlobalQueue.Lt(e, l);
954
- if (!t && u === e && typeof n.oe === "function" && e.T & CONFIG_AUTO_DISPOSE && !(u.S & STATUS_PENDING) && !e.u) {
1090
+ if (pendingCheckActive) GlobalQueue.jt(e, u);
1091
+ if (!t && l === e && typeof n.oe === "function" && e.T & CONFIG_AUTO_DISPOSE && !(l.S & STATUS_PENDING) && !e.u) {
955
1092
  // Deferred, not inline (#3078): an inline unobserved() here made untracked
956
1093
  // reads destructive — dispose on this read, full revival recompute on the
957
1094
  // next — so consecutive reads could answer differently with no write in
@@ -961,41 +1098,47 @@ function read(e) {
961
1098
  dormantNodes.add(e);
962
1099
  schedule();
963
1100
  }
964
- return l;
1101
+ return u;
965
1102
  }
966
1103
 
967
1104
  function setSignal(e, t) {
968
- if (e.Ae && activeTransition !== e.Ae) globalQueue.initTransition(e.Ae);
1105
+ if (e.ge && activeTransition !== e.ge) globalQueue.initTransition(e.ge);
969
1106
  // The optimistic write path lives with the engine: only optimisticSignal /
970
1107
  // optimisticComputed callers and optimistic store nodes carry an
971
1108
  // _overrideValue slot (flagged by CONFIG_OPTIMISTIC — a masked read of the
972
1109
  // always-present config instead of a missing-property probe), and every
973
1110
  // module that installs one installs the engine first.
974
- if (e.T & CONFIG_OPTIMISTIC && !projectionWriteActive) return GlobalQueue.yt(e, t);
975
- const n = e.Re === NOT_PENDING ? e.be : e.Re;
1111
+ if (e.T & CONFIG_OPTIMISTIC) {
1112
+ if (!projectionWriteActive) return GlobalQueue.Bt(e, t);
1113
+ // An authoritative store landing on an override-covered node: the store
1114
+ // twin of asyncWrite's override branch, decided by the engine (#3331).
1115
+ const n = e.o?.be;
1116
+ if (n !== undefined && n !== NOT_PENDING) return GlobalQueue.zt(e, t);
1117
+ }
1118
+ const n = e.Ge === NOT_PENDING ? e.me : e.Ge;
976
1119
  if (typeof t === "function") t = t(n);
977
1120
  // Uninitialized check first: the first commit has no previous value, so the
978
1121
  // user comparator must not run against `undefined` (matches recompute).
979
- const i = !!(e.S & STATUS_UNINITIALIZED) || !e.pe || !e.pe(n, t);
1122
+ const i = !!(e.S & STATUS_UNINITIALIZED) || !e.ve || !e.ve(n, t);
980
1123
  if (!i) return t;
981
- const u = e.Re !== NOT_PENDING;
982
- if (!u) queuePendingNode(e);
983
- e.Re = t;
1124
+ const l = e.Ge !== NOT_PENDING;
1125
+ if (!l) queuePendingNode(e);
1126
+ e.Ge = t;
984
1127
  // syncCompanions only pokes _pendingSignal/_latestValueComputed — with
985
1128
  // neither companion present the call is a guaranteed no-op (companions are
986
1129
  // only ever created, never removed, and creating one installs the hook and
987
1130
  // sets CONFIG_HAS_COMPANIONS — one masked read replaces two optional-field
988
1131
  // probes on every write).
989
- e.T & CONFIG_HAS_COMPANIONS && GlobalQueue.Ue !== null && GlobalQueue.Ue(e, t);
1132
+ e.T & CONFIG_HAS_COMPANIONS && GlobalQueue.pe !== null && GlobalQueue.pe(e, t);
990
1133
  // _time is a computed-only slot (§12e): writing it on a signal would fork
991
1134
  // the lean shape. Every read site is computed-typed.
992
- if (e.oe !== undefined) e.Te = clock;
1135
+ if (e.oe !== undefined) e._e = clock;
993
1136
  // Staged-rewrite fast path (§12d): a re-write to a node whose subscribers
994
1137
  // were already walked — and where nothing has recomputed or linked since
995
1138
  // (epoch) — re-stages the value and stops. The walk is idempotent (subs
996
1139
  // marked, heap entries flag-guarded, effects queued once); lane and reask
997
1140
  // contexts change what a walk MEANS, so they always walk.
998
- if (u && e.Et === notifyEpoch && currentOptimisticLane === null && !reaskArmed) return t;
1141
+ if (l && e.At === notifyEpoch && currentOptimisticLane === null && !reaskArmed) return t;
999
1142
  insertSubs(e);
1000
1143
  schedule();
1001
1144
  return t;
@@ -1009,12 +1152,12 @@ function setSignal(e, t) {
1009
1152
  * cleanup point.
1010
1153
  */ function suppressComputedRecompute(e) {
1011
1154
  deleteFromHeap(e, queueFor(e));
1012
- if (!(e.ie & REACTIVE_MANUAL_WRITE) && e.Re === NOT_PENDING) {
1155
+ if (!(e.ie & REACTIVE_MANUAL_WRITE) && e.Ge === NOT_PENDING) {
1013
1156
  queuePendingNode(e);
1014
1157
  schedule();
1015
1158
  }
1016
1159
  e.ie = e.ie & -4 | REACTIVE_MANUAL_WRITE;
1017
- e.Qt = clock;
1160
+ e.Jt = clock;
1018
1161
  }
1019
1162
 
1020
1163
  /**
@@ -1084,7 +1227,7 @@ function staleValues(e, t = true) {
1084
1227
  // refresh is a later, explicit re-ask and lifts the mask — otherwise
1085
1228
  // any setStore early in an action silently swallows every refresh()
1086
1229
  // for the rest of the transaction (#3026).
1087
- if (e.Qt === clock) return;
1230
+ if (e.Jt === clock) return;
1088
1231
  e.ie &= ~REACTIVE_MANUAL_WRITE;
1089
1232
  // The lift falls through to the re-ask classification below. The held
1090
1233
  // write's value change already rides the transaction; the refetch it
@@ -1112,4 +1255,4 @@ function staleValues(e, t = true) {
1112
1255
  }
1113
1256
  }
1114
1257
 
1115
- export { READ_SLOW, clearSnapshots, computed, context, createEffectNode, currentOptimisticLane, effectStatusNotify, ext, installAuthoritativeRead, isEqual, latestReadActive, markRefresh, markSnapshotScope, notifyAuthoritativeObservers, optimisticComputed, optimisticSignal, pendingCheckActive, prepareComputed, read, readNodeFast, recompute, releaseSnapshotScope, runWithOwner, setContextInternal, setEffectStatusNotify, setLatestReadActive, setMemo, setPendingCheckActive, setSignal, setSlotUnobserved, setSnapshotCapture, signal, slotSignal, slotUnobservedHook, snapshotCaptureActive, snapshotSources, stale, staleValues, statusNotifierOf, suppressComputedRecompute, tracking, untrack };
1258
+ export { READ_SLOW, clearSnapshots, computed, context, createEffectNode, currentOptimisticLane, effectStatusNotify, ext, installAuthoritativeRead, isEqual, latestReadActive, markRefresh, markSnapshotScope, notifyAuthoritativeObservers, optimisticComputed, optimisticSignal, pendingCheckActive, prepareComputed, read, readNodeFast, recompute, releaseSnapshotScope, runWithOwner, setContextInternal, setEffectStatusNotify, setLatestReadActive, setMemo, setPendingCheckActive, setSignal, setSlotUnobserved, setSnapshotCapture, signal, slotSignal, slotUnobservedHook, snapshotCaptureActive, snapshotSources, stale, staleValues, statusNotifierOf, suppressComputedRecompute, tracking, unlinkFirewallChild, untrack };