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