@solidjs/signals 2.0.0-rc.3 → 2.0.0-rc.5

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 (71) hide show
  1. package/dist/dev.js +2494 -271
  2. package/dist/node.cjs +3691 -1595
  3. package/dist/prod/affects.js +13 -12
  4. package/dist/prod/boundaries.js +43 -35
  5. package/dist/prod/core/action.js +3 -3
  6. package/dist/prod/core/async.js +137 -106
  7. package/dist/prod/core/constants.js +55 -1
  8. package/dist/prod/core/core.js +354 -247
  9. package/dist/prod/core/effect.js +47 -50
  10. package/dist/prod/core/error.js +13 -1
  11. package/dist/prod/core/external.js +4 -4
  12. package/dist/prod/core/graph.js +88 -52
  13. package/dist/prod/core/heap.js +38 -38
  14. package/dist/prod/core/lanes.js +34 -34
  15. package/dist/prod/core/optimistic.js +61 -58
  16. package/dist/prod/core/owner.js +38 -38
  17. package/dist/prod/core/scheduler.js +401 -174
  18. package/dist/prod/core/verdict.js +132 -65
  19. package/dist/prod/index.js +7 -3
  20. package/dist/prod/map.js +106 -106
  21. package/dist/prod/signals.js +253 -25
  22. package/dist/prod/store/index.js +2 -0
  23. package/dist/prod/store/next/optimistic.js +314 -121
  24. package/dist/prod/store/next/patch-hooks.js +13 -0
  25. package/dist/prod/store/next/patch.js +614 -0
  26. package/dist/prod/store/next/projection.js +23 -19
  27. package/dist/prod/store/next/reconcile.js +307 -120
  28. package/dist/prod/store/next/store.js +440 -117
  29. package/dist/prod/store/next/target.js +13 -4
  30. package/dist/prod/store/store.js +5 -5
  31. package/dist/types/core/async.d.ts +2 -0
  32. package/dist/types/core/attribution.d.ts +9 -4
  33. package/dist/types/core/constants.d.ts +54 -0
  34. package/dist/types/core/core.d.ts +34 -21
  35. package/dist/types/core/dev.d.ts +8 -0
  36. package/dist/types/core/error.d.ts +9 -0
  37. package/dist/types/core/graph.d.ts +22 -0
  38. package/dist/types/core/index.d.ts +2 -2
  39. package/dist/types/core/scheduler.d.ts +46 -0
  40. package/dist/types/core/types.d.ts +12 -0
  41. package/dist/types/index.d.ts +3 -3
  42. package/dist/types/signals.d.ts +108 -0
  43. package/dist/types/store/index.d.ts +2 -0
  44. package/dist/types/store/next/optimistic.d.ts +13 -10
  45. package/dist/types/store/next/patch-hooks.d.ts +41 -0
  46. package/dist/types/store/next/patch.d.ts +91 -0
  47. package/dist/types/store/next/projection.d.ts +1 -1
  48. package/dist/types/store/next/reconcile.d.ts +14 -0
  49. package/dist/types/store/next/store.d.ts +52 -2
  50. package/dist/types/store/next/target.d.ts +73 -8
  51. package/dist/types-cjs/core/async.d.cts +2 -0
  52. package/dist/types-cjs/core/attribution.d.cts +9 -4
  53. package/dist/types-cjs/core/constants.d.cts +54 -0
  54. package/dist/types-cjs/core/core.d.cts +34 -21
  55. package/dist/types-cjs/core/dev.d.cts +8 -0
  56. package/dist/types-cjs/core/error.d.cts +9 -0
  57. package/dist/types-cjs/core/graph.d.cts +22 -0
  58. package/dist/types-cjs/core/index.d.cts +2 -2
  59. package/dist/types-cjs/core/scheduler.d.cts +46 -0
  60. package/dist/types-cjs/core/types.d.cts +12 -0
  61. package/dist/types-cjs/index.d.cts +3 -3
  62. package/dist/types-cjs/signals.d.cts +108 -0
  63. package/dist/types-cjs/store/index.d.cts +2 -0
  64. package/dist/types-cjs/store/next/optimistic.d.cts +13 -10
  65. package/dist/types-cjs/store/next/patch-hooks.d.cts +41 -0
  66. package/dist/types-cjs/store/next/patch.d.cts +91 -0
  67. package/dist/types-cjs/store/next/projection.d.cts +1 -1
  68. package/dist/types-cjs/store/next/reconcile.d.cts +14 -0
  69. package/dist/types-cjs/store/next/store.d.cts +52 -2
  70. package/dist/types-cjs/store/next/target.d.cts +73 -8
  71. package/package.json +2 -2
@@ -1,22 +1,22 @@
1
- import { handleAsync, clearStatus, parkLoadingWindow, notifyStatus, settleErroredDependents } from "./async.js";
1
+ import { releaseFlightTeardown, handleAsync, clearStatus, parkLoadingWindow, notifyStatus, settleErroredDependents, settlePendingSource } 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, OVERRIDE_UNDEFINED, CONFIG_HAS_COMPANIONS, REACTIVE_LAZY, REACTIVE_DISPOSED, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, REACTIVE_CHECK, REACTIVE_DIRTY, REACTIVE_IN_HEAP, REACTIVE_IN_HEAP_HEIGHT, defaultContext, CONFIG_IN_SNAPSHOT_SCOPE, CONFIG_TRANSPARENT, CONFIG_OWNED_WRITE, CONFIG_NO_SNAPSHOT, $REFRESH, REACTIVE_MANUAL_WRITE, CONFIG_FW_CHILDREN, NO_SNAPSHOT, CONFIG_HAS_SNAPSHOT, STORE_SNAPSHOT_PROPS, EFFECT_USER } from "./constants.js";
3
+ import { EFFECT_TRACKED, 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_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";
4
4
 
5
5
  import { NotReadyError } from "./error.js";
6
6
 
7
- import { trimStaleDeps, link, unobserved } from "./graph.js";
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, activeTransition, globalQueue, clock, insertSubs, queuePendingNode, runInTransition, schedule, notifyEpoch, dirtyQueue, bumpNotifyEpoch, projectionWriteActive, reaskArmed, armReaskClear } from "./scheduler.js";
11
+ import { GlobalQueue, bumpNotifyEpoch, activeTransition, globalQueue, clock, 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.Ce = recompute;
17
+ GlobalQueue.Fe = recompute;
18
18
 
19
- GlobalQueue.Fe = disposeChildren;
19
+ GlobalQueue.He = disposeChildren;
20
20
 
21
21
  let tracking = false;
22
22
 
@@ -48,8 +48,8 @@ let snapshotSources = null;
48
48
 
49
49
  function ownerInSnapshotScope(e) {
50
50
  while (e) {
51
- if (e.He) return true;
52
- e = e.ve;
51
+ if (e.Ve) return true;
52
+ e = e.ke;
53
53
  }
54
54
  return false;
55
55
  }
@@ -60,41 +60,41 @@ function setSnapshotCapture(e) {
60
60
  }
61
61
 
62
62
  function markSnapshotScope(e) {
63
- e.He = true;
63
+ e.Ve = true;
64
64
  }
65
65
 
66
66
  function releaseSnapshotScope(e) {
67
- e.He = false;
67
+ e.Ve = false;
68
68
  releaseSubtree(e);
69
69
  schedule();
70
70
  }
71
71
 
72
72
  function releaseSubtree(e) {
73
- let t = e.ke;
73
+ let t = e.xe;
74
74
  while (t) {
75
- if (t.He) {
76
- t = t.Ve;
75
+ if (t.Ve) {
76
+ t = t.Le;
77
77
  continue;
78
78
  }
79
- if (t.Se) {
79
+ if (t.oe) {
80
80
  const e = t;
81
81
  e.T &= ~CONFIG_IN_SNAPSHOT_SCOPE;
82
82
  if (e.ie & REACTIVE_SNAPSHOT_STALE) {
83
83
  e.ie &= ~REACTIVE_SNAPSHOT_STALE;
84
84
  e.ie |= REACTIVE_DIRTY;
85
- if (dirtyQueue.xe > e.Le) dirtyQueue.xe = e.Le;
85
+ if (dirtyQueue.Qe > e.Me) dirtyQueue.Qe = e.Me;
86
86
  insertIntoHeap(e, dirtyQueue);
87
87
  }
88
88
  }
89
89
  releaseSubtree(t);
90
- t = t.Ve;
90
+ t = t.Le;
91
91
  }
92
92
  }
93
93
 
94
94
  function clearSnapshots() {
95
95
  if (snapshotSources) {
96
96
  for (const e of snapshotSources) {
97
- delete e.o?.Qe;
97
+ delete e.o?.We;
98
98
  // StoreNode targets share one pre-initialized hidden class (see
99
99
  // createStoreProxy) — assign undefined instead of deleting, and only
100
100
  // when present so signal-node sources don't grow the field.
@@ -108,48 +108,63 @@ function clearSnapshots() {
108
108
  function recompute(e, t = false) {
109
109
  // §12d: any recompute can clean a marked subscriber — invalidate skips.
110
110
  bumpNotifyEpoch();
111
- const n = e.Re;
111
+ const n = e.he;
112
112
  if (!t) {
113
- if (e._e && (!n || activeTransition) && activeTransition !== e._e) globalQueue.initTransition(e._e);
113
+ if (e.Ae && (!n || activeTransition) && activeTransition !== e.Ae) globalQueue.initTransition(e.Ae);
114
114
  deleteFromHeap(e, queueFor(e));
115
- if (e.o !== null) e.o.Ee = null;
115
+ if (e.o !== null) {
116
+ e.o.Ie = null;
117
+ // Supersede is where an iterator flight dies (#3122): close it now.
118
+ // Its cleanup(close) registration may sit in a zombie-deferred
119
+ // disposal list that a held transition only drains when the
120
+ // SUPERSEDING flight settles — cancellation must not wait for the
121
+ // work that replaced it. Idempotent with the cleanup-channel close.
122
+ releaseFlightTeardown(e);
123
+ }
116
124
  // Tracked effects run after finalizePureQueue, so dispose immediately instead of deferring
117
- if (e._e || n === EFFECT_TRACKED) disposeChildren(e); else if (e.ke !== null || e.he !== null) {
125
+ if (e.Ae || n === EFFECT_TRACKED) disposeChildren(e); else if (e.xe !== null || e.pe !== null) {
118
126
  markDisposal(e);
119
127
  const t = ext(e);
120
- t.We = e.he;
121
- t.qe = e.ke;
122
- e.he = null;
123
- e.ke = null;
124
- e.Me = 0;
128
+ t.qe = e.pe;
129
+ t.Ye = e.xe;
130
+ e.pe = null;
131
+ e.xe = null;
132
+ e.Ze = 0;
125
133
  } else ;
126
134
  }
127
135
  let i = !!(e.ie & REACTIVE_OPTIMISTIC_DIRTY);
128
- const u = (e.T & CONFIG_OPTIMISTIC) !== 0 && e.o?.De !== NOT_PENDING && e.o?.De !== undefined;
136
+ const u = (e.T & CONFIG_OPTIMISTIC) !== 0 && e.o?.Oe !== NOT_PENDING && e.o?.Oe !== undefined;
129
137
  const l = !!(e.S & STATUS_UNINITIALIZED);
130
138
  // Outgoing error, captured before the compute clears status: if this run
131
139
  // recovers to an unchanged value, dependents still holding this object must
132
140
  // be swept (settleErroredDependents, #2949).
133
141
  const o = e.S & STATUS_ERROR ? e.o?._ : undefined;
142
+ // Pending SOURCE-hood, captured before the compute clears status: a node
143
+ // whose own flight parked dependents self-registers in _pendingSources
144
+ // (notifyStatus, isSource). If this recompute supersedes that flight and
145
+ // settles synchronously, those dependents settle HERE — asyncWrite's
146
+ // settlePendingSource walk never runs for a landing that was preempted
147
+ // (#3181).
148
+ const s = (e.S & STATUS_PENDING) !== 0 && e.o?.le?.has(e) === true;
134
149
  // Re-ask classification lives in the verdict module; capture the flag before
135
150
  // the recompute wipes _flags below.
136
- const s = (e.ie & REACTIVE_REASK) !== 0;
151
+ const a = (e.ie & REACTIVE_REASK) !== 0;
137
152
  // Captured before the compute clears it on a sync landing: if that landing
138
153
  // is transition-held below, the window must stay open until the hold
139
154
  // commits (commitPendingNode) — a closed window plus a held value reads as
140
155
  // a pending frame to live observers of the verdict (#2990).
141
- const a = e.Ie;
142
- const r = context;
156
+ const r = e.Ne;
157
+ const c = context;
143
158
  context = e;
144
- e.Ye = null;
145
- e.Ze++;
159
+ e.je = null;
160
+ e.Ke++;
146
161
  e.ie = REACTIVE_RECOMPUTING_DEPS;
147
162
  e.Te = clock;
148
- let c = e.Pe === NOT_PENDING ? e.be : e.Pe;
149
- let _ = e.Le;
150
- let f = false;
163
+ let _ = e.Pe === NOT_PENDING ? e.be : e.Pe;
164
+ let f = e.Me;
165
+ let I = false;
151
166
  let E = tracking;
152
- let I = currentOptimisticLane;
167
+ let N = currentOptimisticLane;
153
168
  tracking = true;
154
169
  // A computed's fn establishes its OWN dependencies, so it must never run
155
170
  // inside a latest() read window: read() short-circuits through the
@@ -157,54 +172,54 @@ function recompute(e, t = false) {
157
172
  // computed) inside latest(fn) came out permanently dependency-less (#2926).
158
173
  // latestRead() already suspends the flag for its pull-recomputes; this
159
174
  // covers creation-time computes and flushes that run inside the window.
160
- const N = latestReadActive;
175
+ const T = latestReadActive;
161
176
  latestReadActive = false;
162
177
  // Lane posture lives with the engine: OPTIMISTIC_DIRTY is only ever set by
163
178
  // engine-driven paths, and _optimisticNodes is only pushed by
164
179
  // _optimisticWrite, so the hook is installed whenever either gate holds.
165
180
  if (i) {
166
- const t = GlobalQueue.je(e, true);
181
+ const t = GlobalQueue.Be(e, true);
167
182
  if (t) currentOptimisticLane = t;
168
183
  // `false` = wake-only lane demotion: recompute plain so a mid-tick
169
184
  // latest()/isPending() pull stages instead of direct-committing (#3009).
170
185
  // The predicate lives with the engine (recomputeLane).
171
186
  else if (t === false) i = false;
172
- } else if (activeTransition && !t && activeTransition.Ke.length) {
187
+ } else if (activeTransition && !t && activeTransition.ze.length) {
173
188
  // Lane adoption: parent-deeper-than-owned-child can run before its OPT-dirty
174
189
  // child propagates. Walk deps once and inherit the OPT lane so this node
175
190
  // recomputes under the right posture and propagates correctly.
176
- const t = GlobalQueue.je(e, false);
191
+ const t = GlobalQueue.Be(e, false);
177
192
  if (t) {
178
193
  i = true;
179
194
  currentOptimisticLane = t;
180
195
  }
181
196
  }
182
- const T = n && n !== EFFECT_USER;
197
+ const S = n && n !== EFFECT_USER;
183
198
  const d = stale;
184
- if (T) stale = true;
199
+ if (S) stale = true;
185
200
  try {
186
201
  if (!false && e.T & CONFIG_SYNC) {
187
- c = e.Se(c);
188
- if (e.o !== null) e.o.Ee = null;
189
- e.Ie = false;
202
+ _ = e.oe(_);
203
+ if (e.o !== null) e.o.Ie = null;
204
+ e.Ne = false;
190
205
  } else {
191
206
  // Snapshot `_inFlight` so we can detect whether `_fn` self-registered an async
192
207
  // subscription (e.g. `createProjection` calls `handleAsync` from inside its body
193
208
  // with a setter callback). In that case, the outer `handleAsync` call below would
194
209
  // clobber the fresh subscription, so we skip it and let the internally-registered
195
210
  // iteration drive updates.
196
- const t = e.o?.Ee;
197
- const n = e.Se(c);
211
+ const t = e.o?.Ie;
212
+ const n = e.oe(_);
198
213
  const i = typeof n === "object" && n !== null;
199
- const u = e.o?.Ee !== t;
200
- c = u || !i ? n : handleAsync(e, n);
214
+ const u = e.o?.Ie !== t;
215
+ _ = u || !i ? n : handleAsync(e, n);
201
216
  if (!u && !i) {
202
- if (e.o !== null) e.o.Ee = null;
217
+ if (e.o !== null) e.o.Ie = null;
203
218
  // A sync (non-object) return is the first real answer; async-shaped
204
219
  // results clear inside handleAsync at their own landing points, and a
205
220
  // self-registered flight (inFlightChanged — projections) clears when
206
221
  // its internal handleAsync lands.
207
- e.Ie = false;
222
+ e.Ne = false;
208
223
  }
209
224
  }
210
225
  // On a status-free node clearStatus is a guaranteed no-op: every field
@@ -214,10 +229,10 @@ function recompute(e, t = false) {
214
229
  if (e.S !== 0 || e.o !== null) clearStatus(e, t);
215
230
  // _optimisticLane is only ever assigned by engine paths (CONFIG_HAS_LANE
216
231
  // is their sticky presence mark).
217
- if (e.T & CONFIG_HAS_LANE && e.o?.Be) GlobalQueue.ze(e);
232
+ if (e.T & CONFIG_HAS_LANE && e.o?.Je) GlobalQueue.Xe(e);
218
233
  } catch (t) {
219
234
  const n = t instanceof NotReadyError;
220
- if (n && e.Ie) {
235
+ if (n && e.Ne) {
221
236
  // Loading window with an unready sync dependency: register for the
222
237
  // source's settle (the settlePendingSource walk runs off
223
238
  // _pendingSources + _blocked alone) but take NO read-visible pending
@@ -232,31 +247,31 @@ function recompute(e, t = false) {
232
247
  if (n && currentOptimisticLane) GlobalQueue.$e(e);
233
248
  let i = false;
234
249
  if (n) {
235
- ext(e).ue = true;
236
- if (GlobalQueue.Je !== null) i = GlobalQueue.Je(e, s);
250
+ ext(e).fe = true;
251
+ if (GlobalQueue.et !== null) i = GlobalQueue.et(e, a);
237
252
  }
238
- notifyStatus(e, n ? STATUS_PENDING : STATUS_ERROR, t, undefined, n ? e.o?.Be : undefined);
239
- if (i) GlobalQueue.p(e);
253
+ notifyStatus(e, n ? STATUS_PENDING : STATUS_ERROR, t, undefined, n ? e.o?.Je : undefined);
254
+ if (i) GlobalQueue.k(e);
240
255
  }
241
256
  } finally {
242
257
  tracking = E;
243
- latestReadActive = N;
244
- if (T) stale = d;
258
+ latestReadActive = T;
259
+ if (S) stale = d;
245
260
  // Consume the missed-wake latch (#3037, set by insertSubs): a dep write
246
261
  // landed beneath this pass on a link it had already validated. The wipe
247
262
  // below must not key off DIRTY/CHECK — the read-time pull protocol
248
263
  // (markNode(c) in read()) marks the running node as part of ordinary
249
264
  // bookkeeping, and those marks are correctly discarded here.
250
- f = (e.ie & REACTIVE_MISSED_WAKE) !== 0;
265
+ I = (e.ie & REACTIVE_MISSED_WAKE) !== 0;
251
266
  e.ie = REACTIVE_NONE | (t ? e.ie & REACTIVE_SNAPSHOT_STALE : 0);
252
- context = r;
267
+ context = c;
253
268
  }
254
269
  if (!e.o?._) {
255
270
  trimStaleDeps(e);
256
- const s = u ? unwrapOverride(e.o?.De) : e.Pe === NOT_PENDING ? e.be : e.Pe;
257
- let r = false;
271
+ const a = u ? unwrapOverride(e.o?.Oe) : e.Pe === NOT_PENDING ? e.be : e.Pe;
272
+ let c = false;
258
273
  try {
259
- r = !n && l || !e.Ue || !e.Ue(s, c);
274
+ c = !n && l || !e.ge || !e.ge(a, _);
260
275
  } catch (t) {
261
276
  // A throwing user comparator is an error of this node's computation.
262
277
  // Route it through the same status path as a compute-phase throw so
@@ -269,55 +284,65 @@ function recompute(e, t = false) {
269
284
  // its runner — happen here instead. `!create` matches the previous `initialized`
270
285
  // gate: the explicit recompute(node, true) inside effect() does not enqueue, so
271
286
  // effect() can call its runner synchronously for the first run.
272
- if (n && r) {
273
- e.Xe = !e.o?._;
287
+ if (n && c) {
288
+ e.tt = !e.o?._;
274
289
  // Reuse one bound runner per effect — runEffect no-ops on a stale
275
290
  // `_modified`, so re-enqueueing the same function is harmless.
276
- if (!t) e.C.enqueue(n, e.et ??= GlobalQueue.tt.bind(null, e));
291
+ if (!t) e.C.enqueue(n, e.nt ??= GlobalQueue.it.bind(null, e));
277
292
  }
278
- if (e.o?._) ; else if (r) {
279
- const l = u ? e.o?.De : undefined;
293
+ if (e.o?._) ; else if (c) {
294
+ const l = u ? e.o?.Oe : undefined;
280
295
  if (t ||
281
296
  // Plain sync flush (no transition on either side) commits effect
282
297
  // values directly — the pending round-trip (queuePendingNode +
283
298
  // commitPendingNodes) exists to sequence transition reveals, and
284
299
  // paying it per effect on the plain path is pure overhead.
285
- n && (activeTransition !== e._e || activeTransition === null) || i) {
286
- e.be = c;
300
+ // DIRECT_COMMIT effects (resolve/until) commit directly even under
301
+ // their own held transition: their applies deliver on a microtask,
302
+ // not the stashed queues, so a staged value would hand the immediate
303
+ // apply stale state — see CONFIG_DIRECT_COMMIT.
304
+ n && (activeTransition !== e.Ae || activeTransition === null || e.T & CONFIG_DIRECT_COMMIT) || i) {
305
+ e.be = _;
287
306
  // Lane-propagated correction: upstream data is fresh, correct the
288
307
  // override unconditionally. The direct _value commit is the lane's
289
308
  // own reveal schedule; drop any superseded older hold so its queued
290
309
  // commit can't clobber the fresh value.
291
310
  if (u && i) {
292
- ext(e).De = c === undefined ? OVERRIDE_UNDEFINED : c;
311
+ ext(e).Oe = _ === undefined ? OVERRIDE_UNDEFINED : _;
293
312
  e.Pe = NOT_PENDING;
294
313
  }
295
314
  } else {
296
- e.Pe = c;
315
+ e.Pe = _;
297
316
  // A window landing that gets held re-opens the window until the hold
298
317
  // commits — the verdict's held-value branch is window-gated (#2990).
299
- if (a) e.Ie = true;
318
+ if (r) e.Ne = true;
300
319
  // Transition-held sync recompute is a write path like setSignal/asyncWrite,
301
320
  // so sync derivations of held sources stay visible to isPending()/latest()
302
321
  // (#2831). Both companion writes are transition-scoped (optimistic) and
303
322
  // auto-revert/re-derive at commit. Skipped for plain flushes where the
304
323
  // pending value commits before effects run.
305
- if ((activeTransition || e._e) && GlobalQueue.Oe !== null) GlobalQueue.Oe(e, c);
324
+ if ((activeTransition || e.Ae) && GlobalQueue.Re !== null) GlobalQueue.Re(e, _);
306
325
  }
307
326
  // insertSubs only walks _subs (no scheduling of its own), so a
308
327
  // subscriber-less node has nothing to notify.
309
- if (e.u !== null && (!u || i || e.o?.De !== l)) insertSubs(e, i || u);
328
+ if (e.u !== null && (!u || i || e.o?.Oe !== l)) insertSubs(e, i || u);
310
329
  } else if (u) {
311
330
  // Unchanged value (equals the override) recomputed while the override
312
331
  // is active: _value may still be stale, so hold the authoritative value
313
332
  // for commit on its own transition's schedule — invisibly (A17/A18).
314
333
  if (e.Pe === NOT_PENDING) queuePendingNode(e);
315
- e.Pe = c;
316
- if (a) e.Ie = true;
334
+ e.Pe = _;
335
+ if (r) e.Ne = true;
317
336
  // see the held branch above (#2990)
318
- } else if (e.Le != _) {
319
- for (let t = e.u; t !== null; t = t.fe) {
320
- insertIntoHeapHeight(t.ae, queueFor(t.ae));
337
+ // A authoritative-view reader (until()) observed this node past its
338
+ // override and "authoritative arrival equal to the override" is
339
+ // exactly the acknowledgment it waits for. Wake those readers only;
340
+ // A17 silence holds for every ordinary subscriber. (Hook installed by
341
+ // until(), the only setter of the gating bit.)
342
+ if (e.T & CONFIG_AUTHORITATIVE_OBSERVED) GlobalQueue.Ue(e);
343
+ } else if (e.Me != f) {
344
+ for (let t = e.u; t !== null; t = t.ae) {
345
+ insertIntoHeapHeight(t.ce, queueFor(t.ce));
321
346
  }
322
347
  }
323
348
  // Silent recovery: errored → unchanged value fires no notification, but
@@ -325,23 +350,34 @@ function recompute(e, t = false) {
325
350
  // in an errored run and may sit on stale commits (#2949). Changed-value
326
351
  // recoveries ride insertSubs above; a comparator throw re-errored the node
327
352
  // (el._x?._error re-set), so this only runs on a genuinely clean recovery.
328
- if (o !== undefined && !r && !e.o?._) settleErroredDependents(e, o);
353
+ if (o !== undefined && !c && !e.o?._) settleErroredDependents(e, o);
354
+ // Pending twin of the sweep above (#3181): a flight superseded by this
355
+ // synchronous settle leaves every registered dependent still flagged
356
+ // STATUS_PENDING with a pending source that will never land — asyncWrite
357
+ // owns the walk only for flights that actually land. An unchanged value
358
+ // is the dangerous shape (a projection reconciling in place: a memo over
359
+ // it re-throws its cached NotReadyError forever, and every reader that
360
+ // suspended through that memo re-parks on the dead source), but the walk
361
+ // runs on the changed shape too, exactly as the landing path does —
362
+ // insertSubs notifies value SUBSCRIBERS, not pending REGISTRANTS, and
363
+ // the two sets only partially overlap.
364
+ if (s && !(e.S & STATUS_PENDING)) settlePendingSource(e);
329
365
  }
330
- currentOptimisticLane = I;
331
- const S = e.Pe !== NOT_PENDING || e.o !== null && (e.o.qe !== null || e.o.We !== null) || (e.S & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
366
+ currentOptimisticLane = N;
367
+ const A = e.Pe !== NOT_PENDING || e.o !== null && (e.o.Ye !== null || e.o.qe !== null) || (e.S & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
332
368
  // Override-covered holds (hasOverride) always queue: their commit belongs
333
369
  // to their own transition's schedule (A18 re-rule) and is unobservable
334
370
  // under the override (A17). Revert no longer commits anything, so an
335
371
  // unqueued covered hold would leak (INV-7) once the revert clears
336
372
  // _transition.
337
- S && (!t || e.S & STATUS_PENDING) && (!e._e || u) && queuePendingNode(e);
338
- e._e && n && activeTransition !== e._e && runInTransition(e._e, () => recompute(e));
373
+ A && (!t || e.S & STATUS_PENDING) && (!e.Ae || u) && queuePendingNode(e);
374
+ e.Ae && n && activeTransition !== e.Ae && runInTransition(e.Ae, () => recompute(e));
339
375
  // Missed-wake reschedule (see the finally above): values this pass read
340
376
  // before the nested commit are stale, so run again now that the heap will
341
377
  // accept the node. Equality gates stop same-value landings from cascading,
342
378
  // and a re-run only latches again if another nested commit changes a dep
343
379
  // beneath it — convergent unless deps genuinely keep changing.
344
- if (f) {
380
+ if (I) {
345
381
  enqueueSub(e);
346
382
  schedule();
347
383
  }
@@ -352,12 +388,14 @@ function updateIfNecessary(e) {
352
388
  // (_depsTail/_depGen) is live, and a nested recompute would corrupt it.
353
389
  // A mid-pass mark stays latched for recompute's own tail to reschedule
354
390
  // (#3037); readers meanwhile serve the values the pass has so far.
355
- if (e.ie & REACTIVE_RECOMPUTING_DEPS) return;
391
+ // Never recompute a DISPOSED node either: recompute rewrites _flags and
392
+ // would resurrect it (#2983) — readers serve its last value.
393
+ if (e.ie & (REACTIVE_RECOMPUTING_DEPS | REACTIVE_DISPOSED)) return;
356
394
  if (e.ie & REACTIVE_CHECK) {
357
- for (let t = e.nt; t; t = t.it) {
358
- const n = t.ut;
359
- const i = n.lt || n;
360
- if (i.Se) {
395
+ for (let t = e.ut; t; t = t.lt) {
396
+ const n = t.ot;
397
+ const i = n.st || n;
398
+ if (i.oe) {
361
399
  updateIfNecessary(i);
362
400
  }
363
401
  if (e.ie & REACTIVE_DIRTY) {
@@ -365,7 +403,7 @@ function updateIfNecessary(e) {
365
403
  }
366
404
  }
367
405
  }
368
- if (e.ie & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.o?._ && e.Te < clock && !e.o?.Ee) {
406
+ if (e.ie & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.o?._ && e.Te < clock && !e.o?.Ie) {
369
407
  recompute(e);
370
408
  }
371
409
  e.ie = e.ie & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
@@ -380,40 +418,40 @@ function computed(e, t) {
380
418
  const u = {
381
419
  id: inheritId(t, n, context),
382
420
  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),
383
- Ue: t?.equals != null ? t.equals : isEqual,
384
- he: null,
421
+ ge: t?.equals ?? isEqual,
422
+ pe: null,
385
423
  C: context?.C ?? globalQueue,
386
424
  we: context?.we ?? defaultContext,
387
- Me: 0,
388
- Se: e,
389
- be: i ? t.loadingValue : undefined,
390
- Le: 0,
391
- ot: undefined,
392
- st: null,
393
- nt: null,
394
- Ye: null,
395
425
  Ze: 0,
396
- u: null,
397
- rt: null,
398
- ve: context,
399
- Ve: null,
426
+ oe: e,
427
+ be: i ? t.loadingValue : undefined,
428
+ Me: 0,
429
+ rt: undefined,
400
430
  ct: null,
401
- ke: null,
431
+ ut: null,
432
+ je: null,
433
+ Ke: 0,
434
+ u: null,
435
+ _t: null,
436
+ ke: context,
437
+ Le: null,
438
+ ft: null,
439
+ xe: null,
402
440
  ie: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
403
441
  // A loadingValue node is born committed: commit #0 is already in _value.
404
442
  S: i ? 0 : STATUS_UNINITIALIZED,
405
443
  Te: clock,
406
444
  Pe: NOT_PENDING,
407
- _e: null,
408
- _t: -1,
409
- Ie: i,
445
+ Ae: null,
446
+ It: -1,
447
+ Ne: i,
410
448
  // Cold machinery (async/transition/optimistic/verdict slots) lives one
411
449
  // hop away in the lazily-allocated extension — the core literal MUST
412
450
  // stay under V8's in-object boundary (§12: past ~39 fields every
413
451
  // allocation spills to a backing store and creation cost ~4x's).
414
452
  o: null
415
453
  };
416
- if (t?.unobserved) ext(u).ft = t.unobserved;
454
+ if (t?.unobserved) ext(u).Et = t.unobserved;
417
455
  setupComputedNode(u, t);
418
456
  return u;
419
457
  }
@@ -423,25 +461,26 @@ function computed(e, t) {
423
461
  * this; hot paths read `el._x?._field` gated by the _config presence bits.
424
462
  * Never call ext() just to store a field's default. */ function ext(e) {
425
463
  return e.o ??= {
426
- De: undefined,
427
- Et: undefined,
428
- Be: undefined,
429
- Ge: undefined,
430
- ge: undefined,
431
- It: undefined,
464
+ Oe: undefined,
465
+ Nt: undefined,
466
+ Je: undefined,
467
+ ye: undefined,
468
+ Ce: undefined,
469
+ Tt: undefined,
432
470
  t: 0,
471
+ Ie: null,
433
472
  Ee: null,
434
473
  _: undefined,
435
- ue: undefined,
474
+ fe: undefined,
436
475
  le: undefined,
437
- A: undefined,
438
- pe: false,
439
- l: null,
440
- ft: undefined,
441
- Qe: undefined,
442
- We: null,
476
+ h: undefined,
477
+ Ge: false,
478
+ i: null,
479
+ Et: undefined,
480
+ We: undefined,
443
481
  qe: null,
444
- Nt: undefined
482
+ Ye: null,
483
+ St: undefined
445
484
  };
446
485
  }
447
486
 
@@ -450,50 +489,74 @@ function computed(e, t) {
450
489
  * so V8 sees the full hidden class shape at construction time. Effects always run in lazy
451
490
  * mode (recompute is called explicitly by `effect()`), so we hardcode the lazy bits and skip
452
491
  * the auto-dispose CONFIG bit (effect() previously cleared it post-construction).
453
- */ function createEffectNode(e, t, n, i, u, l) {
454
- const o = l?.transparent ?? false;
455
- const s = {
456
- id: inheritId(l, o, context),
457
- T: (o ? CONFIG_TRANSPARENT : 0) | (l?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (l?.sync ? CONFIG_SYNC : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
458
- Ue: false,
459
- he: null,
492
+ */ function createEffectNode(e, t, n, i, u) {
493
+ const l = u?.transparent ?? false;
494
+ const o = {
495
+ id: inheritId(u, l, context),
496
+ 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),
497
+ ge: false,
498
+ pe: null,
460
499
  C: context?.C ?? globalQueue,
461
500
  we: context?.we ?? defaultContext,
462
- Me: 0,
463
- Se: e,
464
- be: undefined,
465
- Le: 0,
466
- ot: undefined,
467
- st: null,
468
- nt: null,
469
- Ye: null,
470
501
  Ze: 0,
471
- u: null,
472
- rt: null,
473
- ve: context,
474
- Ve: null,
502
+ oe: e,
503
+ be: undefined,
504
+ Me: 0,
505
+ rt: undefined,
475
506
  ct: null,
476
- ke: null,
507
+ ut: null,
508
+ je: null,
509
+ Ke: 0,
510
+ u: null,
511
+ _t: null,
512
+ ke: context,
513
+ Le: null,
514
+ ft: null,
515
+ xe: null,
477
516
  ie: REACTIVE_LAZY,
478
517
  S: STATUS_UNINITIALIZED,
479
518
  Te: clock,
480
519
  Pe: NOT_PENDING,
481
- _e: null,
482
- _t: -1,
483
- Ie: false,
484
- Xe: false,
485
- Tt: undefined,
486
- dt: t,
487
- St: n,
520
+ Ae: null,
521
+ It: -1,
522
+ Ne: false,
523
+ tt: false,
488
524
  At: undefined,
489
- Re: i,
525
+ Ot: t,
526
+ Ct: n,
527
+ Rt: undefined,
528
+ he: i,
490
529
  o: null
491
530
  };
492
- // Boundary effects carry a status channel; most effects never touch _x.
493
- if (u !== undefined) ext(s).A = u;
494
- if (l?.unobserved) ext(s).ft = l.unobserved;
495
- setupComputedNode(s, lazyOptions);
496
- return s;
531
+ // Effects dispatch status through the SHARED notifier (statusNotifierOf,
532
+ // keyed off _type) storing it per node forced a full NodeExtension
533
+ // allocation on EVERY effect at creation (an alloc + 19 field stores,
534
+ // +23% effect creation, caught by the creation benches). Only genuinely
535
+ // per-node channels (boundaries) live on _x.
536
+ if (u?.unobserved) ext(o).Et = u.unobserved;
537
+ setupComputedNode(o, lazyOptions);
538
+ return o;
539
+ }
540
+
541
+ /**
542
+ * The shared status notifier for effect nodes, installed once by effect.ts
543
+ * at module evaluation (`this`-dispatched — one function serves every
544
+ * effect, so nodes never store it). Boundary computeds keep their own
545
+ * per-node channel on `_x._notifyStatus`, which takes precedence.
546
+ */ let effectStatusNotify = null;
547
+
548
+ function setEffectStatusNotify(e) {
549
+ effectStatusNotify = e;
550
+ }
551
+
552
+ /** Resolve a node's status notifier: an own `_x` channel (boundaries) wins;
553
+ * effect nodes (`_type` — EFFECT_PURE is 0, and only effect literals carry
554
+ * the field) fall back to the shared notifier. Presence doubles as the
555
+ * "display consumer" membership test in the status walks, exactly as the
556
+ * per-node field did when every effect carried one. */ function statusNotifierOf(e) {
557
+ const t = e.o?.h;
558
+ if (t !== undefined) return t;
559
+ return e.he ? effectStatusNotify ?? undefined : undefined;
497
560
  }
498
561
 
499
562
  const lazyOptions = {
@@ -501,24 +564,24 @@ const lazyOptions = {
501
564
  };
502
565
 
503
566
  function setupComputedNode(e, t) {
504
- e.st = e;
505
- const n = context?.Ct ? context.Ot : context;
567
+ e.ct = e;
568
+ const n = context?.Gt ? context.Dt : context;
506
569
  if (context) {
507
- const t = context.ke;
570
+ const t = context.xe;
508
571
  if (t === null) {
509
- context.ke = e;
572
+ context.xe = e;
510
573
  } else {
511
- e.Ve = t;
512
- t.ct = e;
513
- context.ke = e;
574
+ e.Le = t;
575
+ t.ft = e;
576
+ context.xe = e;
514
577
  }
515
578
  }
516
- if (n) e.Le = n.Le + 1;
517
- if (GlobalQueue.Rt !== null) GlobalQueue.Rt(e);
579
+ if (n) e.Me = n.Me + 1;
580
+ if (GlobalQueue.Pt !== null) GlobalQueue.Pt(e);
518
581
  !t?.lazy && recompute(e, true);
519
582
  if (snapshotCaptureActive && !t?.lazy) {
520
583
  if (!(e.S & STATUS_PENDING) && !(e.T & CONFIG_NO_SNAPSHOT)) {
521
- ext(e).Qe = e.be === undefined ? NO_SNAPSHOT : e.be;
584
+ ext(e).We = e.be === undefined ? NO_SNAPSHOT : e.be;
522
585
  e.T |= CONFIG_HAS_SNAPSHOT;
523
586
  snapshotSources.add(e);
524
587
  }
@@ -527,31 +590,31 @@ function setupComputedNode(e, t) {
527
590
 
528
591
  function signal(e, t, n = null) {
529
592
  const i = {
530
- Ue: t?.equals != null ? t.equals : isEqual,
593
+ ge: t?.equals ?? isEqual,
531
594
  T: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.H ? CONFIG_NO_SNAPSHOT : 0),
532
595
  be: e,
533
596
  u: null,
534
- rt: null,
597
+ _t: null,
535
598
  Te: clock,
536
- lt: n,
537
- ce: n?.o?.l || null,
599
+ st: n,
600
+ Se: n?.o?.i || null,
538
601
  Pe: NOT_PENDING,
539
602
  // Signal-literal diet (§12e): NO _time/_fn/_statusFlags slots. Stores
540
603
  // materialize one signal per touched leaf, so signal bytes are store
541
604
  // bytes. _time is write-only on signals (every read site is computed-
542
605
  // typed error-retry gating); _fn/_statusFlags read falsy-identically as
543
606
  // missing properties on the shared paths (undefined masks to 0).
544
- _e: null,
545
- _t: -1,
607
+ Ae: null,
608
+ It: -1,
546
609
  o: null
547
610
  };
548
- if (t?.unobserved) ext(i).ft = t.unobserved;
611
+ if (t?.unobserved) ext(i).Et = t.unobserved;
549
612
  if (n) {
550
- ext(n).l = i;
613
+ ext(n).i = i;
551
614
  n.T |= CONFIG_FW_CHILDREN;
552
615
  }
553
616
  if (snapshotCaptureActive && !(i.T & CONFIG_NO_SNAPSHOT) && !((n?.S ?? 0) & STATUS_PENDING)) {
554
- ext(i).Qe = e === undefined ? NO_SNAPSHOT : e;
617
+ ext(i).We = e === undefined ? NO_SNAPSHOT : e;
555
618
  i.T |= CONFIG_HAS_SNAPSHOT;
556
619
  snapshotSources.add(i);
557
620
  }
@@ -560,14 +623,14 @@ function signal(e, t, n = null) {
560
623
 
561
624
  function optimisticSignal(e, t) {
562
625
  const n = signal(e, t);
563
- ext(n).De = NOT_PENDING;
626
+ ext(n).Oe = NOT_PENDING;
564
627
  n.T |= CONFIG_OPTIMISTIC;
565
628
  return n;
566
629
  }
567
630
 
568
631
  function optimisticComputed(e, t) {
569
632
  const n = computed(e, t);
570
- ext(n).De = NOT_PENDING;
633
+ ext(n).Oe = NOT_PENDING;
571
634
  n.T |= CONFIG_OPTIMISTIC;
572
635
  return n;
573
636
  }
@@ -598,11 +661,11 @@ function isEqual(e, t) {
598
661
  * );
599
662
  * ```
600
663
  */ function untrack(e, t) {
601
- if (GlobalQueue.Gt === null && !tracking && true) return e();
664
+ if (GlobalQueue.ht === null && !tracking && true) return e();
602
665
  const n = tracking;
603
666
  tracking = false;
604
667
  try {
605
- if (GlobalQueue.Gt !== null) return GlobalQueue.Gt(e);
668
+ if (GlobalQueue.ht !== null) return GlobalQueue.ht(e);
606
669
  return e();
607
670
  } finally {
608
671
  tracking = n;
@@ -643,10 +706,38 @@ function isEqual(e, t) {
643
706
  * fast path, `_fn` nodes need prepareComputed, and firewall / override /
644
707
  * snapshot / transition / lane / dev-strictRead state all take the full
645
708
  * resolution. Anything slow returns READ_SLOW; the caller then calls read().
646
- */ function readNodeFast(e) {
647
- if (latestReadActive || pendingCheckActive || e.Se || e.lt || e.o?.De !== undefined || e.o?.Qe !== undefined || activeTransition !== null || currentOptimisticLane !== null || snapshotCaptureActive || false) return READ_SLOW;
709
+ */
710
+ /**
711
+ * Wake only authoritative-view readers (until() predicates) subscribed to `el`.
712
+ * The A17-silent ack paths — an authoritative arrival equal to the active
713
+ * override — use this so the predicate re-evaluates without re-firing
714
+ * ordinary subscribers whose visible (override) value did not change.
715
+ * Pay-for-use: reached through GlobalQueue._notifyAuthoritativeObservers,
716
+ * installed at first until() call — apps that never use until() shake it.
717
+ */ function notifyAuthoritativeObservers(e) {
718
+ for (let t = e.u; t !== null; t = t.ae) {
719
+ const e = t.ce;
720
+ if (!(e.T & CONFIG_AUTHORITATIVE_READ)) continue;
721
+ // Missed-wake latch (#3037), same contract as insertSubs: the reader may
722
+ // itself have pulled this recompute (updateIfNecessary from its own
723
+ // read), and the heap refuses RECOMPUTING nodes — latch so recompute's
724
+ // tail reschedules it with the staged value visible.
725
+ if (e.ie & REACTIVE_RECOMPUTING_DEPS && t.Ft === e.Ke && t !== e.je) e.ie |= REACTIVE_MISSED_WAKE;
726
+ enqueueSub(e);
727
+ }
728
+ schedule();
729
+ }
730
+
731
+ /** Installs the until() machinery hook. Idempotent; called by until() before
732
+ * any authoritative-view read happens (same late-binding contract as the
733
+ * optimistic engine). */ function installAuthoritativeRead() {
734
+ if (GlobalQueue.Ue === null) GlobalQueue.Ue = notifyAuthoritativeObservers;
735
+ }
736
+
737
+ function readNodeFast(e) {
738
+ if (latestReadActive || pendingCheckActive || e.oe || e.st || e.o?.Oe !== undefined || e.o?.We !== undefined || activeTransition !== null || currentOptimisticLane !== null || snapshotCaptureActive || false) return READ_SLOW;
648
739
  let t = context;
649
- if (t?.Ct) t = t.Ot;
740
+ if (t?.Gt) t = t.Dt;
650
741
  if (t && tracking) link(e, t);
651
742
  // Children-forbidden readers (createTrackedEffect / onSettled callbacks) get
652
743
  // committed visibility: like the effect half of createEffect and event
@@ -660,47 +751,54 @@ function read(e) {
660
751
  // Checked before isPending so that isPending(() => latest(x)) checks
661
752
  // the _pendingSignal of _latestValueComputed (async in flight) rather
662
753
  // than the original node (which stays "pending" while held in a transition).
663
- if (latestReadActive) return GlobalQueue.Pt(e);
754
+ if (latestReadActive) return GlobalQueue.gt(e);
664
755
  let t = context;
665
- if (t?.Ct) t = t.Ot;
756
+ if (t?.Gt) t = t.Dt;
666
757
  const n = e;
667
- const i = e.lt;
758
+ const i = e.st;
668
759
  const u = i || e;
669
760
  // Handle isPending() mode: collect pending state while preserving normal read semantics.
670
761
  // Probe mode is suspended while preparing the node so nested reads during a
671
762
  // recompute don't collect into the probe.
672
763
  if (pendingCheckActive) {
673
- GlobalQueue.Dt(e, t, u, i);
674
- } else if (typeof n.Se === "function") {
764
+ GlobalQueue.Ht(e, t, u, i);
765
+ } else if (typeof n.oe === "function") {
675
766
  prepareComputed(e, false);
676
767
  }
677
- if (!n.Se && u === e && e.o?.De === undefined && e.o?.Qe === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
768
+ if (!n.oe && u === e && e.o?.Oe === undefined && e.o?.We === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
678
769
  if (t && tracking) link(e, t);
679
770
  // Committed visibility for children-forbidden readers — see readNodeFast.
680
771
  return !t || e.Pe === NOT_PENDING || t.T & CONFIG_CHILDREN_FORBIDDEN ? e.be : e.Pe;
681
772
  }
682
773
  if (t && tracking) {
683
774
  link(e, t, pendingCheckActive);
684
- if (u.Se) {
775
+ if (u.oe) {
685
776
  const n = queueFor(e);
686
- if (u.Le >= n.xe) {
777
+ if (u.Me >= n.Qe) {
687
778
  markNode(t);
688
779
  markHeap(n);
689
780
  updateIfNecessary(u);
690
781
  }
691
- const i = u.Le;
782
+ // Fresh-pull readers (awaitable refresh's waiter) recompute a dirty
783
+ // source inline even when the height gate defers to the flush: the
784
+ // waiter must park on the re-ask's window (or serve its sync answer),
785
+ // never read the PRE-re-ask value as settled. Self-guarded: a clean
786
+ // node no-ops and updateIfNecessary refuses disposed nodes (#2983) —
787
+ // a dead target serves its last value, which is already quiescent.
788
+ else if (t.T & CONFIG_FRESH_READ) updateIfNecessary(u);
789
+ const i = u.Me;
692
790
  // parent check is shallow, might need to be recursive
693
- if (i >= t.Le && e.ve !== t) {
694
- t.Le = i + 1;
791
+ if (i >= t.Me && e.ke !== t) {
792
+ t.Me = i + 1;
695
793
  }
696
794
  }
697
795
  }
698
796
  if (u.S & STATUS_PENDING) {
699
- if (t && !(stale && u._e && activeTransition !== u._e)) {
797
+ if (t && !(stale && u.Ae && activeTransition !== u.Ae)) {
700
798
  // Per-lane suspension lives with the engine (a non-null lane implies it
701
799
  // is installed): under a lane, only same-lane pending async without an
702
800
  // active override throws.
703
- if (currentOptimisticLane === null || GlobalQueue.ht(u)) {
801
+ if (currentOptimisticLane === null || GlobalQueue.Vt(u)) {
704
802
  if (!tracking && e !== t) link(e, t);
705
803
  throw u.o?._;
706
804
  }
@@ -725,7 +823,7 @@ function read(e) {
725
823
  // firewall-backed reads follow the same rules (memo parity, #2897 ruling):
726
824
  // an errored derive throws for every late reader instead of silently
727
825
  // serving node values (the seed, or last-good data after a failed refetch).
728
- if (u.Se && u.S & STATUS_ERROR) {
826
+ if (u.oe && u.S & STATUS_ERROR) {
729
827
  // Only a genuine reactive re-read may retry an errored async source:
730
828
  // - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
731
829
  // - !pendingCheckActive: an `isPending` probe observes the error, never refetches
@@ -736,7 +834,7 @@ function read(e) {
736
834
  } else throw u.o?._;
737
835
  }
738
836
  if (snapshotCaptureActive && t && t.T & CONFIG_IN_SNAPSHOT_SCOPE) {
739
- const n = e.o?.Qe;
837
+ const n = e.o?.We;
740
838
  if (n !== undefined) {
741
839
  const i = n === NO_SNAPSHOT ? undefined : n;
742
840
  const u = e.Pe !== NOT_PENDING ? e.Pe : e.be;
@@ -744,9 +842,19 @@ function read(e) {
744
842
  return i;
745
843
  }
746
844
  }
747
- if (e.o?.De !== undefined && e.o?.De !== NOT_PENDING) {
748
- // A17: the override IS the value for every reader.
749
- return unwrapOverride(e.o?.De);
845
+ if (e.o?.Oe !== undefined && e.o?.Oe !== NOT_PENDING) {
846
+ // A17: the override IS the value for every reader — except an authoritative
847
+ // reader (until()'s predicate carries CONFIG_AUTHORITATIVE_READ): it must
848
+ // observe independently-arriving truth, and serving it the caller's own
849
+ // tentative write would trivially satisfy the predicate. The bit is checked
850
+ // on the reading computation itself, so a shared computed the predicate
851
+ // pulls recomputes as ITSELF (context = the memo, no bit) under the normal
852
+ // view. Fall through to normal value selection (staged `_pendingValue` is
853
+ // authoritative — optimism never lives there); the sticky mark makes the
854
+ // A17-silent "landing equals override" paths notify this node's subs so
855
+ // the reader re-runs when truth arrives.
856
+ if (!(t && t.T & CONFIG_AUTHORITATIVE_READ)) return unwrapOverride(e.o?.Oe);
857
+ e.T |= CONFIG_AUTHORITATIVE_OBSERVED;
750
858
  }
751
859
  // Entanglement gate: a reader recomputing under an optimistic lane that reads
752
860
  // a pending mid-transition write sees the committed value. Projection-store
@@ -755,7 +863,7 @@ function read(e) {
755
863
  // _pendingValue for correct fetching. The sub is recorded for replay at commit
756
864
  // so it re-runs with the new committed view. (Gate details live with the
757
865
  // engine — a non-null lane implies it is installed.)
758
- if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.Ft(e, u, t)) {
866
+ if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.vt(e, u, t)) {
759
867
  return e.be;
760
868
  }
761
869
  // In optimistic lane context, return _value for optimistic/lane-assigned signals
@@ -764,29 +872,45 @@ function read(e) {
764
872
  // (The lane-context clause lives with the engine.) Children-forbidden readers
765
873
  // (createTrackedEffect / onSettled callbacks) get committed visibility — see
766
874
  // readNodeFast (#3006).
767
- const l = !t || currentOptimisticLane !== null && GlobalQueue.gt(e, u, t) || e.Pe === NOT_PENDING || t.T & CONFIG_CHILDREN_FORBIDDEN || stale && e._e && activeTransition !== e._e ? e.be : e.Pe;
875
+ const l = !t || currentOptimisticLane !== null && GlobalQueue.bt(e, u, t) || e.Pe === NOT_PENDING || t.T & CONFIG_CHILDREN_FORBIDDEN || stale && e.Ae && activeTransition !== e.Ae ||
876
+ // A17 for HELD truth (#3164, see CONFIG_HELD_TRUTH): staged confirming
877
+ // truth — fold-staged onto an armed family, or entangle-stolen by an
878
+ // awaited until() — is masked from ordinary readers until its
879
+ // transaction's reveal; the retaining transaction's own speculative
880
+ // recomputes included (partial override coverage would otherwise
881
+ // compose override + staged truth into a state no timeline contains).
882
+ // Authoritative readers (until()'s predicate) and latest() see the
883
+ // staged truth — the tunnel that keeps the hold deadlock-free.
884
+ e.T & CONFIG_HELD_TRUTH && !latestReadActive && !(t.T & CONFIG_AUTHORITATIVE_READ) ? e.be : e.Pe;
768
885
  // Record that this isPending() probe observed the fresh pending value, so
769
886
  // the probe doesn't pair "pending" with the new value (#2831).
770
- if (pendingCheckActive) GlobalQueue.Ht(e, l);
771
- if (!t && u === e && typeof n.Se === "function" && e.T & CONFIG_AUTO_DISPOSE && !(u.S & STATUS_PENDING) && !e.u) {
772
- unobserved(e);
887
+ if (pendingCheckActive) GlobalQueue.kt(e, l);
888
+ if (!t && u === e && typeof n.oe === "function" && e.T & CONFIG_AUTO_DISPOSE && !(u.S & STATUS_PENDING) && !e.u) {
889
+ // Deferred, not inline (#3078): an inline unobserved() here made untracked
890
+ // reads destructive — dispose on this read, full revival recompute on the
891
+ // next — so consecutive reads could answer differently with no write in
892
+ // between (the revival samples the ambient transition/lane context).
893
+ // The sweep at flush finalization re-validates and reclaims; schedule()
894
+ // guarantees that flush happens even if nothing else is queued.
895
+ dormantNodes.add(e);
896
+ schedule();
773
897
  }
774
898
  return l;
775
899
  }
776
900
 
777
901
  function setSignal(e, t) {
778
- if (e._e && activeTransition !== e._e) globalQueue.initTransition(e._e);
902
+ if (e.Ae && activeTransition !== e.Ae) globalQueue.initTransition(e.Ae);
779
903
  // The optimistic write path lives with the engine: only optimisticSignal /
780
904
  // optimisticComputed callers and optimistic store nodes carry an
781
905
  // _overrideValue slot (flagged by CONFIG_OPTIMISTIC — a masked read of the
782
906
  // always-present config instead of a missing-property probe), and every
783
907
  // module that installs one installs the engine first.
784
- if (e.T & CONFIG_OPTIMISTIC && !projectionWriteActive) return GlobalQueue.vt(e, t);
908
+ if (e.T & CONFIG_OPTIMISTIC && !projectionWriteActive) return GlobalQueue.xt(e, t);
785
909
  const n = e.Pe === NOT_PENDING ? e.be : e.Pe;
786
910
  if (typeof t === "function") t = t(n);
787
911
  // Uninitialized check first: the first commit has no previous value, so the
788
912
  // user comparator must not run against `undefined` (matches recompute).
789
- const i = !!(e.S & STATUS_UNINITIALIZED) || !e.Ue || !e.Ue(n, t);
913
+ const i = !!(e.S & STATUS_UNINITIALIZED) || !e.ge || !e.ge(n, t);
790
914
  if (!i) return t;
791
915
  const u = e.Pe !== NOT_PENDING;
792
916
  if (!u) queuePendingNode(e);
@@ -796,16 +920,16 @@ function setSignal(e, t) {
796
920
  // only ever created, never removed, and creating one installs the hook and
797
921
  // sets CONFIG_HAS_COMPANIONS — one masked read replaces two optional-field
798
922
  // probes on every write).
799
- e.T & CONFIG_HAS_COMPANIONS && GlobalQueue.Oe !== null && GlobalQueue.Oe(e, t);
923
+ e.T & CONFIG_HAS_COMPANIONS && GlobalQueue.Re !== null && GlobalQueue.Re(e, t);
800
924
  // _time is a computed-only slot (§12e): writing it on a signal would fork
801
925
  // the lean shape. Every read site is computed-typed.
802
- if (e.Se !== undefined) e.Te = clock;
926
+ if (e.oe !== undefined) e.Te = clock;
803
927
  // Staged-rewrite fast path (§12d): a re-write to a node whose subscribers
804
928
  // were already walked — and where nothing has recomputed or linked since
805
929
  // (epoch) — re-stages the value and stops. The walk is idempotent (subs
806
930
  // marked, heap entries flag-guarded, effects queued once); lane and reask
807
931
  // contexts change what a walk MEANS, so they always walk.
808
- if (u && e._t === notifyEpoch && currentOptimisticLane === null && !reaskArmed) return t;
932
+ if (u && e.It === notifyEpoch && currentOptimisticLane === null && !reaskArmed) return t;
809
933
  insertSubs(e);
810
934
  schedule();
811
935
  return t;
@@ -824,7 +948,7 @@ function setSignal(e, t) {
824
948
  schedule();
825
949
  }
826
950
  e.ie = e.ie & -4 | REACTIVE_MANUAL_WRITE;
827
- e.kt = clock;
951
+ e.Ut = clock;
828
952
  }
829
953
 
830
954
  /**
@@ -880,39 +1004,22 @@ function staleValues(e, t = true) {
880
1004
  }
881
1005
 
882
1006
  /**
883
- * Invalidates one reactive source, forcing it to re-execute even if its inputs
884
- * haven't changed.
885
- *
886
- * Pass either a Solid-created accessor or a projected store created from
887
- * `createStore(fn, ...)` / `createProjection(...)`. `refresh()` is a
888
- * write-like invalidation operation: it does not read the target's value, and
889
- * refreshing a plain signal accessor is a no-op.
890
- *
891
- * Use it to invalidate cached async values (e.g. force a re-fetch) without
892
- * tearing the consumer down.
893
- *
894
- * @example
895
- * ```ts
896
- * const user = createMemo(async () => fetch(`/users/${id()}`).then(r => r.json()));
897
- *
898
- * // Re-fetch on demand
899
- * <button onClick={() => refresh(user)}>Reload</button>
900
- * ```
901
- */ function refresh(e) {
902
- const t = e?.[$REFRESH];
903
- if (!t) {
904
- return;
905
- }
906
- if (typeof t.Se === "function" && !(t.ie & REACTIVE_DISPOSED)) {
907
- if (t.ie & REACTIVE_MANUAL_WRITE) {
1007
+ * Core marking half of `refresh()` (the public wrapper lives in signals.ts
1008
+ * it validates the target, marks through here, then builds the quiescence
1009
+ * promise on the resolve()/until() effect machinery). Flags the node's next
1010
+ * recompute as a quiet re-ask and schedules it; no-ops for non-derived or
1011
+ * disposed targets and for same-tick manual writes.
1012
+ */ function markRefresh(e) {
1013
+ if (typeof e.oe === "function" && !(e.ie & REACTIVE_DISPOSED)) {
1014
+ if (e.ie & REACTIVE_MANUAL_WRITE) {
908
1015
  // A manual write in the CURRENT tick wins over the refresh (#2692).
909
1016
  // A mask stamped in an earlier tick only survives because a
910
1017
  // transaction (action) is holding the pending drain open; there the
911
1018
  // refresh is a later, explicit re-ask and lifts the mask — otherwise
912
1019
  // any setStore early in an action silently swallows every refresh()
913
1020
  // for the rest of the transaction (#3026).
914
- if (t.kt === clock) return;
915
- t.ie &= ~REACTIVE_MANUAL_WRITE;
1021
+ if (e.Ut === clock) return;
1022
+ e.ie &= ~REACTIVE_MANUAL_WRITE;
916
1023
  // No REASK below: the batch carries a manual value change, so the
917
1024
  // recompute is not a quiet re-ask of an unchanged question.
918
1025
  }
@@ -923,14 +1030,14 @@ function staleValues(e, t = true) {
923
1030
  // REACTIVE_IN_HEAP counts as dirt: insertSubs schedules subscribers by
924
1031
  // heap insertion alone (no DIRTY/CHECK flag), so a same-batch value
925
1032
  // change followed by refresh() must not be laundered into a quiet re-ask.
926
- else if (!(t.ie & (REACTIVE_DIRTY | REACTIVE_CHECK | REACTIVE_IN_HEAP))) {
927
- t.ie |= REACTIVE_REASK;
1033
+ else if (!(e.ie & (REACTIVE_DIRTY | REACTIVE_CHECK | REACTIVE_IN_HEAP))) {
1034
+ e.ie |= REACTIVE_REASK;
928
1035
  armReaskClear();
929
1036
  }
930
- t.ie = t.ie & ~REACTIVE_CHECK | REACTIVE_DIRTY;
931
- insertIntoHeap(t, queueFor(t));
1037
+ e.ie = e.ie & ~REACTIVE_CHECK | REACTIVE_DIRTY;
1038
+ insertIntoHeap(e, queueFor(e));
932
1039
  schedule();
933
1040
  }
934
1041
  }
935
1042
 
936
- export { READ_SLOW, clearSnapshots, computed, context, createEffectNode, currentOptimisticLane, ext, isEqual, latestReadActive, markSnapshotScope, optimisticComputed, optimisticSignal, pendingCheckActive, prepareComputed, read, readNodeFast, recompute, refresh, releaseSnapshotScope, runWithOwner, setContextInternal, setLatestReadActive, setMemo, setPendingCheckActive, setSignal, setSnapshotCapture, signal, snapshotCaptureActive, snapshotSources, stale, staleValues, suppressComputedRecompute, tracking, untrack };
1043
+ 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 };